2021-01-24 22:10:00 +00:00
|
|
|
`include "wally-config.vh"
|
2021-01-21 21:17:34 +00:00
|
|
|
|
2021-01-24 22:10:00 +00:00
|
|
|
module testbench_busybear();
|
2021-01-21 21:17:34 +00:00
|
|
|
|
2021-01-21 22:55:05 +00:00
|
|
|
logic clk, reset;
|
|
|
|
logic [31:0] GPIOPinsIn;
|
|
|
|
logic [31:0] GPIOPinsOut, GPIOPinsEn;
|
2021-01-21 21:17:34 +00:00
|
|
|
|
|
|
|
// instantiate device to be tested
|
2021-01-30 17:38:18 +00:00
|
|
|
logic [`XLEN-1:0] PCF;
|
2021-01-21 22:55:05 +00:00
|
|
|
logic [31:0] InstrF;
|
2021-01-23 22:52:05 +00:00
|
|
|
|
2021-01-29 17:46:50 +00:00
|
|
|
logic [`AHBW-1:0] HRDATA;
|
|
|
|
logic [31:0] HADDR;
|
|
|
|
logic [`AHBW-1:0] HWDATA;
|
|
|
|
logic HWRITE;
|
|
|
|
logic [2:0] HSIZE;
|
|
|
|
logic [2:0] HBURST;
|
|
|
|
logic [3:0] HPROT;
|
|
|
|
logic [1:0] HTRANS;
|
|
|
|
logic HMASTLOCK;
|
2021-01-30 17:38:18 +00:00
|
|
|
logic HCLK, HRESETn;
|
2021-02-23 18:59:06 +00:00
|
|
|
logic [`AHBW-1:0] HRDATAEXT;
|
|
|
|
logic HREADYEXT, HRESPEXT;
|
|
|
|
logic UARTSout;
|
2021-01-29 17:46:50 +00:00
|
|
|
|
|
|
|
assign GPIOPinsIn = 0;
|
|
|
|
assign UARTSin = 1;
|
2021-01-21 22:55:05 +00:00
|
|
|
|
|
|
|
// instantiate processor and memories
|
2021-02-23 18:59:06 +00:00
|
|
|
wallypipelinedsocbusybear dut(.*);
|
2021-01-21 21:17:34 +00:00
|
|
|
|
|
|
|
// initialize test
|
|
|
|
initial
|
|
|
|
begin
|
2021-01-21 22:55:05 +00:00
|
|
|
reset <= 1; # 22; reset <= 0;
|
2021-01-21 21:17:34 +00:00
|
|
|
end
|
2021-01-22 19:11:17 +00:00
|
|
|
|
change how testbench reads data
we're not sure if this is a good idea, but for now, we broke things up into 3 seperate
files, each read seperately. One for pc and instructions, one for registers, and one for
memory reads. Each is scrolled through essentially independantly: new pc data is read and checked
whenever pc changes, new register data is checked whenever any register changes, and a new mem
read value is gotten whenever DataAdrM or MemRWM changes and MemRWM is not zero. I'm not super
sure about the last one. Currently it looks like things should be working, but it goes wrong after,
like, 3 instructions.
2021-01-23 01:27:01 +00:00
|
|
|
// read pc trace file
|
|
|
|
integer data_file_PC, scan_file_PC;
|
2021-01-22 19:11:17 +00:00
|
|
|
initial begin
|
2021-02-07 03:14:48 +00:00
|
|
|
data_file_PC = $fopen("/courses/e190ax/busybear_boot/parsedPC.txt", "r");
|
change how testbench reads data
we're not sure if this is a good idea, but for now, we broke things up into 3 seperate
files, each read seperately. One for pc and instructions, one for registers, and one for
memory reads. Each is scrolled through essentially independantly: new pc data is read and checked
whenever pc changes, new register data is checked whenever any register changes, and a new mem
read value is gotten whenever DataAdrM or MemRWM changes and MemRWM is not zero. I'm not super
sure about the last one. Currently it looks like things should be working, but it goes wrong after,
like, 3 instructions.
2021-01-23 01:27:01 +00:00
|
|
|
if (data_file_PC == 0) begin
|
2021-01-22 19:11:17 +00:00
|
|
|
$display("file couldn't be opened");
|
2021-02-12 17:21:56 +00:00
|
|
|
$stop;
|
2021-01-22 19:11:17 +00:00
|
|
|
end
|
|
|
|
end
|
change how testbench reads data
we're not sure if this is a good idea, but for now, we broke things up into 3 seperate
files, each read seperately. One for pc and instructions, one for registers, and one for
memory reads. Each is scrolled through essentially independantly: new pc data is read and checked
whenever pc changes, new register data is checked whenever any register changes, and a new mem
read value is gotten whenever DataAdrM or MemRWM changes and MemRWM is not zero. I'm not super
sure about the last one. Currently it looks like things should be working, but it goes wrong after,
like, 3 instructions.
2021-01-23 01:27:01 +00:00
|
|
|
|
2021-02-01 23:57:06 +00:00
|
|
|
integer data_file_PCW, scan_file_PCW;
|
|
|
|
initial begin
|
2021-02-07 03:14:48 +00:00
|
|
|
data_file_PCW = $fopen("/courses/e190ax/busybear_boot/parsedPC.txt", "r");
|
2021-02-01 23:57:06 +00:00
|
|
|
if (data_file_PCW == 0) begin
|
|
|
|
$display("file couldn't be opened");
|
2021-02-12 17:21:56 +00:00
|
|
|
$stop;
|
2021-02-01 23:57:06 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
change how testbench reads data
we're not sure if this is a good idea, but for now, we broke things up into 3 seperate
files, each read seperately. One for pc and instructions, one for registers, and one for
memory reads. Each is scrolled through essentially independantly: new pc data is read and checked
whenever pc changes, new register data is checked whenever any register changes, and a new mem
read value is gotten whenever DataAdrM or MemRWM changes and MemRWM is not zero. I'm not super
sure about the last one. Currently it looks like things should be working, but it goes wrong after,
like, 3 instructions.
2021-01-23 01:27:01 +00:00
|
|
|
// read register trace file
|
|
|
|
integer data_file_rf, scan_file_rf;
|
|
|
|
initial begin
|
2021-02-07 03:14:48 +00:00
|
|
|
data_file_rf = $fopen("/courses/e190ax/busybear_boot/parsedRegs.txt", "r");
|
change how testbench reads data
we're not sure if this is a good idea, but for now, we broke things up into 3 seperate
files, each read seperately. One for pc and instructions, one for registers, and one for
memory reads. Each is scrolled through essentially independantly: new pc data is read and checked
whenever pc changes, new register data is checked whenever any register changes, and a new mem
read value is gotten whenever DataAdrM or MemRWM changes and MemRWM is not zero. I'm not super
sure about the last one. Currently it looks like things should be working, but it goes wrong after,
like, 3 instructions.
2021-01-23 01:27:01 +00:00
|
|
|
if (data_file_rf == 0) begin
|
|
|
|
$display("file couldn't be opened");
|
2021-02-12 17:21:56 +00:00
|
|
|
$stop;
|
change how testbench reads data
we're not sure if this is a good idea, but for now, we broke things up into 3 seperate
files, each read seperately. One for pc and instructions, one for registers, and one for
memory reads. Each is scrolled through essentially independantly: new pc data is read and checked
whenever pc changes, new register data is checked whenever any register changes, and a new mem
read value is gotten whenever DataAdrM or MemRWM changes and MemRWM is not zero. I'm not super
sure about the last one. Currently it looks like things should be working, but it goes wrong after,
like, 3 instructions.
2021-01-23 01:27:01 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-02-02 03:08:11 +00:00
|
|
|
// read CSR trace file
|
|
|
|
integer data_file_csr, scan_file_csr;
|
|
|
|
initial begin
|
2021-02-07 03:14:48 +00:00
|
|
|
data_file_csr = $fopen("/courses/e190ax/busybear_boot/parsedCSRs.txt", "r");
|
2021-02-02 03:08:11 +00:00
|
|
|
if (data_file_csr == 0) begin
|
|
|
|
$display("file couldn't be opened");
|
2021-02-12 17:21:56 +00:00
|
|
|
$stop;
|
2021-02-02 03:08:11 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
change how testbench reads data
we're not sure if this is a good idea, but for now, we broke things up into 3 seperate
files, each read seperately. One for pc and instructions, one for registers, and one for
memory reads. Each is scrolled through essentially independantly: new pc data is read and checked
whenever pc changes, new register data is checked whenever any register changes, and a new mem
read value is gotten whenever DataAdrM or MemRWM changes and MemRWM is not zero. I'm not super
sure about the last one. Currently it looks like things should be working, but it goes wrong after,
like, 3 instructions.
2021-01-23 01:27:01 +00:00
|
|
|
// read memreads trace file
|
2021-01-25 01:43:47 +00:00
|
|
|
integer data_file_memR, scan_file_memR;
|
change how testbench reads data
we're not sure if this is a good idea, but for now, we broke things up into 3 seperate
files, each read seperately. One for pc and instructions, one for registers, and one for
memory reads. Each is scrolled through essentially independantly: new pc data is read and checked
whenever pc changes, new register data is checked whenever any register changes, and a new mem
read value is gotten whenever DataAdrM or MemRWM changes and MemRWM is not zero. I'm not super
sure about the last one. Currently it looks like things should be working, but it goes wrong after,
like, 3 instructions.
2021-01-23 01:27:01 +00:00
|
|
|
initial begin
|
2021-02-07 03:14:48 +00:00
|
|
|
data_file_memR = $fopen("/courses/e190ax/busybear_boot/parsedMemRead.txt", "r");
|
2021-01-25 01:43:47 +00:00
|
|
|
if (data_file_memR == 0) begin
|
|
|
|
$display("file couldn't be opened");
|
2021-02-12 17:21:56 +00:00
|
|
|
$stop;
|
2021-01-25 01:43:47 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
// read memwrite trace file
|
|
|
|
integer data_file_memW, scan_file_memW;
|
|
|
|
initial begin
|
2021-02-07 03:14:48 +00:00
|
|
|
data_file_memW = $fopen("/courses/e190ax/busybear_boot/parsedMemWrite.txt", "r");
|
2021-01-25 01:43:47 +00:00
|
|
|
if (data_file_memW == 0) begin
|
change how testbench reads data
we're not sure if this is a good idea, but for now, we broke things up into 3 seperate
files, each read seperately. One for pc and instructions, one for registers, and one for
memory reads. Each is scrolled through essentially independantly: new pc data is read and checked
whenever pc changes, new register data is checked whenever any register changes, and a new mem
read value is gotten whenever DataAdrM or MemRWM changes and MemRWM is not zero. I'm not super
sure about the last one. Currently it looks like things should be working, but it goes wrong after,
like, 3 instructions.
2021-01-23 01:27:01 +00:00
|
|
|
$display("file couldn't be opened");
|
2021-02-12 17:21:56 +00:00
|
|
|
$stop;
|
change how testbench reads data
we're not sure if this is a good idea, but for now, we broke things up into 3 seperate
files, each read seperately. One for pc and instructions, one for registers, and one for
memory reads. Each is scrolled through essentially independantly: new pc data is read and checked
whenever pc changes, new register data is checked whenever any register changes, and a new mem
read value is gotten whenever DataAdrM or MemRWM changes and MemRWM is not zero. I'm not super
sure about the last one. Currently it looks like things should be working, but it goes wrong after,
like, 3 instructions.
2021-01-23 01:27:01 +00:00
|
|
|
end
|
|
|
|
end
|
2021-02-12 19:56:20 +00:00
|
|
|
|
2021-02-12 17:21:56 +00:00
|
|
|
integer warningCount = 0;
|
2021-02-12 19:56:20 +00:00
|
|
|
|
2021-02-23 18:59:06 +00:00
|
|
|
//logic[63:0] adrTranslation[4:0];
|
|
|
|
//string translationType[4:0] = {"rf", "writeAdr", "PCW", "PC", "readAdr"};
|
|
|
|
//initial begin
|
|
|
|
// for(int i=0; i<5; i++) begin
|
|
|
|
// adrTranslation[i] = 64'b0;
|
|
|
|
// end
|
|
|
|
//end
|
|
|
|
|
|
|
|
//function logic equal(logic[63:0] adr, logic[63:0] adrExpected, integer func);
|
|
|
|
// if (adr[11:0] !== adrExpected[11:0]) begin
|
|
|
|
// equal = 1'b0;
|
|
|
|
// end else begin
|
|
|
|
// equal = 1'b1;
|
|
|
|
// if ((adr+adrTranslation[func]) !== adrExpected) begin
|
|
|
|
// adrTranslation[func] = adrExpected - adr;
|
|
|
|
// $display("warning: probably new address translation %x for %s at instr %0d", adrTranslation[func], translationType[func], instrs);
|
|
|
|
// warningCount += 1;
|
|
|
|
// end
|
|
|
|
// end
|
|
|
|
//endfunction
|
|
|
|
|
|
|
|
// pretty sure this isn't necessary anymore, but keeping this for now since its easier
|
2021-02-12 19:56:20 +00:00
|
|
|
function logic equal(logic[63:0] adr, logic[63:0] adrExpected, integer func);
|
2021-02-23 18:59:06 +00:00
|
|
|
equal = adr === adrExpected;
|
2021-02-12 19:56:20 +00:00
|
|
|
endfunction
|
|
|
|
|
|
|
|
|
2021-02-12 17:21:56 +00:00
|
|
|
`define ERROR \
|
|
|
|
#10; \
|
|
|
|
$display("processed %0d instructions with %0d warnings", instrs, warningCount); \
|
|
|
|
$stop;
|
change how testbench reads data
we're not sure if this is a good idea, but for now, we broke things up into 3 seperate
files, each read seperately. One for pc and instructions, one for registers, and one for
memory reads. Each is scrolled through essentially independantly: new pc data is read and checked
whenever pc changes, new register data is checked whenever any register changes, and a new mem
read value is gotten whenever DataAdrM or MemRWM changes and MemRWM is not zero. I'm not super
sure about the last one. Currently it looks like things should be working, but it goes wrong after,
like, 3 instructions.
2021-01-23 01:27:01 +00:00
|
|
|
|
2021-01-22 20:05:58 +00:00
|
|
|
logic [63:0] pcExpected;
|
2021-02-02 01:27:43 +00:00
|
|
|
logic [63:0] regExpected;
|
|
|
|
integer regNumExpected;
|
|
|
|
|
change how testbench reads data
we're not sure if this is a good idea, but for now, we broke things up into 3 seperate
files, each read seperately. One for pc and instructions, one for registers, and one for
memory reads. Each is scrolled through essentially independantly: new pc data is read and checked
whenever pc changes, new register data is checked whenever any register changes, and a new mem
read value is gotten whenever DataAdrM or MemRWM changes and MemRWM is not zero. I'm not super
sure about the last one. Currently it looks like things should be working, but it goes wrong after,
like, 3 instructions.
2021-01-23 01:27:01 +00:00
|
|
|
genvar i;
|
|
|
|
generate
|
2021-02-02 01:27:43 +00:00
|
|
|
for(i=1; i<32; i++) begin
|
2021-02-23 18:59:06 +00:00
|
|
|
always @(dut.hart.ieu.dp.regf.rf[i]) begin
|
2021-02-04 19:22:09 +00:00
|
|
|
if ($time == 0) begin
|
|
|
|
scan_file_rf = $fscanf(data_file_rf, "%x\n", regExpected);
|
2021-02-23 18:59:06 +00:00
|
|
|
if (dut.hart.ieu.dp.regf.rf[i] != regExpected) begin
|
2021-02-23 22:01:23 +00:00
|
|
|
$display("%0t ps, instr %0d: rf[%0d] does not equal rf expected: %x, %x", $time, instrs, i, dut.hart.ieu.dp.regf.rf[i], regExpected);
|
2021-02-12 17:21:56 +00:00
|
|
|
`ERROR
|
2021-02-04 19:22:09 +00:00
|
|
|
end
|
|
|
|
end else begin
|
2021-02-02 01:27:43 +00:00
|
|
|
scan_file_rf = $fscanf(data_file_rf, "%d\n", regNumExpected);
|
|
|
|
scan_file_rf = $fscanf(data_file_rf, "%x\n", regExpected);
|
|
|
|
if (i != regNumExpected) begin
|
2021-02-23 22:01:23 +00:00
|
|
|
$display("%0t ps, instr %0d: wrong register changed: %0d, %0d expected", $time, instrs, i, regNumExpected);
|
2021-02-12 19:56:20 +00:00
|
|
|
`ERROR
|
2021-02-02 01:27:43 +00:00
|
|
|
end
|
2021-02-23 18:59:06 +00:00
|
|
|
if (~equal(dut.hart.ieu.dp.regf.rf[i],regExpected, 0)) begin
|
2021-02-23 22:01:23 +00:00
|
|
|
$display("%0t ps, instr %0d: rf[%0d] does not equal rf expected: %x, %x", $time, instrs, i, dut.hart.ieu.dp.regf.rf[i], regExpected);
|
2021-02-12 17:21:56 +00:00
|
|
|
`ERROR
|
2021-02-02 01:27:43 +00:00
|
|
|
end
|
2021-02-23 18:59:06 +00:00
|
|
|
if (dut.hart.ieu.dp.regf.rf[i] !== regExpected) begin
|
|
|
|
force dut.hart.ieu.dp.regf.rf[i] = regExpected;
|
|
|
|
release dut.hart.ieu.dp.regf.rf[i];
|
2021-02-12 19:56:20 +00:00
|
|
|
end
|
2021-02-02 01:27:43 +00:00
|
|
|
end
|
change how testbench reads data
we're not sure if this is a good idea, but for now, we broke things up into 3 seperate
files, each read seperately. One for pc and instructions, one for registers, and one for
memory reads. Each is scrolled through essentially independantly: new pc data is read and checked
whenever pc changes, new register data is checked whenever any register changes, and a new mem
read value is gotten whenever DataAdrM or MemRWM changes and MemRWM is not zero. I'm not super
sure about the last one. Currently it looks like things should be working, but it goes wrong after,
like, 3 instructions.
2021-01-23 01:27:01 +00:00
|
|
|
end
|
|
|
|
end
|
2021-02-02 01:27:43 +00:00
|
|
|
endgenerate
|
2021-02-23 22:01:23 +00:00
|
|
|
|
|
|
|
`define MAX_RAM 'h8000000
|
|
|
|
logic [`XLEN-1:0] RAM[`MAX_RAM:0];
|
|
|
|
logic [`XLEN-1:0] readRAM, readPC;
|
|
|
|
integer RAMAdr, RAMPC;
|
|
|
|
assign RAMAdr = HADDR - 'h80000000;
|
|
|
|
assign RAMPC = PCF - 'h80000000;
|
|
|
|
always @(HWDATA or HADDR or HSIZE or HWRITE or dut.hart.MemRWM[1]) begin
|
|
|
|
if ((HWRITE || dut.hart.MemRWM[1]) && (HADDR >= 'h80000000 && HADDR <= 'h87FFFFFF)) begin
|
|
|
|
if (HWRITE) begin
|
|
|
|
RAM[RAMAdr] = HWDATA;
|
|
|
|
end else begin
|
|
|
|
readRAM = RAM[RAMAdr];
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
always @(PCF) begin
|
|
|
|
if (PCF >= 'h80000000 && PCF <= 'h87FFFFFF) begin
|
|
|
|
readPC = RAM[RAMPC];
|
|
|
|
end
|
|
|
|
end
|
change how testbench reads data
we're not sure if this is a good idea, but for now, we broke things up into 3 seperate
files, each read seperately. One for pc and instructions, one for registers, and one for
memory reads. Each is scrolled through essentially independantly: new pc data is read and checked
whenever pc changes, new register data is checked whenever any register changes, and a new mem
read value is gotten whenever DataAdrM or MemRWM changes and MemRWM is not zero. I'm not super
sure about the last one. Currently it looks like things should be working, but it goes wrong after,
like, 3 instructions.
2021-01-23 01:27:01 +00:00
|
|
|
|
2021-01-28 18:16:38 +00:00
|
|
|
logic [`XLEN-1:0] readAdrExpected;
|
change how testbench reads data
we're not sure if this is a good idea, but for now, we broke things up into 3 seperate
files, each read seperately. One for pc and instructions, one for registers, and one for
memory reads. Each is scrolled through essentially independantly: new pc data is read and checked
whenever pc changes, new register data is checked whenever any register changes, and a new mem
read value is gotten whenever DataAdrM or MemRWM changes and MemRWM is not zero. I'm not super
sure about the last one. Currently it looks like things should be working, but it goes wrong after,
like, 3 instructions.
2021-01-23 01:27:01 +00:00
|
|
|
// this might need to change
|
2021-02-23 18:59:06 +00:00
|
|
|
always @(dut.hart.MemRWM[1] or HADDR) begin
|
|
|
|
if (dut.hart.MemRWM[1]) begin
|
2021-01-28 18:16:38 +00:00
|
|
|
if($feof(data_file_memR)) begin
|
|
|
|
$display("no more memR data to read");
|
2021-02-12 17:21:56 +00:00
|
|
|
`ERROR
|
2021-01-28 18:16:38 +00:00
|
|
|
end
|
|
|
|
scan_file_memR = $fscanf(data_file_memR, "%x\n", readAdrExpected);
|
2021-01-30 17:38:18 +00:00
|
|
|
scan_file_memR = $fscanf(data_file_memR, "%x\n", HRDATA);
|
|
|
|
#1;
|
2021-02-12 19:56:20 +00:00
|
|
|
if (~equal(HADDR,readAdrExpected,4)) begin
|
2021-02-23 22:01:23 +00:00
|
|
|
$display("%0t ps, instr %0d: HADDR does not equal readAdrExpected: %x, %x", $time, instrs, HADDR, readAdrExpected);
|
|
|
|
`ERROR
|
|
|
|
end
|
|
|
|
if (HRDATA != readRAM && (HADDR >= 'h80000000 && HADDR <= 'h87FFFFFF)) begin
|
|
|
|
$display("warning %0t ps, instr %0d: HRDATA does not equal readRAM: %x, %x from address %x", $time, instrs, HRDATA, readRAM, HADDR);
|
|
|
|
warningCount += 1;
|
2021-02-12 17:21:56 +00:00
|
|
|
`ERROR
|
2021-01-28 18:16:38 +00:00
|
|
|
end
|
2021-01-25 01:43:47 +00:00
|
|
|
end
|
|
|
|
end
|
2021-01-30 17:38:18 +00:00
|
|
|
|
2021-01-26 01:06:13 +00:00
|
|
|
logic [`XLEN-1:0] writeDataExpected, writeAdrExpected;
|
2021-01-25 01:43:47 +00:00
|
|
|
// this might need to change
|
2021-02-23 22:01:23 +00:00
|
|
|
always @(HWDATA or HADDR or HSIZE or HWRITE) begin
|
2021-01-26 01:06:13 +00:00
|
|
|
#1;
|
2021-01-30 17:38:18 +00:00
|
|
|
if (HWRITE) begin
|
2021-01-28 18:16:38 +00:00
|
|
|
if($feof(data_file_memW)) begin
|
|
|
|
$display("no more memW data to read");
|
2021-02-12 17:21:56 +00:00
|
|
|
`ERROR
|
2021-01-28 18:16:38 +00:00
|
|
|
end
|
2021-01-25 01:43:47 +00:00
|
|
|
scan_file_memW = $fscanf(data_file_memW, "%x\n", writeDataExpected);
|
2021-01-26 01:06:13 +00:00
|
|
|
scan_file_memW = $fscanf(data_file_memW, "%x\n", writeAdrExpected);
|
2021-01-30 17:38:18 +00:00
|
|
|
if (writeDataExpected != HWDATA) begin
|
2021-02-23 22:01:23 +00:00
|
|
|
$display("%0t ps, instr %0d: HWDATA does not equal writeDataExpected: %x, %x", $time, instrs, HWDATA, writeDataExpected);
|
2021-02-12 17:21:56 +00:00
|
|
|
`ERROR
|
2021-01-26 01:06:13 +00:00
|
|
|
end
|
2021-02-12 19:56:20 +00:00
|
|
|
if (~equal(writeAdrExpected,HADDR,1)) begin
|
2021-02-23 22:01:23 +00:00
|
|
|
$display("%0t ps, instr %0d: HADDR does not equal writeAdrExpected: %x, %x", $time, instrs, HADDR, writeAdrExpected);
|
2021-02-12 17:21:56 +00:00
|
|
|
`ERROR
|
2021-01-25 01:43:47 +00:00
|
|
|
end
|
2021-01-22 20:05:58 +00:00
|
|
|
end
|
change how testbench reads data
we're not sure if this is a good idea, but for now, we broke things up into 3 seperate
files, each read seperately. One for pc and instructions, one for registers, and one for
memory reads. Each is scrolled through essentially independantly: new pc data is read and checked
whenever pc changes, new register data is checked whenever any register changes, and a new mem
read value is gotten whenever DataAdrM or MemRWM changes and MemRWM is not zero. I'm not super
sure about the last one. Currently it looks like things should be working, but it goes wrong after,
like, 3 instructions.
2021-01-23 01:27:01 +00:00
|
|
|
end
|
|
|
|
|
2021-02-04 19:22:09 +00:00
|
|
|
integer totalCSR = 0;
|
|
|
|
logic [99:0] StartCSRexpected[63:0];
|
|
|
|
string StartCSRname[99:0];
|
|
|
|
initial begin
|
|
|
|
while(1) begin
|
|
|
|
scan_file_csr = $fscanf(data_file_csr, "%s\n", StartCSRname[totalCSR]);
|
|
|
|
if(StartCSRname[totalCSR] == "---") begin
|
|
|
|
break;
|
|
|
|
end
|
|
|
|
scan_file_csr = $fscanf(data_file_csr, "%x\n", StartCSRexpected[totalCSR]);
|
|
|
|
totalCSR = totalCSR + 1;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-02-04 20:13:36 +00:00
|
|
|
`define CHECK_CSR2(CSR, PATH) \
|
2021-02-02 06:06:03 +00:00
|
|
|
string CSR; \
|
|
|
|
logic [63:0] expected``CSR``; \
|
|
|
|
//CSR checking \
|
2021-02-04 20:13:36 +00:00
|
|
|
always @(``PATH``.``CSR``_REGW) begin \
|
2021-02-02 06:06:03 +00:00
|
|
|
if ($time > 1) begin \
|
|
|
|
scan_file_csr = $fscanf(data_file_csr, "%s\n", CSR); \
|
|
|
|
scan_file_csr = $fscanf(data_file_csr, "%x\n", expected``CSR``); \
|
|
|
|
if(CSR.icompare(`"CSR`")) begin \
|
2021-02-23 22:01:23 +00:00
|
|
|
$display("%0t ps, instr %0d: %s changed, expected %s", $time, instrs, `"CSR`", CSR); \
|
2021-02-02 06:06:03 +00:00
|
|
|
end \
|
2021-02-04 20:13:36 +00:00
|
|
|
if(``PATH``.``CSR``_REGW != ``expected``CSR) begin \
|
2021-02-23 22:01:23 +00:00
|
|
|
$display("%0t ps, instr %0d: %s does not equal %s expected: %x, %x", $time, instrs, `"CSR`", CSR, ``PATH``.``CSR``_REGW, ``expected``CSR); \
|
2021-02-12 17:21:56 +00:00
|
|
|
`ERROR \
|
2021-02-04 19:22:09 +00:00
|
|
|
end \
|
|
|
|
end else begin \
|
|
|
|
for(integer j=0; j<totalCSR; j++) begin \
|
|
|
|
if(!StartCSRname[j].icompare(`"CSR`")) begin \
|
2021-02-04 20:13:36 +00:00
|
|
|
if(``PATH``.``CSR``_REGW != StartCSRexpected[j]) begin \
|
2021-02-23 22:01:23 +00:00
|
|
|
$display("%0t ps, instr %0d: %s does not equal %s expected: %x, %x", $time, instrs, `"CSR`", StartCSRname[j], ``PATH``.``CSR``_REGW, StartCSRexpected[j]); \
|
2021-02-12 17:21:56 +00:00
|
|
|
`ERROR \
|
2021-02-04 19:22:09 +00:00
|
|
|
end \
|
|
|
|
end \
|
2021-02-02 06:06:03 +00:00
|
|
|
end \
|
|
|
|
end \
|
|
|
|
end
|
2021-02-04 20:13:36 +00:00
|
|
|
`define CHECK_CSR(CSR) \
|
2021-02-23 18:59:06 +00:00
|
|
|
`CHECK_CSR2(CSR, dut.hart.priv.csr)
|
|
|
|
`define CSRM dut.hart.priv.csr.genblk1.csrm
|
|
|
|
`define CSRS dut.hart.priv.csr.genblk1.csrs.genblk1
|
2021-02-02 06:06:03 +00:00
|
|
|
|
|
|
|
//`CHECK_CSR(FCSR)
|
2021-02-17 01:03:24 +00:00
|
|
|
`CHECK_CSR2(MCAUSE, `CSRM)
|
2021-02-02 06:06:03 +00:00
|
|
|
`CHECK_CSR(MCOUNTEREN)
|
|
|
|
`CHECK_CSR(MEDELEG)
|
2021-02-17 01:03:24 +00:00
|
|
|
`CHECK_CSR(MEPC)
|
2021-02-04 20:13:36 +00:00
|
|
|
//`CHECK_CSR(MHARTID)
|
2021-02-17 01:03:24 +00:00
|
|
|
`CHECK_CSR(MIDELEG)
|
2021-02-02 06:06:03 +00:00
|
|
|
`CHECK_CSR(MIE)
|
2021-02-17 01:03:24 +00:00
|
|
|
//`CHECK_CSR(MIP)
|
|
|
|
`CHECK_CSR2(MISA, `CSRM)
|
|
|
|
`CHECK_CSR2(MSCRATCH, `CSRM)
|
|
|
|
`CHECK_CSR(MSTATUS)
|
|
|
|
`CHECK_CSR2(MTVAL, `CSRM)
|
2021-02-02 06:06:03 +00:00
|
|
|
`CHECK_CSR(MTVEC)
|
2021-02-17 01:03:24 +00:00
|
|
|
//`CHECK_CSR2(PMPADDR0, `CSRM)
|
|
|
|
//`CHECK_CSR2(PMPCFG0, `CSRM)
|
|
|
|
`CHECK_CSR2(SATP, `CSRS)
|
|
|
|
`CHECK_CSR2(SCAUSE, `CSRS)
|
2021-02-02 06:06:03 +00:00
|
|
|
`CHECK_CSR(SCOUNTEREN)
|
2021-02-17 01:03:24 +00:00
|
|
|
`CHECK_CSR(SEPC)
|
2021-02-12 03:42:58 +00:00
|
|
|
`CHECK_CSR(SIE)
|
2021-02-17 01:03:24 +00:00
|
|
|
`CHECK_CSR2(SSCRATCH, `CSRS)
|
|
|
|
`CHECK_CSR(SSTATUS)
|
|
|
|
`CHECK_CSR2(STVAL, `CSRS)
|
|
|
|
`CHECK_CSR(STVEC)
|
2021-02-02 03:08:11 +00:00
|
|
|
|
2021-01-26 00:45:26 +00:00
|
|
|
logic speculative;
|
2021-01-24 00:01:44 +00:00
|
|
|
initial begin
|
|
|
|
speculative = 0;
|
2021-01-26 00:45:26 +00:00
|
|
|
speculative = 0;
|
2021-01-24 00:01:44 +00:00
|
|
|
end
|
2021-01-26 00:45:26 +00:00
|
|
|
logic [63:0] lastInstrF, lastPC, lastPC2;
|
2021-02-01 23:57:06 +00:00
|
|
|
|
|
|
|
string PCtextW, PCtext2W;
|
|
|
|
logic [31:0] InstrWExpected;
|
|
|
|
logic [63:0] PCWExpected;
|
2021-02-23 18:59:06 +00:00
|
|
|
always @(dut.hart.ifu.PCW or dut.hart.ieu.InstrValidW) begin
|
|
|
|
if(dut.hart.ieu.InstrValidW && dut.hart.ifu.PCW != 0) begin
|
2021-02-01 23:57:06 +00:00
|
|
|
if($feof(data_file_PCW)) begin
|
|
|
|
$display("no more PC data to read");
|
2021-02-12 17:21:56 +00:00
|
|
|
`ERROR
|
2021-02-01 23:57:06 +00:00
|
|
|
end
|
|
|
|
scan_file_PCW = $fscanf(data_file_PCW, "%s\n", PCtextW);
|
2021-02-12 04:06:12 +00:00
|
|
|
if (PCtextW != "ret" && PCtextW != "fence" && PCtextW != "nop" && PCtextW != "mret" && PCtextW != "sfence.vma" && PCtextW != "unimp") begin
|
2021-02-01 23:57:06 +00:00
|
|
|
scan_file_PC = $fscanf(data_file_PCW, "%s\n", PCtext2W);
|
|
|
|
PCtextW = {PCtextW, " ", PCtext2W};
|
|
|
|
end
|
|
|
|
scan_file_PCW = $fscanf(data_file_PCW, "%x\n", InstrWExpected);
|
|
|
|
// then expected PC value
|
|
|
|
scan_file_PCW = $fscanf(data_file_PCW, "%x\n", PCWExpected);
|
2021-02-23 18:59:06 +00:00
|
|
|
if(~equal(dut.hart.ifu.PCW,PCWExpected,2)) begin
|
2021-02-23 22:01:23 +00:00
|
|
|
$display("%0t ps, instr %0d: PCW does not equal PCW expected: %x, %x", $time, instrs, dut.hart.ifu.PCW, PCWExpected);
|
2021-02-12 17:21:56 +00:00
|
|
|
`ERROR
|
2021-02-01 23:57:06 +00:00
|
|
|
end
|
|
|
|
//if(it.InstrW != InstrWExpected) begin
|
2021-02-23 22:01:23 +00:00
|
|
|
// $display("%0t ps, instr %0d: InstrW does not equal InstrW expected: %x, %x", $time, instrs, it.InstrW, InstrWExpected);
|
2021-02-01 23:57:06 +00:00
|
|
|
//end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-01-26 17:34:12 +00:00
|
|
|
string PCtext, PCtext2;
|
2021-01-25 01:43:47 +00:00
|
|
|
integer instrs;
|
|
|
|
initial begin
|
|
|
|
instrs = 0;
|
|
|
|
end
|
change how testbench reads data
we're not sure if this is a good idea, but for now, we broke things up into 3 seperate
files, each read seperately. One for pc and instructions, one for registers, and one for
memory reads. Each is scrolled through essentially independantly: new pc data is read and checked
whenever pc changes, new register data is checked whenever any register changes, and a new mem
read value is gotten whenever DataAdrM or MemRWM changes and MemRWM is not zero. I'm not super
sure about the last one. Currently it looks like things should be working, but it goes wrong after,
like, 3 instructions.
2021-01-23 01:27:01 +00:00
|
|
|
always @(PCF) begin
|
2021-01-26 00:45:26 +00:00
|
|
|
lastInstrF = InstrF;
|
|
|
|
lastPC <= PCF;
|
|
|
|
lastPC2 <= lastPC;
|
2021-02-12 19:56:20 +00:00
|
|
|
if (speculative && ~equal(lastPC,pcExpected,3)) begin
|
|
|
|
speculative = ~equal(PCF,pcExpected,3);
|
2021-01-24 00:01:44 +00:00
|
|
|
end
|
2021-01-26 00:45:26 +00:00
|
|
|
else begin
|
2021-01-28 18:16:38 +00:00
|
|
|
if($feof(data_file_PC)) begin
|
|
|
|
$display("no more PC data to read");
|
2021-02-12 17:21:56 +00:00
|
|
|
`ERROR
|
2021-01-28 18:16:38 +00:00
|
|
|
end
|
2021-01-28 19:47:40 +00:00
|
|
|
scan_file_PC = $fscanf(data_file_PC, "%s\n", PCtext);
|
2021-02-12 04:06:12 +00:00
|
|
|
if (PCtext != "ret" && PCtext != "fence" && PCtext != "nop" && PCtext != "mret" && PCtext != "sfence.vma" && PCtext != "unimp") begin
|
2021-01-28 19:47:40 +00:00
|
|
|
scan_file_PC = $fscanf(data_file_PC, "%s\n", PCtext2);
|
|
|
|
PCtext = {PCtext, " ", PCtext2};
|
|
|
|
end
|
2021-01-24 00:01:44 +00:00
|
|
|
scan_file_PC = $fscanf(data_file_PC, "%x\n", InstrF);
|
2021-02-01 19:44:56 +00:00
|
|
|
if(InstrF[6:0] == 7'b1010011) begin // for now, NOP out any float instrs
|
2021-01-30 19:52:47 +00:00
|
|
|
InstrF = 32'b0010011;
|
2021-02-01 23:57:06 +00:00
|
|
|
$display("warning: NOPing out %s at PC=%0x", PCtext, PCF);
|
2021-02-12 17:21:56 +00:00
|
|
|
warningCount += 1;
|
2021-02-01 19:44:56 +00:00
|
|
|
end
|
2021-02-12 03:42:58 +00:00
|
|
|
if(InstrF[28:27] != 2'b11 && InstrF[6:0] == 7'b0101111) begin //for now, replace non-SC A instrs with LD
|
|
|
|
InstrF = {12'b0, InstrF[19:7], 7'b0000011};
|
|
|
|
$display("warning: replacing AMO instr %s at PC=%0x with ld", PCtext, PCF);
|
2021-02-12 17:21:56 +00:00
|
|
|
warningCount += 1;
|
2021-02-12 03:42:58 +00:00
|
|
|
end
|
2021-01-24 00:01:44 +00:00
|
|
|
// then expected PC value
|
|
|
|
scan_file_PC = $fscanf(data_file_PC, "%x\n", pcExpected);
|
2021-01-29 00:44:58 +00:00
|
|
|
if (instrs <= 10 || (instrs <= 100 && instrs % 10 == 0) ||
|
2021-01-29 05:13:14 +00:00
|
|
|
(instrs <= 1000 && instrs % 100 == 0) || (instrs <= 10000 && instrs % 1000 == 0) ||
|
2021-02-07 03:14:48 +00:00
|
|
|
(instrs <= 100000 && instrs % 10000 == 0) || (instrs <= 1000000 && instrs % 100000 == 0)) begin
|
2021-01-28 18:33:22 +00:00
|
|
|
$display("loaded %0d instructions", instrs);
|
|
|
|
end
|
2021-01-25 01:43:47 +00:00
|
|
|
instrs += 1;
|
2021-01-24 00:01:44 +00:00
|
|
|
// are we at a branch/jump?
|
2021-02-07 03:14:48 +00:00
|
|
|
casex (lastInstrF[31:0])
|
|
|
|
32'b00000000001000000000000001110011, // URET
|
|
|
|
32'b00010000001000000000000001110011, // SRET
|
|
|
|
32'b00110000001000000000000001110011, // MRET
|
|
|
|
32'bXXXXXXXXXXXXXXXXXXXXXXXXX1101111, // JAL
|
|
|
|
32'bXXXXXXXXXXXXXXXXXXXXXXXXX1100111, // JALR
|
|
|
|
32'bXXXXXXXXXXXXXXXXXXXXXXXXX1100011, // B
|
|
|
|
32'bXXXXXXXXXXXXXXXX110XXXXXXXXXXX01, // C.BEQZ
|
|
|
|
32'bXXXXXXXXXXXXXXXX111XXXXXXXXXXX01, // C.BNEZ
|
|
|
|
32'bXXXXXXXXXXXXXXXX101XXXXXXXXXXX01: // C.J
|
2021-01-28 19:40:35 +00:00
|
|
|
speculative = 1;
|
2021-02-07 03:14:48 +00:00
|
|
|
32'bXXXXXXXXXXXXXXXX1001000000000010: // C.EBREAK:
|
2021-01-28 19:40:35 +00:00
|
|
|
speculative = 0; // tbh don't really know what should happen here
|
2021-02-07 03:14:48 +00:00
|
|
|
32'bXXXXXXXXXXXXXXXX1000XXXXX0000010, // C.JR
|
|
|
|
32'bXXXXXXXXXXXXXXXX1001XXXXX0000010: // C.JALR //this is RV64 only so no C.JAL
|
2021-01-26 00:45:26 +00:00
|
|
|
speculative = 1;
|
2021-01-24 00:01:44 +00:00
|
|
|
default:
|
2021-01-26 00:45:26 +00:00
|
|
|
speculative = 0;
|
2021-01-24 00:01:44 +00:00
|
|
|
endcase
|
|
|
|
|
|
|
|
//check things!
|
2021-02-12 19:56:20 +00:00
|
|
|
if ((~speculative) && (~equal(PCF,pcExpected,3))) begin
|
2021-02-23 22:01:23 +00:00
|
|
|
$display("%0t ps, instr %0d: PC does not equal PC expected: %x, %x", $time, instrs, PCF, pcExpected);
|
2021-02-12 17:21:56 +00:00
|
|
|
`ERROR
|
2021-01-24 00:01:44 +00:00
|
|
|
end
|
2021-02-23 22:01:23 +00:00
|
|
|
if (readPC != InstrF) begin
|
|
|
|
$display("%0t ps, instr %0d: readPC does not equal InstrF: %x, %x", $time, instrs, readPC, InstrF);
|
|
|
|
warningCount += 1;
|
|
|
|
end
|
2021-01-22 20:05:58 +00:00
|
|
|
end
|
2021-01-22 19:11:17 +00:00
|
|
|
end
|
|
|
|
|
2021-01-23 02:14:45 +00:00
|
|
|
// Track names of instructions
|
|
|
|
string InstrFName, InstrDName, InstrEName, InstrMName, InstrWName;
|
|
|
|
logic [31:0] InstrW;
|
|
|
|
instrNameDecTB dec(InstrF, InstrFName);
|
2021-02-23 18:59:06 +00:00
|
|
|
instrTrackerTB it(clk, reset, dut.hart.ieu.dp.FlushE,
|
|
|
|
dut.hart.ifu.InstrD, dut.hart.ifu.InstrE,
|
|
|
|
dut.hart.ifu.InstrM, InstrW,
|
2021-01-23 02:14:45 +00:00
|
|
|
InstrDName, InstrEName, InstrMName, InstrWName);
|
2021-01-21 21:17:34 +00:00
|
|
|
|
|
|
|
// generate clock to sequence tests
|
|
|
|
always
|
|
|
|
begin
|
2021-01-21 22:55:05 +00:00
|
|
|
clk <= 1; # 5; clk <= 0; # 5;
|
2021-01-21 21:17:34 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
endmodule
|