Improve Spike - Ariane alignment

- Don't increment instret on exception
- Align cycle counter with instret counter (-> IPC 1 as in Spike)
- Add mock uart functionality
- Make the preloading elf a plus-arg
This commit is contained in:
Florian Zaruba 2018-11-04 16:20:07 +01:00
parent 0d6e4fe658
commit 9db50883da
No known key found for this signature in database
GPG key ID: E742FFE8EC38A792
16 changed files with 210 additions and 76 deletions

View file

@ -128,6 +128,29 @@ list_incdir := $(foreach dir, ${incdir}, +incdir+$(dir))
riscv-torture-dir := tmp/riscv-torture
riscv-torture-bin := java -Xmx1G -Xss8M -XX:MaxPermSize=128M -jar sbt-launch.jar
ifdef batch-mode
questa-flags += -c
questa-cmd := -do "coverage save -onexit tmp/$@.ucdb; run -a; quit -code [coverage attribute -name TESTSTATUS -concise]"
else
questa-cmd := -do " log -r /*; run -all;"
endif
# we want to preload the memories
ifdef preload
questa-cmd += +PRELOAD=$(preload)
elf-bin = none
# tandem verify with spike, this requires pre-loading
ifdef tandem
compile_flag += +define+TANDEM
questa-cmd += -gblso tb/riscv-isa-sim/install/lib/libriscv.so
endif
endif
# remote bitbang is enabled
ifdef rbb
questa-cmd += +jtag_rbb_enable=1
else
questa-cmd += +jtag_rbb_enable=0
endif
# Build the TB and module using QuestaSim
build: $(library) $(library)/.build-srcs $(library)/.build-tb $(dpi-library)/ariane_dpi.so
# Optimize top level
@ -163,18 +186,9 @@ $(dpi-library)/ariane_dpi.so: $(dpi)
sim: build
vsim${questa_version} +permissive -64 -lib ${library} +max-cycles=$(max_cycles) +UVM_TESTNAME=${test_case} \
+BASEDIR=$(riscv-test-dir) $(uvm-flags) "+UVM_VERBOSITY=LOW" -coverage -classdebug +jtag_rbb_enable=0 \
$(QUESTASIM_FLAGS) \
-gblso $(RISCV)/lib/libfesvr.so -gblso tb/riscv-isa-sim/install/lib/libriscv.so -sv_lib $(dpi-library)/ariane_dpi -do "log -r /*;" \
${top_level}_optimized +permissive-off ++$(riscv-test-dir)$(riscv-test) ++$(target-options)
simc: build
vsim${questa_version} +permissive -64 -c -lib ${library} +max-cycles=$(max_cycles) +UVM_TESTNAME=${test_case} \
+BASEDIR=$(riscv-test-dir) $(uvm-flags) "+UVM_VERBOSITY=LOW" -coverage -classdebug +jtag_rbb_enable=0 \
$(QUESTASIM_FLAGS) \
-gblso $(RISCV)/lib/libfesvr.so -gblso tb/riscv-isa-sim/install/lib/libriscv.so -sv_lib $(dpi-library)/ariane_dpi -do "log -r /*;" \
${top_level}_optimized +permissive-off ++$(riscv-test-dir)$(riscv-test) ++$(target-options)
vsim${questa_version} +permissive $(questa-flags) $(questa-cmd) -lib $(library) +MAX_CYCLES=$(max_cycles) +UVM_TESTNAME=$(test_case) \
+BASEDIR=$(riscv-test-dir) $(uvm-flags) -gblso $(RISCV)/lib/libfesvr.so -sv_lib $(dpi-library)/ariane_dpi \
${top_level}_optimized +permissive-off ++$(elf-bin) ++$(target-options) | tee sim.log
$(riscv-asm-tests): build
vsim${questa_version} +permissive -64 -c -lib ${library} +max-cycles=$(max_cycles) +UVM_TESTNAME=${test_case} \

View file

