Adds a way to simulate the programs with spike, to compare PCs and debug

This commit is contained in:
2025-11-15 00:57:30 +01:00
parent ca03b29774
commit 0c377a1380
8 changed files with 77 additions and 76 deletions

View File

@@ -70,6 +70,7 @@ $(MEM_DIR):
@mkdir -p $@/programs
@mkdir -p $@/programs_rust
.PRECIOUS: $(MEM_DIR)/programs_rust/%.elf
$(MEM_DIR)/programs_rust/%.elf: bench/programs_rust/% force $(MEM_DIR)/crt.o |$(MEM_DIR)
cd bench/programs_rust && cargo build --release --bin=$(basename $(notdir $@))
cp -f bench/programs_rust/target/riscv64i/release/$(basename $(notdir $@)) $@
@@ -100,6 +101,7 @@ PATH_SRC := src/main/scala/$(TOP_REP)
TOP_TEST := $(addsuffix Spec, $(TOP))
CYCLES=500
INSTRUCTIONS=1000
# Pour filtrer les tests dans une simulation
ifdef PROG
FILTRE_TEST:= -- -z "$(PROG)"
@@ -120,11 +122,16 @@ testall: mill compile ##! Lance la simulation automatique pour tous les tests en
$(PROG): $(MEM_DIR)/$(PROG).mem
simulation: mill $(PROG) ##! Lance gtkwave sur le test fourni dans PROG
simulation: mill $(PROG) ##! Lance gtkwave sur le test fourni dans PROG et produit le log du pc
@$(call check_vars,PROG)
@PROOT=$(PWD) PROG=$(PROG) CYCLES=$(CYCLES) ./mill TPchisel.test.testOnly $(TOP_REP).$(TOP_TEST) -- -DemitVcd=1 -z "gtkwave"
@cp -f ./build/chiselsim/ZzTopSpec/Simulation-pour-gtkwave/workdir-verilator/core_pc.log .
@gtkwave -a common/config.gtkw ./build/chiselsim/ZzTopSpec/Simulation-pour-gtkwave/workdir-verilator/trace.vcd
spike-simulation: mill $(PROG) ##! Simule INSTRUCTIONS instructions de PROG avec spike et produit un log du PC dans spike_pc.log
spike --log spike.log --instructions=$$(($(INSTRUCTIONS) + 5)) -m0x10000:0x20000,0x80000000:0x00020000 -l $(MEM_DIR)/$(PROG).elf
cat spike.log | sed "/>>>>/d" | awk '{print $$3}' | tail -n $(INSTRUCTIONS) > spike_pc.log
###############################################################################

View File

@@ -4,13 +4,8 @@
_start:
# réservation d'une (petite) zone de mémoire pour la pile
la sp, stack + STACK_SIZE
la sp, _stack_start
# appel de main, sans espoir de retour !
jal main
1: j 1b
.bss
.align 4
.global stack
stack:
.skip STACK_SIZE
.data
.bss

View File

@@ -1,50 +1,19 @@
OUTPUT_ARCH( "riscv" )
ENTRY (_start)
MEMORY
{
insnmem (rx) : ORIGIN = 0x0000, LENGTH = 8K
datamem (wai!x) : ORIGIN = 0x2000, LENGTH = 8K
}
PHDRS
{
text PT_LOAD;
data PT_LOAD;
bss PT_LOAD;
}
SECTIONS
{
PROVIDE(_start = ORIGIN(insnmem));
.text : {
PROVIDE(_text_start = .);
*(.text._start) *(.text .text.*)
PROVIDE(_text_end = .);
} >insnmem AT>insnmem :text
. = 0x10000;
.text : { *(.text) }
. = ALIGN(8);
.data : { *(.data) }
.bss : { *(.bss) }
. = ALIGN(8);
PROVIDE(_memory_start = . );
PROVIDE(_memory_end = 0x20000);
PROVIDE(_stack_size = 1024); /* 1 KiB */
PROVIDE(_stack_start = _memory_end);
PROVIDE(_stack_end = _stack_start - _stack_size);
. = ORIGIN(datamem);
.rodata ALIGN(4) : {
PROVIDE(_rodata_start = .);
*(.rodata .rodata.*)
PROVIDE(_rodata_end = .);
} >datamem AT>datamem :data
.data ALIGN(4) : {
PROVIDE(_data_start = .);
*(.sdata .sdata.*) *(.data .data.*)
PROVIDE(_data_end = .);
} >datamem AT>datamem :data
.bss ALIGN(4) : {
PROVIDE(_bss_start = .);
*(.sbss .sbss.*) *(.bss .bss.*)
PROVIDE(_bss_end = .);
} >datamem AT>datamem :bss
PROVIDE(_memory_start = ORIGIN(datamem));
PROVIDE(_memory_end = ORIGIN(datamem) + LENGTH(datamem));
PROVIDE(_stack_size = 1024); /* 1 KiB */
PROVIDE(_stack_start = ORIGIN(datamem) + LENGTH(datamem));
PROVIDE(_stack_end = _stack_start - _stack_size);
}

View File

@@ -8,6 +8,7 @@ linker = "riscv64-unknown-elf-ld"
rustflags = [
# "-C", "link-arg=-nostartfiles",
"-C", "link-arg=-T../link.ld",
"-C", "link-arg=../mem/crt.o",
]
[unstable]

View File

