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-03-30 19:25:07 +00:00
|
|
|
logic [31:0] CheckInstrD;
|
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-02-24 05:28:33 +00:00
|
|
|
|
2021-01-21 22:55:05 +00:00
|
|
|
// instantiate processor and memories
|
2021-02-28 06:02:21 +00:00
|
|
|
wallypipelinedsoc dut(.*);
|
2021-01-21 21:17:34 +00:00
|
|
|
|
2021-02-24 01:51:18 +00:00
|
|
|
|
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-02-24 05:28:33 +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-04-05 23:38:43 +00:00
|
|
|
data_file_PC = $fopen("../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-02-24 05:28:33 +00:00
|
|
|
end
|
2021-01-22 19:11:17 +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
|
|
|
|
2021-02-01 23:57:06 +00:00
|
|
|
integer data_file_PCW, scan_file_PCW;
|
|
|
|
initial begin
|
2021-04-05 23:38:43 +00:00
|
|
|
data_file_PCW = $fopen("../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-24 05:28:33 +00:00
|
|
|
end
|
2021-02-01 23:57:06 +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
|
|
|
// read register trace file
|
|
|
|
integer data_file_rf, scan_file_rf;
|
|
|
|
initial begin
|
2021-04-05 23:38:43 +00:00
|
|
|
data_file_rf = $fopen("../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;
|
2021-02-24 05:28:33 +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-02 03:08:11 +00:00
|
|
|
// read CSR trace file
|
|
|
|
integer data_file_csr, scan_file_csr;
|
|
|
|
initial begin
|
2021-04-05 23:38:43 +00:00
|
|
|
data_file_csr = $fopen("../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-24 05:28:33 +00:00
|
|
|
end
|
2021-02-02 03:08:11 +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
|
|
|
// 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-04-05 23:38:43 +00:00
|
|
|
data_file_memR = $fopen("../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-02-24 05:28:33 +00:00
|
|
|
end
|
2021-01-25 01:43:47 +00:00
|
|
|
end
|
2021-02-24 05:28:33 +00:00
|
|
|
|
2021-01-25 01:43:47 +00:00
|
|
|
// read memwrite trace file
|
|
|
|
integer data_file_memW, scan_file_memW;
|
|
|
|
initial begin
|
2021-04-05 23:38:43 +00:00
|
|
|
data_file_memW = $fopen("../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;
|
2021-02-24 05:28:33 +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-12 19:56:20 +00:00
|
|
|
|
2021-03-08 19:26:26 +00:00
|
|
|
// initial loading of memories
|
|
|
|
initial begin
|
2021-04-05 23:38:43 +00:00
|
|
|
$readmemh("../busybear_boot/bootmem.txt", dut.uncore.bootdtim.RAM, 'h1000 >> 3);
|
|
|
|
$readmemh("../busybear_boot/ram.txt", dut.uncore.dtim.RAM);
|
|
|
|
$readmemh("../busybear_boot/bootmem.txt", dut.imem.bootram, 'h1000 >> 3);
|
|
|
|
$readmemh("../busybear_boot/ram.txt", dut.imem.RAM);
|
2021-03-18 21:37:10 +00:00
|
|
|
$readmemb(`TWO_BIT_PRELOAD, dut.hart.ifu.bpred.Predictor.DirPredictor.PHT.memory);
|
2021-03-15 22:27:27 +00:00
|
|
|
$readmemb(`BTB_PRELOAD, dut.hart.ifu.bpred.TargetPredictor.memory.memory);
|
2021-03-08 19:26:26 +00:00
|
|
|
end
|
|
|
|
|
2021-02-12 17:21:56 +00:00
|
|
|
integer warningCount = 0;
|
2021-03-17 01:42:26 +00:00
|
|
|
integer instrs;
|
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;
|
2021-03-30 19:25:07 +00:00
|
|
|
logic [`XLEN-1:0] PCW;
|
|
|
|
|
2021-03-31 17:41:40 +00:00
|
|
|
flopenr #(`XLEN) PCWReg(clk, reset, ~dut.hart.ieu.dp.StallW, dut.hart.ifu.PCM, PCW);
|
2021-02-02 01:27:43 +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
|
|
|
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-03-22 22:12:41 +00:00
|
|
|
$display("%0t ps, instr %0d: wrong register changed: %0d, %0d expected to switch to %x from %x", $time, instrs, i, regNumExpected, regExpected, dut.hart.ieu.dp.regf.rf[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-03-08 19:48:12 +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];
|
|
|
|
//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-24 05:28:33 +00:00
|
|
|
|
|
|
|
// RAM and bootram are addressed in 64-bit blocks - this logic handles R/W
|
|
|
|
// including subwords. Brief explanation on signals:
|
|
|
|
//
|
|
|
|
// readMask: bitmask of bits to read / write, left-shifted to align with
|
|
|
|
// nearest 64-bit boundary - examples
|
|
|
|
// HSIZE = 0 -> readMask = 11111111
|
|
|
|
// HSIZE = 1 -> readMask = 1111111111111111
|
|
|
|
//
|
|
|
|
// In the linux boot, the processor spends the first ~5 instructions in
|
|
|
|
// bootram, before jr jumps to main RAM
|
|
|
|
|
2021-02-24 01:51:18 +00:00
|
|
|
logic [63:0] readMask;
|
|
|
|
assign readMask = ((1 << (8*(1 << HSIZE))) - 1) << 8 * HADDR[2:0];
|
2021-02-24 19:35:28 +00:00
|
|
|
|
|
|
|
logic [`XLEN-1:0] readAdrExpected;
|
|
|
|
|
2021-03-22 20:52:22 +00:00
|
|
|
always @(dut.HRDATA) begin
|
2021-03-30 19:25:07 +00:00
|
|
|
#2;
|
|
|
|
if (dut.hart.MemRWM[1] && ~HWRITE && HADDR[31:3] != dut.PCF[31:3] && dut.HRDATA !== {64{1'bx}}) begin
|
2021-03-22 18:54:05 +00:00
|
|
|
//$display("%0t", $time);
|
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);
|
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
|
2021-03-22 20:52:22 +00:00
|
|
|
if ((readMask & HRDATA) !== (readMask & dut.HRDATA)) begin
|
2021-03-22 21:28:39 +00:00
|
|
|
if (HADDR inside `BUSYBEAR_FIX_READ) begin
|
2021-03-22 22:12:41 +00:00
|
|
|
//$display("warning %0t ps, instr %0d, adr %0d: forcing HRDATA to expected: %x, %x", $time, instrs, HADDR, HRDATA, dut.HRDATA);
|
2021-03-22 21:28:39 +00:00
|
|
|
force dut.uncore.HRDATA = HRDATA;
|
|
|
|
#9;
|
|
|
|
release dut.uncore.HRDATA;
|
|
|
|
warningCount += 1;
|
|
|
|
end else begin
|
|
|
|
$display("%0t ps, instr %0d: ExpectedHRDATA does not equal dut.HRDATA: %x, %x from address %x, %x", $time, instrs, HRDATA, dut.HRDATA, HADDR, HSIZE);
|
|
|
|
`ERROR
|
|
|
|
end
|
2021-01-28 18:16:38 +00:00
|
|
|
end
|
2021-03-22 18:54:05 +00:00
|
|
|
//end else if(dut.hart.MemRWM[1]) begin
|
2021-03-22 20:52:22 +00:00
|
|
|
// $display("%x, %x, %x, %t", HADDR, dut.PCF, dut.HRDATA, $time);
|
2021-03-22 18:47:43 +00:00
|
|
|
|
2021-01-25 01:43:47 +00:00
|
|
|
end
|
2021-03-22 18:47:43 +00:00
|
|
|
|
2021-01-25 01:43:47 +00:00
|
|
|
end
|
2021-02-24 05:28:33 +00:00
|
|
|
|
2021-01-26 01:06:13 +00:00
|
|
|
logic [`XLEN-1:0] writeDataExpected, writeAdrExpected;
|
2021-02-24 19:35:28 +00:00
|
|
|
|
2021-01-25 01:43:47 +00:00
|
|
|
// this might need to change
|
2021-03-01 20:56:04 +00:00
|
|
|
//always @(HWDATA or HADDR or HSIZE or HWRITE) begin
|
|
|
|
always @(negedge HWRITE) begin
|
|
|
|
//#1;
|
|
|
|
if ($time != 0) 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
|
2021-02-24 05:28:33 +00:00
|
|
|
scan_file_csr = $fscanf(data_file_csr, "%s\n", StartCSRname[totalCSR]);
|
2021-02-04 19:22:09 +00:00
|
|
|
if(StartCSRname[totalCSR] == "---") begin
|
|
|
|
break;
|
|
|
|
end
|
|
|
|
scan_file_csr = $fscanf(data_file_csr, "%x\n", StartCSRexpected[totalCSR]);
|
|
|
|
totalCSR = totalCSR + 1;
|
|
|
|
end
|
|
|
|
end
|
2021-02-24 05:28:33 +00:00
|
|
|
|
2021-03-17 01:42:26 +00:00
|
|
|
always @(dut.hart.priv.csr.genblk1.csrm.MCAUSE_REGW) begin
|
2021-03-30 19:25:07 +00:00
|
|
|
if (dut.hart.priv.csr.genblk1.csrm.MCAUSE_REGW == 2 && instrs > 1) begin
|
2021-03-22 22:24:31 +00:00
|
|
|
$display("!!!!!! illegal instruction !!!!!!!!!!");
|
|
|
|
$display("(as a reminder, MCAUSE and MEPC are set by this)");
|
|
|
|
$display("at %0t ps, instr %0d, HADDR %x", $time, instrs, HADDR);
|
|
|
|
`ERROR
|
|
|
|
end
|
2021-03-17 01:42:26 +00:00
|
|
|
if (dut.hart.priv.csr.genblk1.csrm.MCAUSE_REGW == 5 && instrs != 0) begin
|
2021-03-22 22:24:31 +00:00
|
|
|
$display("!!!!!! illegal (physical) memory access !!!!!!!!!!");
|
2021-03-17 01:42:26 +00:00
|
|
|
$display("(as a reminder, MCAUSE and MEPC are set by this)");
|
|
|
|
$display("at %0t ps, instr %0d, HADDR %x", $time, instrs, HADDR);
|
|
|
|
`ERROR
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-04-05 16:47:11 +00:00
|
|
|
string sepc_lit = "SEPC";
|
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 \
|
2021-04-05 16:47:11 +00:00
|
|
|
if (sepc_lit.icompare(`"CSR`")) begin #1; end \
|
2021-02-02 06:06:03 +00:00
|
|
|
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-24 05:28:33 +00:00
|
|
|
`CHECK_CSR2(CSR, dut.hart.priv.csr)
|
|
|
|
`define CSRM dut.hart.priv.csr.genblk1.csrm
|
2021-02-23 18:59:06 +00:00
|
|
|
`define CSRS dut.hart.priv.csr.genblk1.csrs.genblk1
|
2021-02-02 06:06:03 +00:00
|
|
|
|
2021-04-05 16:47:11 +00:00
|
|
|
|
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)
|
2021-02-28 16:46:53 +00:00
|
|
|
//`CHECK_CSR2(PMdut.PCFG0, `CSRM)
|
2021-03-11 06:45:14 +00:00
|
|
|
`CHECK_CSR(SATP)
|
2021-02-17 01:03:24 +00:00
|
|
|
`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-04-05 16:47:11 +00:00
|
|
|
//$stop;
|
|
|
|
initial begin
|
|
|
|
#34140421;
|
|
|
|
$stop;
|
|
|
|
end
|
2021-03-22 22:12:41 +00:00
|
|
|
initial begin //this is temporary until the bug can be fixed!!!
|
2021-03-30 19:25:07 +00:00
|
|
|
#11130100;
|
2021-03-22 22:12:41 +00:00
|
|
|
force dut.hart.ieu.dp.regf.rf[5] = 64'h0000000080000004;
|
|
|
|
#100;
|
|
|
|
release dut.hart.ieu.dp.regf.rf[5];
|
|
|
|
end
|
|
|
|
|
2021-01-26 00:45:26 +00:00
|
|
|
logic speculative;
|
2021-01-24 00:01:44 +00:00
|
|
|
initial begin
|
|
|
|
speculative = 0;
|
|
|
|
end
|
2021-03-30 19:25:07 +00:00
|
|
|
logic [63:0] lastCheckInstrD, lastPC, lastPC2;
|
2021-02-01 23:57:06 +00:00
|
|
|
|
|
|
|
string PCtextW, PCtext2W;
|
|
|
|
logic [31:0] InstrWExpected;
|
|
|
|
logic [63:0] PCWExpected;
|
2021-03-30 19:25:07 +00:00
|
|
|
always @(PCW or dut.hart.ieu.InstrValidW) begin
|
|
|
|
if(dut.hart.ieu.InstrValidW && 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-03-30 19:25:07 +00:00
|
|
|
if(~equal(PCW,PCWExpected,2)) begin
|
|
|
|
$display("%0t ps, instr %0d: PCW does not equal PCW expected: %x, %x", $time, instrs, 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
|
|
|
initial begin
|
|
|
|
instrs = 0;
|
2021-02-24 05:28:33 +00:00
|
|
|
end
|
2021-02-26 20:26:54 +00:00
|
|
|
logic [31:0] InstrMask;
|
|
|
|
logic forcedInstr;
|
2021-03-30 19:25:07 +00:00
|
|
|
logic [63:0] lastPCD;
|
|
|
|
always @(dut.hart.ifu.PCD or dut.hart.ifu.InstrRawD or reset or negedge dut.hart.ifu.StallE) begin
|
2021-03-01 20:56:04 +00:00
|
|
|
if(~HWRITE) begin
|
2021-03-30 19:25:07 +00:00
|
|
|
#2;
|
|
|
|
if (~reset && dut.hart.ifu.InstrRawD[15:0] !== {16{1'bx}} && dut.hart.ifu.PCD !== 64'h0 && ~dut.hart.ifu.StallE) begin
|
|
|
|
if (dut.hart.ifu.PCD !== lastPCD) begin
|
|
|
|
lastCheckInstrD = CheckInstrD;
|
|
|
|
lastPC <= dut.hart.ifu.PCD;
|
|
|
|
lastPC2 <= lastPC;
|
|
|
|
if (speculative && (lastPC != pcExpected)) begin
|
|
|
|
speculative = ~equal(dut.hart.ifu.PCD,pcExpected,3);
|
|
|
|
if(dut.hart.ifu.PCD===pcExpected) begin
|
|
|
|
if(dut.hart.ifu.InstrRawD[6:0] == 7'b1010011) begin // for now, NOP out any float instrs
|
|
|
|
force CheckInstrD = 32'b0010011;
|
|
|
|
release CheckInstrD;
|
|
|
|
force dut.hart.ifu.InstrRawD = 32'b0010011;
|
|
|
|
#7;
|
|
|
|
release dut.hart.ifu.InstrRawD;
|
|
|
|
$display("warning: NOPing out %s at PC=%0x, instr %0d, time %0t", PCtext, dut.hart.ifu.PCD, instrs, $time);
|
|
|
|
warningCount += 1;
|
|
|
|
forcedInstr = 1;
|
|
|
|
end
|
|
|
|
else begin
|
|
|
|
forcedInstr = 0;
|
|
|
|
end
|
2021-03-08 21:24:19 +00:00
|
|
|
end
|
2021-03-01 19:08:35 +00:00
|
|
|
end
|
2021-03-30 19:25:07 +00:00
|
|
|
else begin
|
|
|
|
if($feof(data_file_PC)) begin
|
|
|
|
$display("no more PC data to read");
|
|
|
|
`ERROR
|
2021-03-01 19:08:35 +00:00
|
|
|
end
|
2021-03-30 19:25:07 +00:00
|
|
|
scan_file_PC = $fscanf(data_file_PC, "%s\n", PCtext);
|
|
|
|
if (PCtext != "ret" && PCtext != "fence" && PCtext != "nop" && PCtext != "mret" && PCtext != "sfence.vma" && PCtext != "unimp") begin
|
|
|
|
scan_file_PC = $fscanf(data_file_PC, "%s\n", PCtext2);
|
|
|
|
PCtext = {PCtext, " ", PCtext2};
|
|
|
|
end
|
|
|
|
scan_file_PC = $fscanf(data_file_PC, "%x\n", CheckInstrD);
|
|
|
|
if(dut.hart.ifu.PCD === pcExpected) begin
|
|
|
|
if(dut.hart.ifu.InstrRawD[6:0] == 7'b1010011) begin // for now, NOP out any float instrs
|
|
|
|
force CheckInstrD = 32'b0010011;
|
|
|
|
release CheckInstrD;
|
|
|
|
force dut.hart.ifu.InstrRawD = 32'b0010011;
|
|
|
|
#7;
|
|
|
|
release dut.hart.ifu.InstrRawD;
|
|
|
|
$display("warning: NOPing out %s at PC=%0x, instr %0d, time %0t", PCtext, dut.hart.ifu.PCD, instrs, $time);
|
|
|
|
warningCount += 1;
|
|
|
|
forcedInstr = 1;
|
|
|
|
end
|
|
|
|
else begin
|
|
|
|
forcedInstr = 0;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
// then expected PC value
|
|
|
|
scan_file_PC = $fscanf(data_file_PC, "%x\n", pcExpected);
|
|
|
|
if (instrs <= 10 || (instrs <= 100 && instrs % 10 == 0) ||
|
|
|
|
(instrs <= 1000 && instrs % 100 == 0) || (instrs <= 10000 && instrs % 1000 == 0) ||
|
|
|
|
(instrs <= 100000 && instrs % 10000 == 0) || (instrs <= 1000000 && instrs % 100000 == 0)) begin
|
|
|
|
$display("loaded %0d instructions", instrs);
|
|
|
|
end
|
|
|
|
instrs += 1;
|
|
|
|
// are we at a branch/jump?
|
|
|
|
casex (lastCheckInstrD[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
|
|
|
|
speculative = 1;
|
|
|
|
32'bXXXXXXXXXXXXXXXX1001000000000010: // C.EBREAK:
|
|
|
|
speculative = 0; // tbh don't really know what should happen here
|
|
|
|
32'bXXXXXXXXXXXXXXXX1000XXXXX0000010, // C.JR
|
|
|
|
32'bXXXXXXXXXXXXXXXX1001XXXXX0000010: // C.JALR //this is RV64 only so no C.JAL
|
|
|
|
speculative = 1;
|
|
|
|
default:
|
|
|
|
speculative = 0;
|
|
|
|
endcase
|
|
|
|
|
|
|
|
//check things!
|
|
|
|
if ((~speculative) && (~equal(dut.hart.ifu.PCD,pcExpected,3))) begin
|
|
|
|
$display("%0t ps, instr %0d: PC does not equal PC expected: %x, %x", $time, instrs, dut.hart.ifu.PCD, pcExpected);
|
|
|
|
`ERROR
|
|
|
|
end
|
|
|
|
InstrMask = CheckInstrD[1:0] == 2'b11 ? 32'hFFFFFFFF : 32'h0000FFFF;
|
|
|
|
if ((~forcedInstr) && (~speculative) && ((InstrMask & dut.hart.ifu.InstrRawD) !== (InstrMask & CheckInstrD))) begin
|
|
|
|
$display("%0t ps, instr %0d: InstrD does not equal CheckInstrD: %x, %x, PC: %x", $time, instrs, dut.hart.ifu.InstrRawD, CheckInstrD, dut.hart.ifu.PCD);
|
|
|
|
`ERROR
|
2021-03-01 19:08:35 +00:00
|
|
|
end
|
2021-03-01 18:50:42 +00:00
|
|
|
end
|
2021-02-26 20:26:54 +00:00
|
|
|
end
|
2021-03-30 19:25:07 +00:00
|
|
|
lastPCD = dut.hart.ifu.PCD;
|
2021-02-23 22:01:23 +00:00
|
|
|
end
|
2021-03-01 20:56:04 +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;
|
2021-03-30 19:25:07 +00:00
|
|
|
instrNameDecTB dec(dut.hart.ifu.ic.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
|
2021-03-30 19:25:07 +00:00
|
|
|
module instrTrackerTB(
|
|
|
|
input logic clk, reset, FlushE,
|
|
|
|
input logic [31:0] InstrD,
|
|
|
|
input logic [31:0] InstrE, InstrM,
|
|
|
|
output logic [31:0] InstrW,
|
|
|
|
output string InstrDName, InstrEName, InstrMName, InstrWName);
|
|
|
|
|
|
|
|
// stage Instr to Writeback for visualization
|
|
|
|
//flopr #(32) InstrWReg(clk, reset, InstrM, InstrW);
|
|
|
|
|
|
|
|
instrNameDecTB ddec(InstrD, InstrDName);
|
|
|
|
instrNameDecTB edec(InstrE, InstrEName);
|
|
|
|
instrNameDecTB mdec(InstrM, InstrMName);
|
|
|
|
instrNameDecTB wdec(InstrW, InstrWName);
|
|
|
|
endmodule
|
|
|
|
|
|
|
|
// decode the instruction name, to help the test bench
|
|
|
|
module instrNameDecTB(
|
|
|
|
input logic [31:0] instr,
|
|
|
|
output string name);
|
|
|
|
|
|
|
|
logic [6:0] op;
|
|
|
|
logic [2:0] funct3;
|
|
|
|
logic [6:0] funct7;
|
|
|
|
logic [11:0] imm;
|
|
|
|
|
|
|
|
assign op = instr[6:0];
|
|
|
|
assign funct3 = instr[14:12];
|
|
|
|
assign funct7 = instr[31:25];
|
|
|
|
assign imm = instr[31:20];
|
|
|
|
|
|
|
|
// it would be nice to add the operands to the name
|
|
|
|
// create another variable called decoded
|
|
|
|
|
|
|
|
always_comb
|
|
|
|
casez({op, funct3})
|
|
|
|
10'b0000000_000: name = "BAD";
|
|
|
|
10'b0000011_000: name = "LB";
|
|
|
|
10'b0000011_001: name = "LH";
|
|
|
|
10'b0000011_010: name = "LW";
|
|
|
|
10'b0000011_011: name = "LD";
|
|
|
|
10'b0000011_100: name = "LBU";
|
|
|
|
10'b0000011_101: name = "LHU";
|
|
|
|
10'b0000011_110: name = "LWU";
|
|
|
|
10'b0010011_000: if (instr[31:15] == 0 && instr[11:7] ==0) name = "NOP/FLUSH";
|
|
|
|
else name = "ADDI";
|
|
|
|
10'b0010011_001: if (funct7[6:1] == 6'b000000) name = "SLLI";
|
|
|
|
else name = "ILLEGAL";
|
|
|
|
10'b0010011_010: name = "SLTI";
|
|
|
|
10'b0010011_011: name = "SLTIU";
|
|
|
|
10'b0010011_100: name = "XORI";
|
|
|
|
10'b0010011_101: if (funct7[6:1] == 6'b000000) name = "SRLI";
|
|
|
|
else if (funct7[6:1] == 6'b010000) name = "SRAI";
|
|
|
|
else name = "ILLEGAL";
|
|
|
|
10'b0010011_110: name = "ORI";
|
|
|
|
10'b0010011_111: name = "ANDI";
|
|
|
|
10'b0010111_???: name = "AUIPC";
|
|
|
|
10'b0100011_000: name = "SB";
|
|
|
|
10'b0100011_001: name = "SH";
|
|
|
|
10'b0100011_010: name = "SW";
|
|
|
|
10'b0100011_011: name = "SD";
|
|
|
|
10'b0011011_000: name = "ADDIW";
|
|
|
|
10'b0011011_001: name = "SLLIW";
|
|
|
|
10'b0011011_101: if (funct7 == 7'b0000000) name = "SRLIW";
|
|
|
|
else if (funct7 == 7'b0100000) name = "SRAIW";
|
|
|
|
else name = "ILLEGAL";
|
|
|
|
10'b0111011_000: if (funct7 == 7'b0000000) name = "ADDW";
|
|
|
|
else if (funct7 == 7'b0100000) name = "SUBW";
|
|
|
|
else name = "ILLEGAL";
|
|
|
|
10'b0111011_001: name = "SLLW";
|
|
|
|
10'b0111011_101: if (funct7 == 7'b0000000) name = "SRLW";
|
|
|
|
else if (funct7 == 7'b0100000) name = "SRAW";
|
|
|
|
else name = "ILLEGAL";
|
|
|
|
10'b0110011_000: if (funct7 == 7'b0000000) name = "ADD";
|
|
|
|
else if (funct7 == 7'b0000001) name = "MUL";
|
|
|
|
else if (funct7 == 7'b0100000) name = "SUB";
|
|
|
|
else name = "ILLEGAL";
|
|
|
|
10'b0110011_001: if (funct7 == 7'b0000000) name = "SLL";
|
|
|
|
else if (funct7 == 7'b0000001) name = "MULH";
|
|
|
|
else name = "ILLEGAL";
|
|
|
|
10'b0110011_010: if (funct7 == 7'b0000000) name = "SLT";
|
|
|
|
else if (funct7 == 7'b0000001) name = "MULHSU";
|
|
|
|
else name = "ILLEGAL";
|
|
|
|
10'b0110011_011: if (funct7 == 7'b0000000) name = "SLTU";
|
|
|
|
else if (funct7 == 7'b0000001) name = "DIV";
|
|
|
|
else name = "ILLEGAL";
|
|
|
|
10'b0110011_100: if (funct7 == 7'b0000000) name = "XOR";
|
|
|
|
else if (funct7 == 7'b0000001) name = "MUL";
|
|
|
|
else name = "ILLEGAL";
|
|
|
|
10'b0110011_101: if (funct7 == 7'b0000000) name = "SRL";
|
|
|
|
else if (funct7 == 7'b0000001) name = "DIVU";
|
|
|
|
else if (funct7 == 7'b0100000) name = "SRA";
|
|
|
|
else name = "ILLEGAL";
|
|
|
|
10'b0110011_110: if (funct7 == 7'b0000000) name = "OR";
|
|
|
|
else if (funct7 == 7'b0000001) name = "REM";
|
|
|
|
else name = "ILLEGAL";
|
|
|
|
10'b0110011_111: if (funct7 == 7'b0000000) name = "AND";
|
|
|
|
else if (funct7 == 7'b0000001) name = "REMU";
|
|
|
|
else name = "ILLEGAL";
|
|
|
|
10'b0110111_???: name = "LUI";
|
|
|
|
10'b1100011_000: name = "BEQ";
|
|
|
|
10'b1100011_001: name = "BNE";
|
|
|
|
10'b1100011_100: name = "BLT";
|
|
|
|
10'b1100011_101: name = "BGE";
|
|
|
|
10'b1100011_110: name = "BLTU";
|
|
|
|
10'b1100011_111: name = "BGEU";
|
|
|
|
10'b1100111_000: name = "JALR";
|
|
|
|
10'b1101111_???: name = "JAL";
|
|
|
|
10'b1110011_000: if (imm == 0) name = "ECALL";
|
|
|
|
else if (imm == 1) name = "EBREAK";
|
|
|
|
else if (imm == 2) name = "URET";
|
|
|
|
else if (imm == 258) name = "SRET";
|
|
|
|
else if (imm == 770) name = "MRET";
|
|
|
|
else name = "ILLEGAL";
|
|
|
|
10'b1110011_001: name = "CSRRW";
|
|
|
|
10'b1110011_010: name = "CSRRS";
|
|
|
|
10'b1110011_011: name = "CSRRC";
|
|
|
|
10'b1110011_101: name = "CSRRWI";
|
|
|
|
10'b1110011_110: name = "CSRRSI";
|
|
|
|
10'b1110011_111: name = "CSRRCI";
|
|
|
|
10'b0001111_???: name = "FENCE";
|
|
|
|
default: name = "ILLEGAL";
|
|
|
|
endcase
|
|
|
|
endmodule
|
|
|
|
|