@ -76,7 +76,7 @@ $ work-ver/Variane_testharness $RISCV/riscv64-unknown-elf/bin/pk hello.elf
If you want to use QuestaSim to run it you can use the following command:
```
$ make simc riscv-test-dir=$RISCV/riscv64-unknown-elf/bin riscv-test=pk target-options=hello.elf
$ make sim riscv-test-dir=$RISCV/riscv64-unknown-elf/bin riscv-test=pk target-options=hello.elf batch-mode=1
```
> Be patient! RTL simulation is way slower than Spike. If you think that you ran into problems you can inspect the trace files.
@ -139,10 +139,10 @@ The core has been developed with a full licensed version of QuestaSim. If you ha
To specify the test to run use (e.g.: you want to run `rv64ui-p-sraw` inside the `tmp/risc-tests/build/isa` folder:
```
$ make sim riscv-test=tmp/risc-tests/build/isa/rv64ui-p-sraw
$ make sim riscv-test=tmp/risc-tests/build/isa/rv64ui-p-sraw make
```
If you call `simc` instead of `sim` it will run without the GUI. QuestaSim uses `riscv-fesvr` for communication as well.
If you call `sim` with `batch-mode=1` it will run without the GUI. QuestaSim uses `riscv-fesvr` for communication as well.
### CI Testsuites and Randomized Constrained Testing with Torture
@ -186,6 +186,17 @@ $ make
$ [sudo] make install
```
### Tandem Verification with Spike
```
$ make sim preload=/home/zarubaf/Downloads/riscv-tests/build/benchmarks/dhrystone.riscv tandem=1
```
There are a couple of limitations:
- Memories should be initialized to zero.
- UART needs to be replaced by a mock uart which exhibits always ready behavior.
- There is no end of test signaling at the moment. You are supposed to kill the simulation when sufficiently long run.
# Contributing
Check out the [contribution guide](CONTRIBUTING.md)

View file

@ -60,7 +60,9 @@ package ariane_pkg;
// enables a commit log which matches spikes commit log format for easier trace comparison
localparam bit ENABLE_SPIKE_COMMIT_LOG = 1'b0;
// enable performance cycle counter, if set to zero mcycle will be incremented
// with instret (non RISC-V conformal)
localparam bit ENABLE_CYCLE_COUNT = 1'b0;
// ------------- Dangerouse -------------
// if set to zero a flush will not invalidate the cache-lines, in a single core environment
// where coherence is not necessary this can improve performance. This needs to be switched on

View file

@ -445,6 +445,7 @@ package riscv;
byte rd;
longint unsigned data;
int unsigned instr;
byte was_exception;
} commit_log_t;
endpackage

View file

@ -233,11 +233,14 @@ module csr_regfile #(
cycle_d = cycle_q;
instret_d = instret_q;
if (!debug_mode_q) begin
// just increment the cycle count
cycle_d = cycle_q + 1'b1;
// increase instruction retired counter
for (int i = 0; i < NR_COMMIT_PORTS; i++) if (commit_ack_i[i]) instret++;
for (int i = 0; i < NR_COMMIT_PORTS; i++) begin
if (commit_ack_i[i] && !ex_i.valid) instret++;
end
instret_d = instret;
// increment the cycle count
if (ENABLE_CYCLE_COUNT) cycle_d = cycle_q + 1'b1;
else cycle_d = instret;
end
eret_o = 1'b0;

@ -1 +1 @@
Subproject commit 3e925e169bd02ebf26e3d4ab65cd1832319cf580
Subproject commit a3ba269c0fc6cfcee6f81e5d9af018a08e479d2b

View file

@ -13,11 +13,11 @@
// Date: 15.08.2018
// Description: SRAM wrapper for FPGA (requires the fpga-support submodule)
//
// Note: the wrapped module contains two different implementations for
// ALTERA and XILINX tools, since these follow different coding styles for
// inferrable RAMS with byte enable. define `FPGA_TARGET_XILINX or
// Note: the wrapped module contains two different implementations for
// ALTERA and XILINX tools, since these follow different coding styles for
// inferrable RAMS with byte enable. define `FPGA_TARGET_XILINX or
// `FPGA_TARGET_ALTERA in your build environment (default is ALTERA)
module sram #(
parameter DATA_WIDTH = 64,
parameter NUM_WORDS = 1024,
@ -52,23 +52,24 @@ end
genvar k;
generate
for (k = 0; k<(DATA_WIDTH+63)/64; k++) begin
for (k = 0; k<(DATA_WIDTH+63)/64; k++) begin
// unused byte-enable segments (8bits) are culled by the tool
SyncSpRamBeNx64 #(
.ADDR_WIDTH($clog2(NUM_WORDS)),
.DATA_DEPTH(NUM_WORDS),
.OUT_REGS (0)
.DATA_DEPTH(NUM_WORDS),
.OUT_REGS (0),
.SIM_INIT (1)
) i_ram (
.Clk_CI ( clk_i ),
.Rst_RBI ( rst_ni ),
.CSel_SI ( req_i ),
.WrEn_SI ( we_i ),
.BEn_SI ( be_aligned[k*8 +: 8] ),
.WrData_DI ( wdata_aligned[k*64 +: 64] ),
.Addr_DI ( addr_i ),
.WrData_DI ( wdata_aligned[k*64 +: 64] ),
.Addr_DI ( addr_i ),
.RdData_DO ( rdata_aligned[k*64 +: 64] )
);
end
);
end
endgenerate
endmodule : sram