@@ -46,7 +46,7 @@ impl VGA
{
let c = if (c as u8 > b'~') || ((c as u8) < b' ')
{
b'?' - b' '
b'/' - b' '
}
else
{
@@ -79,21 +79,9 @@ impl VGA
/// The text must have a length that can fit within a `u16`
pub unsafe fn draw_string(x: u16, y: u16, str: &str, color: Color)
{
//str.chars().enumerate().for_each(|(i, c)| unsafe {
//Self::draw_char(x + i as u16 * (FONT_WIDTH as u16), y, c, color)
//Self::draw_char(x + (i as u16) << 1, y, c, color)
//Self::draw_char(x, y, c, color)
//});
for i in 0..2
{
Self::draw_char(
x + (2 - i) as u16 * (FONT_WIDTH as u16),
y,
str.as_bytes()[i] as char,
color,
);
}
str.bytes().enumerate().for_each(|(i, c)| unsafe {
Self::draw_char(x + i as u16 * (FONT_WIDTH as u16), y, c as char, color)
});
}
unsafe fn font_plate_index(x: u16, y: u16) -> bool

View File

@@ -6,15 +6,14 @@ use core::arch::asm;
use fpga_lib::{
panic_handler,
register::X31,
vga::{BLUE, GREEN, RED, VGA, WHITE},
vga::{BLUE, FONT_WIDTH, GREEN, RED, VGA, WHITE},
};
panic_handler! {}
#[unsafe(no_mangle)]
pub extern "C" fn _start() -> !
pub extern "C" fn main() -> !
{
unsafe { asm!("la sp, _stack_start") }
// X31::write_const::<0xdead1ffffffff>();
// let test = X31::read() + 10;
//unsafe {
@@ -27,10 +26,45 @@ pub extern "C" fn _start() -> !
// {
// VGA::write_pixel_unsafe(i, i, WHITE);
// }
//unsafe { VGA::draw_char(9, 3, 'S', RED) };
unsafe { VGA::draw_string(3, 3, "{Skibidi toilet !!}", GREEN) };
//let c = core::hint::black_box('S');
let c = core::hint::black_box('S');
//unsafe { VGA::draw_char(10, 10, c, RED) };
//unsafe { VGA::draw_string(3, 3, "{Skibidi toilet !!}", GREEN) };
//}
// for i in 0..2
// {
// unsafe { VGA::draw_char(0 + i as u16 * FONT_WIDTH as u16, 0, c, RED) };
// }
// unsafe { VGA::draw_char(0, 0, c, RED) };
// unsafe { VGA::draw_char(1, 0, c, RED) };
unsafe { VGA::draw_char(1, 0, c, RED) };
unsafe { VGA::draw_char(1, 0, c, GREEN) };
// if (c as u8 > b'~') || ((c as u8) < b' ')
// {
// X31::write_const::<0x01>();
// }
// else
// {
// X31::write_const::<0xFFFFFFFFFFFFFFFF>();
// };
//
// if (c as u8 > b'~') || ((c as u8) < b' ')
// {
// X31::write_const::<0x01>();
// }
// else
// {
// X31::write_const::<0xFFFFFFFFFFFFFFFF>();
// };
// for i in 0..100
// {
// unsafe { VGA::write_pixel_unsafe(i, i, WHITE) };
// }
//
// let mut a = core::hint::black_box(true);
// let mut x = core::hint::black_box(121);
// let mut y = core::hint::black_box(221);

View File

@@ -41,8 +41,8 @@ class BusInterconnect extends Module {
// BASE => ( X"0000_1000", X"3000_0000", X"3000_0008", X"0C00_0000", X"0200_0000", X"8000_0000"),
// HIGH => ( X"0000_8FFF", X"3000_0004", X"3000_0008", X"1000_0000", X"0200_C000", X"8FFF_FFFF")
val DMEM_BASE = 0x00000000L.U // Une mémoire unifiée code + données
val DMEM_SIZE = 0x00010000L.U
val DMEM_BASE = 0x00010000L.U // Une mémoire unifiée code + données
val DMEM_SIZE = 0x00020000L.U
val LDIP_BASE = 0x30000000L.U
val LDIP_SIZE = 0x00000004L.U

View File

@@ -10,7 +10,7 @@ class Rv64i(sim: Boolean = true) extends Module {
val valid_x31 = if (sim) Some(Output(Bool())) else None
})
val reg_pc = RegInit(0.U(64.W));
val reg_pc = RegInit("x10000".U(64.W));
val reg_file = Module(new RegFile(sim));
reg_file.io.rd_data := 0.U;
@@ -33,10 +33,17 @@ class Rv64i(sim: Boolean = true) extends Module {
alu.io.word_mode := control_unit.io.alu_word_mode
// PC delayed to execute stage for auipc op
val execute_pc = Delay.Delay(reg_pc, 1, 0.U);
val execute_pc = Delay.Delay(reg_pc, 1, "x10000".U(64.W));
// True if the instruction in the execute stage is a jump
val is_jump = Delay.Delay(control_unit.io.is_jump, 1, false.B);
if (sim) {
val log = SimLog.file("core_pc.log");
when(!is_jump) {
log.printf(cf"0x${execute_pc}%x\n")
}
}
// Pipelining registers for mem stage
val reg_rd_index = RegInit(0.U);
val reg_execute_out = RegInit(0.U);