View file

@ -54,13 +54,22 @@ module ariane_tb;
.exit_o
);
// `ifdef TANDEM
// initial $display("Tandem defined",);
spike i_spike (
.clk_i,
.rst_ni,
.clint_tick_i ( dut.i_clint.rtc_i ),
.commit_instr_i ( dut.i_ariane.commit_instr_id_commit ),
.commit_ack_i ( dut.i_ariane.commit_ack )
.commit_ack_i ( dut.i_ariane.commit_ack ),
.exception_i ( dut.i_ariane.ex_commit ),
.waddr_i ( dut.i_ariane.waddr_commit_id ),
.wdata_i ( dut.i_ariane.wdata_commit_id ),
.priv_lvl_i ( dut.i_ariane.priv_lvl )
);
// `else
// initial $display("Tandem not defined",);
// `endif
// Clock process
initial begin
@ -110,12 +119,12 @@ module ariane_tb;
byte buffer[];
void'(uvcl.get_arg_value("+PRELOAD=", binary));
binary = "/home/zarubaf/riscv/target/share/riscv-tests/benchmarks/dhrystone.riscv";
if (binary != "") begin
`uvm_info( "Core Test", $sformatf("Preloading ELF: %s", binary), UVM_LOW)
void'(read_elf(binary));
// wait with preloading, otherwise randomization will overwrite the existing value
wait(rst_ni);
// while there are more sections to process
while (get_section(address, len)) begin

View file

@ -10,7 +10,7 @@
//
// Author: Florian Zaruba, ETH Zurich
// Date: 28/09/2018
// Description: Mock replacement for UART in testbench
// Description: Mock replacement for UART in testbench (not synthesiesable!)
module mock_uart (
input logic clk_i,
@ -24,6 +24,32 @@ module mock_uart (
output logic pready_o,
output logic pslverr_o
);
localparam RBR 0
localparam THR 0
localparam IER 1
localparam IIR 2
localparam FCR 2
localparam LCR 3
localparam MCR 4
localparam LSR 5
localparam MSR 6
localparam SCR 7
localparam DLL 0
localparam DLM 1
localparam THRE 5 // transmit holding register empty
localparam TEMT 6 // transmit holding register empty
byte lcr = 0;
byte dlm = 0;
byte dll = 0;
byte mcr = 0;
byte lsr = 0;
byte ier = 0;
byte msr = 0;
byte scr = 0;
logic fifo_enabled = 1'b0;
// string buffer
byte buffer [$];
@ -54,7 +80,48 @@ module mock_uart (
always_ff @(posedge clk_i or negedge rst_ni) begin
if (rst_ni) begin
if (psel_i & penable_i & pwrite_i & paddr_i[3:0] == 'h4) append(byte'(pwdata_i[7:0]));
if (psel_i & penable_i & pwrite_i & (paddr_i >> 2)) begin
case ((paddr_i >> 'h2) & 'h7)
THR: begin
if (lcr & 'h80) dll = byte'(pwdata_i[7:0]);
else append(byte'(pwdata_i[7:0]));
end
IER: begin
if (lcr & 'h80) dlm = byte'(pwdata_i[7:0]);
else ier = byte'(pwdata_i[7:0] & 'hF)
end
FCR: begin
if (pwdata_i[0]) fifo_enabled = 1'b1;
else fifo_enabled = 1'b0;
end
LCR: lcr = byte'(pwdata_i[7:0]);
MCR: mcr = byte'(pwdata_i[7:0] & 'h1F);
LSR: lsr = byte'(pwdata_i[7:0]);
MSR: msr = byte'(pwdata_i[7:0]);
SCR: scr = byte'(pwdata_i[7:0]);
default:;
endcase
end else if (psel_i & penable_i & ~pwrite_i) begin
case ((paddr_i >> 'h2) & 'h7)
THR: begin
if (lcr & 'h80) prdata_o = {24'b0, dll};
end
IER: begin
if (lcr & 'h80) prdata_o = {24'b0, dlm};
else ier = prdata_o = {24'b0, ier};
end
IIR: begin
if (fifo_enabled) prdata_o = {24'b0, 8'hc0};
else prdata_o = {24'b0, 8'b0};
end
LCR: prdata_o = {24'b0, lcr};
MCR: prdata_o = {24'b0, mcr};
LSR: prdata_o = {24'b0, (lsr | (1 << THRE) | (1 << TEMT))};
MSR: prdata_o = {24'b0, msr};
SCR: prdata_o = {24'b0, scr};
default:;
endcase
end
end
end
endmodule

View file

@ -12,6 +12,14 @@
// Date: 3/11/2018
// Description: Wrapped Spike Model for Tandem Verification
import uvm_pkg::*;
`include "uvm_macros.svh"
import "DPI-C" function int spike_create(string filename, longint unsigned dram_base, int unsigned size);
import "DPI-C" function void spike_tick(output riscv::commit_log_t commit_log);
import "DPI-C" function void clint_tick();
module spike #(
parameter longint unsigned DramBase = 'h8000_0000,
parameter int unsigned Size = 64 * 1024 * 1024 // 64 Mega Byte
@ -20,16 +28,20 @@ module spike #(
input logic rst_ni,
input logic clint_tick_i,
input ariane_pkg::scoreboard_entry_t [ariane_pkg::NR_COMMIT_PORTS-1:0] commit_instr_i,
input logic [ariane_pkg::NR_COMMIT_PORTS-1:0] commit_ack_i
input logic [ariane_pkg::NR_COMMIT_PORTS-1:0] commit_ack_i,
input ariane_pkg::exception_t exception_i,
input logic [ariane_pkg::NR_COMMIT_PORTS-1:0][4:0] waddr_i,
input logic [ariane_pkg::NR_COMMIT_PORTS-1:0][63:0] wdata_i,
input riscv::priv_lvl_t priv_lvl_i
);
// Create a spike simulation object with base at dram_base and size (in bytes).
// Bytes must be page aligned.
import "DPI-C" function int spike_create(string filename, longint unsigned dram_base, int unsigned size);
import "DPI-C" function void spike_tick(output riscv::commit_log_t commit_log);
import "DPI-C" function void clint_tick();
static uvm_cmdline_processor uvcl = uvm_cmdline_processor::get_inst();
string binary = "";
initial begin
void'(spike_create("/home/zarubaf/riscv/target/share/riscv-tests/benchmarks/dhrystone.riscv", DramBase, Size));
void'(uvcl.get_arg_value("+PRELOAD=", binary));
assert(binary != "") else $error("We need a preloaded binary for tandem verification");
void'(spike_create(binary, DramBase, Size));
end
riscv::commit_log_t commit_log;
@ -40,8 +52,39 @@ module spike #(
if (commit_instr_i[i].valid && commit_ack_i[i]) begin
spike_tick(commit_log);
instr = (commit_log.instr[1:0] != 2'b11) ? {16'b0, commit_log.instr[15:0]} : commit_log.instr;
$display("\x1B[32m%h %h\x1B[0m", commit_log.pc, instr);
$display("\x1B[37m%h %h\x1B[0m", commit_instr_i[i].pc, commit_instr_i[i].ex.tval[31:0]);
// $display("\x1B[32m%h %h\x1B[0m", commit_log.pc, instr);
// $display("%p", commit_log);
// $display("\x1B[37m%h %h\x1B[0m", commit_instr_i[i].pc, commit_instr_i[i].ex.tval[31:0]);
assert (commit_log.pc === commit_instr_i[i].pc) else begin
$warning("\x1B[33m[Tandem] PCs Mismatch\x1B[0m");
end
assert (commit_log.was_exception === exception_i.valid) else begin
$warning("\x1B[33m[Tandem] Exception not detected\x1B[0m");
$display("Spike: %p", commit_log);
$display("Ariane: %p", commit_instr_i[i]);
end
assert (commit_log.priv === priv_lvl_i) else begin
$warning("\x1B[33m[Tandem] Privilege level mismatches\x1B[0m");
$display("\x1B[37m @ PC %h\x1B[0m", commit_log.pc);
end
if (!exception_i.valid) begin
assert (instr === commit_instr_i[i].ex.tval) else begin
$warning("\x1B[33m[Tandem] Decoded instructions mismatch\x1B[0m");
$display("\x1B[37m%h === %h @ PC %h\x1B[0m", commit_instr_i[i].ex.tval, instr, commit_log.pc);
end
// TODO(zarubaf): Adapt for floating point instructions
if (commit_instr_i[i].rd != 0) begin
// check the return value
// $display("\x1B[37m%h === %h\x1B[0m", commit_instr_i[i].rd, commit_log.rd);
assert (waddr_i[i] === commit_log.rd) else begin
$warning("\x1B[33m[Tandem] Destination register mismatches\x1B[0m");
end
assert (wdata_i[i] === commit_log.data) else begin
$warning("\x1B[33m[Tandem] Write back data mismatches\x1B[0m");
$display("\x1B[37m%h === %h @ PC %h\x1B[0m", wdata_i[i], commit_log.data, commit_log.pc);
end
end
end
end
end
end

View file

@ -57,27 +57,14 @@ commit_log_t sim_spike_t::tick(size_t n)
int xlen = procs[0]->get_state()->last_inst_xlen;
int flen = procs[0]->get_state()->last_inst_flen;
// fprintf(stderr, "%1d ", priv);
// fprintf(stderr, "%lx ", pc);
// fprintf(stderr, "%lx ", xlen);
// fprintf(stderr, "%1d ", fp);
// fprintf(stderr, "%c%d ", fp ? 'f' : 'x', rd);
if (procs[0]->get_state()->rd) {
bool fp = procs[0]->get_state()->rd & 1;
int rd = procs[0]->get_state()->rd >> 1;
int size = fp ? flen : xlen;
// fprintf(stderr, "%c%2d ", fp ? 'f' : 'x', rd);
// fprintf(stderr, "0x%016" PRIx64 "\n", reg.data.v[0]);
// fprintf(stderr, "\n");
} else {
// fprintf(stderr, "\n");
}
commit_log.priv = priv;
commit_log.pc = pc;
commit_log.is_fp = procs[0]->get_state()->rd & 1;
commit_log.rd = procs[0]->get_state()->rd >> 2;
commit_log.is_fp = reg.addr & 1;
commit_log.rd = reg.addr >> 1;
commit_log.data = reg.data.v[0];
commit_log.instr = procs[0]->get_state()->last_insn;
commit_log.was_exception = procs[0]->get_state()->was_exception;
return commit_log;
}

View file

@ -25,6 +25,7 @@ typedef struct
char rd;
uint64_t data;
uint32_t instr;
char was_exception;
} commit_log_t;
// this class encapsulates the processors and memory in a RISC-V machine.

View file

@ -29,8 +29,6 @@ commit_log_t commit_log_val;
#define SHT_GROUP 0x11
void write_spike_mem (reg_t address, size_t len, uint8_t* buf) {
fprintf(stderr, "Storing: %llx\n", address);
memcpy(mem[0].second->contents() + (address & ~(1 << 31)), buf,len);
}
@ -126,6 +124,7 @@ extern "C" void spike_tick(commit_log_t* commit_log)
commit_log->rd = commit_log_val.rd;
commit_log->data = commit_log_val.data;
commit_log->instr = commit_log_val.instr;
commit_log->was_exception = commit_log_val.was_exception;
}
extern "C" void clint_tick()

View file

@ -43,24 +43,13 @@ static void commit_log_print_insn(state_t* state, reg_t pc, insn_t insn)
int xlen = state->last_inst_xlen;
int flen = state->last_inst_flen;
state->rd = reg.addr;
state->last_insn = insn.bits();
// fprintf(stderr, "%1d ", priv);
// commit_log_print_value(xlen, 0, pc);
// fprintf(stderr, " (");
// commit_log_print_value(insn.length() * 8, 0, insn.bits());
if (reg.addr) {
bool fp = reg.addr & 1;
int rd = reg.addr >> 1;
int size = fp ? flen : xlen;
// fprintf(stderr, ") %c%2d ", fp ? 'f' : 'x', rd);
// commit_log_print_value(size, reg.data.v[1], reg.data.v[0]);
// fprintf(stderr, "\n");
} else {
// fprintf(stderr, ")\n");
}
reg.addr = 0;
#endif
}
@ -93,6 +82,9 @@ bool processor_t::slow_path()
// fetch/decode/execute loop
void processor_t::step(size_t n)
{
#ifdef RISCV_ENABLE_COMMITLOG
state.was_exception = false;
#endif
if (state.dcsr.cause == DCSR_CAUSE_NONE) {
if (halt_request) {
enter_debug_mode(DCSR_CAUSE_DEBUGINT);
@ -210,6 +202,9 @@ void processor_t::step(size_t n)
}
catch(trap_t& t)
{
#ifdef RISCV_ENABLE_COMMITLOG
state.was_exception = true;
#endif
take_trap(t, pc);
n = instret;

View file

@ -143,8 +143,8 @@ struct state_t
reg_t last_inst_priv;
int last_inst_xlen;
int last_inst_flen;
reg_t rd;
uint32_t last_insn;
bool was_exception;
#endif
};

View file

@ -34,6 +34,7 @@ bool uart_t::load(reg_t addr, size_t len, uint8_t* bytes)
if (lcr & 0x80) {
bytes[0] = dll;
} else {
// TODO(zarubaf)
// printf("%c", bytes[0]);
}
break;