From aa921606980d039fa8a7784b15a8826247f5402c Mon Sep 17 00:00:00 2001 From: Andrei Solodovnikov Date: Mon, 1 Apr 2024 04:48:09 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9B=D0=A05.=20=D0=A0=D0=B5=D1=84=D0=B0=D0=BA?= =?UTF-8?q?=D1=82=D0=BE=D1=80=20=D1=82=D0=B5=D1=81=D1=82=D0=B1=D0=B5=D0=BD?= =?UTF-8?q?=D1=87=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Labs/05. Main decoder/tb_decoder_riscv.sv | 1173 ++++++++++++++------- 1 file changed, 766 insertions(+), 407 deletions(-) diff --git a/Labs/05. Main decoder/tb_decoder_riscv.sv b/Labs/05. Main decoder/tb_decoder_riscv.sv index a8492bb..1fc5e62 100644 --- a/Labs/05. Main decoder/tb_decoder_riscv.sv +++ b/Labs/05. Main decoder/tb_decoder_riscv.sv @@ -2,460 +2,821 @@ * Project Name : Architectures of Processor Systems (APS) lab work * Organization : National Research University of Electronic Technology (MIET) * Department : Institute of Microdevices and Control Systems -* Author(s) : Nikita Bulavin -* Email(s) : nekkit6@edu.miet.ru +* Author(s) : Andrei Solodovnikov +* Email(s) : hepoh@org.miet.ru See https://github.com/MPSU/APS/blob/master/LICENSE file for licensing details. * ------------------------------------------------------------------------------ */ + module tb_decoder_riscv(); import riscv_pkg::*; - parameter delay = 4; - parameter cycle = 200; // per one opcode + typedef class riscv_instr; + riscv_instr instr = new(); - reg [31:0] instr; - wire [1:0] a_sel; - wire [2:0] b_sel; - wire [ALU_OP_WIDTH-1:0] alu_op; - wire [2:0] csr_op; - wire csr_we; - wire mem_req; - wire mem_we; - wire [2:0] mem_size; - wire gpr_we; - wire [1:0] wb_sel; - wire illegal_instr; - wire branch; - wire jal; - wire jalr; - wire mret; + logic clk, test_has_been_finished; + logic [31:0] fetched_instr_i = '0; - reg a_sel_miss; - reg b_sel_miss; - reg alu_op_miss; - reg csr_op_miss; - reg csr_we_miss; - reg mem_req_miss; - reg mem_we_miss; - reg mem_size_miss; - reg gpr_we_miss; - reg wb_sel_miss; - reg illegal_miss; - reg branch_miss; - reg jal_miss; - reg jalr_miss; - reg mret_miss; + int err_count; - string opcode_type; - string instr_type; + //list of all valid opcodes + logic [4:0] opcode_array[11] = { + LOAD_OPCODE, + MISC_MEM_OPCODE, + OP_IMM_OPCODE, + AUIPC_OPCODE, + STORE_OPCODE, + OP_OPCODE, + LUI_OPCODE, + BRANCH_OPCODE, + JALR_OPCODE, + JAL_OPCODE, + SYSTEM_OPCODE + }; - decoder_riscv dut ( - .fetched_instr_i (instr), - .a_sel_o (a_sel), - .b_sel_o (b_sel), - .alu_op_o (alu_op), - .csr_op_o (csr_op), - .csr_we_o (csr_we), - .mem_req_o (mem_req), - .mem_we_o (mem_we), - .mem_size_o (mem_size), - .gpr_we_o (gpr_we), - .wb_sel_o (wb_sel), - .illegal_instr_o (illegal_instr), - .branch_o (branch), - .jal_o (jal), - .jalr_o (jalr), - .mret_o (mret) + /* + Since randomize with overconstraining slows down simulation, it has been + decided to make a list of all codes instead of looping over every possible + combination func3 and func7. + */ + logic [14:0] valid_codes[44] = { + {LOAD_OPCODE , 3'h0, 7'h00}, + {LOAD_OPCODE , 3'h1, 7'h00}, + {LOAD_OPCODE , 3'h2, 7'h00}, + {LOAD_OPCODE , 3'h4, 7'h00}, + {LOAD_OPCODE , 3'h5, 7'h00}, + {MISC_MEM_OPCODE, 3'h0, 7'h00}, + {OP_IMM_OPCODE , 3'h0, 7'h00}, + {OP_IMM_OPCODE , 3'h1, 7'h00}, + {OP_IMM_OPCODE , 3'h2, 7'h00}, + {OP_IMM_OPCODE , 3'h3, 7'h00}, + {OP_IMM_OPCODE , 3'h4, 7'h00}, + {OP_IMM_OPCODE , 3'h5, 7'h00}, + {OP_IMM_OPCODE , 3'h5, 7'h20}, + {OP_IMM_OPCODE , 3'h6, 7'h00}, + {OP_IMM_OPCODE , 3'h7, 7'h00}, + {AUIPC_OPCODE , 3'h0, 7'h00}, + {STORE_OPCODE , 3'h0, 7'h00}, + {STORE_OPCODE , 3'h1, 7'h00}, + {STORE_OPCODE , 3'h2, 7'h00}, + {OP_OPCODE , 3'h0, 7'h00}, + {OP_OPCODE , 3'h0, 7'h20}, + {OP_OPCODE , 3'h1, 7'h00}, + {OP_OPCODE , 3'h2, 7'h00}, + {OP_OPCODE , 3'h3, 7'h00}, + {OP_OPCODE , 3'h4, 7'h00}, + {OP_OPCODE , 3'h5, 7'h00}, + {OP_OPCODE , 3'h5, 7'h20}, + {OP_OPCODE , 3'h6, 7'h00}, + {OP_OPCODE , 3'h7, 7'h00}, + {LUI_OPCODE , 3'h0, 7'h00}, + {BRANCH_OPCODE , 3'h0, 7'h00}, + {BRANCH_OPCODE , 3'h1, 7'h00}, + {BRANCH_OPCODE , 3'h4, 7'h00}, + {BRANCH_OPCODE , 3'h5, 7'h00}, + {BRANCH_OPCODE , 3'h6, 7'h00}, + {BRANCH_OPCODE , 3'h7, 7'h00}, + {JALR_OPCODE , 3'h0, 7'h00}, + {JAL_OPCODE , 3'h0, 7'h00}, + {SYSTEM_OPCODE , 3'h1, 7'h00}, + {SYSTEM_OPCODE , 3'h2, 7'h00}, + {SYSTEM_OPCODE , 3'h3, 7'h00}, + {SYSTEM_OPCODE , 3'h5, 7'h00}, + {SYSTEM_OPCODE , 3'h6, 7'h00}, + {SYSTEM_OPCODE , 3'h7, 7'h00} + }; + + logic [14:0] invalid_codes[38] = { + {LOAD_OPCODE , 3'h3, 7'h00}, + {LOAD_OPCODE , 3'h6, 7'h00}, + {LOAD_OPCODE , 3'h7, 7'h00}, + {MISC_MEM_OPCODE, 3'h1, 7'h00}, + {MISC_MEM_OPCODE, 3'h2, 7'h00}, + {MISC_MEM_OPCODE, 3'h3, 7'h00}, + {MISC_MEM_OPCODE, 3'h4, 7'h00}, + {MISC_MEM_OPCODE, 3'h5, 7'h00}, + {MISC_MEM_OPCODE, 3'h6, 7'h00}, + {MISC_MEM_OPCODE, 3'h7, 7'h00}, + {OP_IMM_OPCODE , 3'h0, 7'h20}, + {OP_IMM_OPCODE , 3'h1, 7'h20}, + {OP_IMM_OPCODE , 3'h2, 7'h20}, + {OP_IMM_OPCODE , 3'h3, 7'h20}, + {OP_IMM_OPCODE , 3'h4, 7'h20}, + {OP_IMM_OPCODE , 3'h6, 7'h20}, + {OP_IMM_OPCODE , 3'h7, 7'h20}, + {STORE_OPCODE , 3'h3, 7'h00}, + {STORE_OPCODE , 3'h4, 7'h00}, + {STORE_OPCODE , 3'h5, 7'h00}, + {STORE_OPCODE , 3'h6, 7'h00}, + {STORE_OPCODE , 3'h7, 7'h00}, + {OP_OPCODE , 3'h1, 7'h20}, + {OP_OPCODE , 3'h2, 7'h20}, + {OP_OPCODE , 3'h3, 7'h20}, + {OP_OPCODE , 3'h4, 7'h20}, + {OP_OPCODE , 3'h6, 7'h20}, + {OP_OPCODE , 3'h7, 7'h20}, + {BRANCH_OPCODE , 3'h2, 7'h00}, + {BRANCH_OPCODE , 3'h3, 7'h00}, + {JALR_OPCODE , 3'h1, 7'h00}, + {JALR_OPCODE , 3'h2, 7'h00}, + {JALR_OPCODE , 3'h3, 7'h00}, + {JALR_OPCODE , 3'h4, 7'h00}, + {JALR_OPCODE , 3'h5, 7'h00}, + {JALR_OPCODE , 3'h6, 7'h00}, + {JALR_OPCODE , 3'h7, 7'h00}, + {SYSTEM_OPCODE , 3'h4, 7'h00} + }; + + initial begin + $display("Test has been started"); + $display( "\n\n==========================\nCLICK THE BUTTON 'Run All'\n==========================\n"); $stop(); + + valid_instrs_direct_test(); + valid_instrs_random_test(); + illegal_instr_direct_test(); + illegal_instrs_random_test(); + + $display("\nTest has been finished\nNumber of errors: %d\n", err_count); + test_has_been_finished = 1'b1; + $finish(); + end + + function void randomize_with_given_opcode(input logic[4:0] given_opcode); + if(!instr.randomize() with {(opcode == given_opcode);}) begin + $fatal(1, "Can't ranomize instr with opcode == %0h", given_opcode); + end + endfunction + + task valid_instrs_direct_test(); + /* + Enumeration of all possible instructions by every opcode, func3 and func7. + Additionally, ecall, ebreak and mret instructions are generated manually. + */ + foreach(valid_codes[i]) begin + if(instr.randomize() with {(opcode == valid_codes[i][14:10]) && (func3 == valid_codes[i][9:7]) && (func7 == valid_codes[i][6:0]);}) begin + @(posedge clk); + fetched_instr_i <= instr.bits; + end + else begin + $fatal(1, "Can't randomize instruction with opcode == %02h, func3 == %0h, func7 == %0h", valid_codes[i][14:10], valid_codes[i][9:7], valid_codes[i][6:0]); + end + end + for(int i = 0; i < 3; i++) begin + @(posedge clk); + fetched_instr_i <= instr.system_instrs[i]; + end + endtask + + task valid_instrs_random_test(); + /* + A thousand random instructions for each opcode. + */ + foreach(opcode_array[i]) begin + repeat(1e3) begin + randomize_with_given_opcode(opcode_array[i]); + @(posedge clk); + fetched_instr_i <= instr.bits; + end + end + endtask + + task illegal_instr_direct_test(); + /* + That's where real things are happening. + This task is intent to check all the ways to get illegal_instr_o goes 1. + Test trying: + - incorrect low 2 bits on every opcode; + - incorrect opcode; + - incorrect func3 and func7 where it's possible; + - incorrect fence, ecall, ebreak, mret instructions + */ + incorrect_low_two_bits_test(); + incorrect_opcode_test(); + incorrect_func3_func7_test(); + incorrect_hardcode_instrs(); + endtask + + task incorrect_low_two_bits_test(); + /* + For every opcode we generate a valid instruction and corrupt 2 low bits. + So for every opcode we try 3 different instructions. + */ + foreach(opcode_array[i]) begin + for(logic[1:0] j = 2'b00; j < 2'b11; j++) begin + randomize_with_given_opcode(opcode_array[i]); + @(posedge clk); + fetched_instr_i <= {instr.bits[31:2], j}; + end + end + endtask + + task incorrect_opcode_test(); + /* + For every instruction type (every opcode for the simplicity sake) we try + an instruction with incorrect opcode. + */ + foreach(opcode_array[i]) begin + automatic logic [4:0] incorrect_opcode; + for(logic[1:0] j = 2'b00; j < 2'b11; j++) begin + randomize_with_given_opcode(opcode_array[i]); + @(posedge clk); + assert(std::randomize(incorrect_opcode) with {!(incorrect_opcode inside { + LOAD_OPCODE, + MISC_MEM_OPCODE, + OP_IMM_OPCODE, + AUIPC_OPCODE, + STORE_OPCODE, + OP_OPCODE, + LUI_OPCODE, + BRANCH_OPCODE, + JALR_OPCODE, + JAL_OPCODE, + SYSTEM_OPCODE + });}); + fetched_instr_i <= {instr.bits[31:7], incorrect_opcode, 2'b11}; + end + end + endtask + + task incorrect_func3_func7_test(); + /* + This test is opposite of valid_instrs_direct_test: we are looping through + every illegal {opcode, func3, func7} combination and applying it onto + generated instruction. + */ + foreach(invalid_codes[i]) begin + randomize_with_given_opcode(invalid_codes[i][14:10]); + @(posedge clk); + fetched_instr_i <= {invalid_codes[i][6:0], instr.bits[24:15], invalid_codes[i][9:7], instr.bits[11:7], invalid_codes[i][14:10], 2'b11}; + end + endtask + + task incorrect_hardcode_instrs(); + /* + In this test we try to broke fence, ecall, ebreak and mret instructions: + - for the fence instr we need to make func3 to be not equal zero; + - for ecall, ebreak and mret instructions we need to corrupt imm, rs1, rd + values. + */ + + // Broken fence instructions + for(logic [3:0] i = 3'd1; i <= 4'd7; i++) begin + randomize_with_given_opcode(MISC_MEM_OPCODE); + @(posedge clk); + fetched_instr_i <= {instr.bits[31:15], i, instr.bits[11:0]}; + end + + // Broken ecall, ebreak, mret instructions + for(logic [2:0] j = 3'd0; j <= 3'd3; j++) begin + @(posedge clk); + // broken imm field + fetched_instr_i <= {12'd2, instr.system_instrs[j][19:0]}; + @(posedge clk); + // broken rs1 field + fetched_instr_i <= {instr.system_instrs[j][31:20], 5'd1, instr.system_instrs[j][14:0]}; + @(posedge clk); + // broken rd field + fetched_instr_i <= {instr.system_instrs[j][31:12], 5'd1, instr.system_instrs[j][6:0]}; + end + endtask + + task illegal_instrs_random_test(); + /* + It's inefficiently to randomize all 32 bits of instructions since most + of them would be illegal by opcode or low 2 bits. + This test will construct instructions from valid parts but in random order + which will cause illegal instructions to be produced. + Additionally test will insert illegal parts with low chance. + */ + automatic logic [2:0] func3; + automatic logic [6:0] func7; + automatic logic [4:0] opcode; + automatic logic [4:0] rs1, rs2, rd; + automatic logic [1:0] low_bits; + automatic logic [9:0] mutation; + repeat(1e4) begin + assert(std::randomize(mutation)); + // we want to broke (invert constraint of) func3 if + // 9's bit is 1 while six lower bits are 0 + if(mutation[9] & !(|mutation[5:0])) begin + assert(std::randomize(func7 ) with {!(func7 inside {7'h0, 7'h20});}); + end + else begin + assert(std::randomize(func7 ) with { (func7 inside {7'h0, 7'h20});}); + end + if(mutation[8] & !(|mutation[5:0])) begin + assert(std::randomize(opcode ) with {!(opcode inside { + LOAD_OPCODE, + MISC_MEM_OPCODE, + OP_IMM_OPCODE, + AUIPC_OPCODE, + STORE_OPCODE, + OP_OPCODE, + LUI_OPCODE, + BRANCH_OPCODE, + JALR_OPCODE, + JAL_OPCODE, + SYSTEM_OPCODE + });}); + end + else begin + assert(std::randomize(opcode ) with { (opcode inside { + LOAD_OPCODE, + MISC_MEM_OPCODE, + OP_IMM_OPCODE, + AUIPC_OPCODE, + STORE_OPCODE, + OP_OPCODE, + LUI_OPCODE, + BRANCH_OPCODE, + JALR_OPCODE, + JAL_OPCODE, + SYSTEM_OPCODE + });}); + end + if(mutation[7] & !(|mutation[5:0])) begin + assert(std::randomize(low_bits ) with {!(low_bits == 2'b11);}); + end + else begin + assert(std::randomize(low_bits ) with { (low_bits == 2'b11);}); + end + assert(std::randomize(func3)); assert(std::randomize(rs1)); assert(std::randomize(rs2)); assert(std::randomize(rd)); + @(posedge clk); + fetched_instr_i <= {func7, rs2, rs1, func3, rd, opcode, low_bits}; + end + endtask + + bit test_paused_by_errs; + initial begin + clk = '0; + test_has_been_finished = '0; + err_count = '0; + test_paused_by_errs = '0; + end + + always #5 clk = ~clk; + always @(posedge clk) begin + if(test_has_been_finished) begin + $finish(); + end + end + + always @(posedge clk) begin + if((err_count >= 10) & !test_paused_by_errs) begin + test_paused_by_errs = '1; + $display("\nTest has been stopped after 10 errors"); + $stop(); + end + end + + logic [1:0] a_sel_o; + logic [2:0] b_sel_o; + logic [4:0] alu_op_o; + logic [2:0] csr_op_o; + logic csr_we_o; + logic mem_req_o; + logic mem_we_o; + logic [2:0] mem_size_o; + logic gpr_we_o; + logic [1:0] wb_sel_o; + logic illegal_instr_o; + logic branch_o; + logic jal_o; + logic jalr_o; + logic mret_o; + + logic [1:0] grm_a_sel_o; + logic [2:0] grm_b_sel_o; + logic [4:0] grm_alu_op_o; + logic [2:0] grm_csr_op_o; + logic grm_csr_we_o; + logic grm_mem_req_o; + logic grm_mem_we_o; + logic [2:0] grm_mem_size_o; + logic grm_gpr_we_o; + logic [1:0] grm_wb_sel_o; + logic grm_illegal_instr_o; + logic grm_branch_o; + logic grm_jal_o; + logic grm_jalr_o; + logic grm_mret_o; + + + decoder_riscv DUT(.*); + + decoder_riscv_ref GRM( + .fetched_instr_i (fetched_instr_i ), + .a_sel_o (grm_a_sel_o ), + .b_sel_o (grm_b_sel_o ), + .alu_op_o (grm_alu_op_o ), + .csr_op_o (grm_csr_op_o ), + .csr_we_o (grm_csr_we_o ), + .mem_req_o (grm_mem_req_o ), + .mem_we_o (grm_mem_we_o ), + .mem_size_o (grm_mem_size_o ), + .gpr_we_o (grm_gpr_we_o ), + .wb_sel_o (grm_wb_sel_o ), + .illegal_instr_o (grm_illegal_instr_o), + .branch_o (grm_branch_o ), + .jal_o (grm_jal_o ), + .jalr_o (grm_jalr_o ), + .mret_o (grm_mret_o ) ); - - decoder_riscv_ref grm(.fetched_instr_i (instr)); - wire [4:0] opcode; - assign opcode = instr[6:2]; + logic [4:0] opcode; + logic [2:0] func3; - always @(*) begin + logic a_sel_check ; + logic b_sel_check ; + logic alu_op_check ; + logic csr_op_check ; + logic csr_we_check ; + logic mem_req_check ; + logic mem_we_check ; + logic mem_size_check; + logic gpr_we_check ; + logic wb_sel_check ; + logic branch_check ; + logic jal_check ; + logic jalr_check ; + logic mret_check ; + + assign opcode = fetched_instr_i[6:2]; + assign func3 = fetched_instr_i[14:12]; + + assign a_sel_check = !(opcode inside {MISC_MEM_OPCODE, SYSTEM_OPCODE}); + assign b_sel_check = !(opcode inside {MISC_MEM_OPCODE, SYSTEM_OPCODE}); + assign alu_op_check = !(opcode inside {MISC_MEM_OPCODE, SYSTEM_OPCODE}); + assign csr_op_check = (opcode == SYSTEM_OPCODE) && (func3 != 3'd0); + assign csr_we_check = 1'b1; + assign mem_req_check = 1'b1; + assign mem_we_check = 1'b1; + assign mem_size_check = (opcode inside {LOAD_OPCODE, STORE_OPCODE}); + assign gpr_we_check = 1'b1; + assign wb_sel_check = !(opcode inside {MISC_MEM_OPCODE, BRANCH_OPCODE}) && (!(opcode == SYSTEM_OPCODE) | ((opcode == SYSTEM_OPCODE) & (func3 != 3'd0))); // (opcode == SYSTEM_OPCODE) -> (func3 != 3'd0) + assign branch_check = 1'b1; + assign jal_check = 1'b1; + assign jalr_check = 1'b1; + assign mret_check = 1'b1; + + string instr_str; + string raw_instr; + + illegal_instr_prop: assert property( + @(posedge clk) + (grm_illegal_instr_o === illegal_instr_o) + ) + else begin + $display("illegal_instr_o value is incorrect ( %b instead of %b), instruction: %s %s", illegal_instr_o, grm_illegal_instr_o , raw_instr, instr_str ); + err_count++; + end + + a_sel_prop : assert property ( + @(posedge clk) disable iff(grm_illegal_instr_o) + a_sel_check |-> (grm_a_sel_o === a_sel_o ) + ) + else begin + $display("a_sel_o value is incorrect ( %02b instead of %02b), instruction: %s %s", a_sel_o , grm_a_sel_o , raw_instr, instr_str ); + err_count++; + end + + b_sel_prop : assert property ( + @(posedge clk) disable iff(grm_illegal_instr_o) + b_sel_check |-> (grm_b_sel_o === b_sel_o ) + ) + else begin + $display("b_sel_o value is incorrect ( %03b instead of %03b), instruction: %s %s", b_sel_o , grm_b_sel_o , raw_instr, instr_str ); + err_count++; + end + + alu_op_prop : assert property ( + @(posedge clk) disable iff(grm_illegal_instr_o) + alu_op_check |-> (grm_alu_op_o === alu_op_o ) + ) + else begin + $display("alu_op_o value is incorrect (%05b instead of %05b), instruction: %s %s", alu_op_o , grm_alu_op_o, raw_instr, instr_str ); + err_count++; + end + + csr_op_prop : assert property ( + @(posedge clk) disable iff(grm_illegal_instr_o) + csr_op_check |-> (grm_csr_op_o === csr_op_o ) + ) + else begin + $display("csr_op_o value is incorrect ( %03b instead of %03b), instruction: %s %s", csr_op_o , grm_csr_op_o, raw_instr, instr_str ); + err_count++; + end + + csr_we_prop : assert property ( + @(posedge clk) + csr_we_check |-> (grm_csr_we_o === csr_we_o ) + ) + else begin + $display("csr_we_o value is incorrect ( %b instead of %b), instruction: %s %s", csr_we_o , grm_csr_we_o, raw_instr, instr_str ); + err_count++; + end + + mem_req_prop : assert property ( + @(posedge clk) + mem_req_check |-> (grm_mem_req_o === mem_req_o ) + ) + else begin + $display("mem_req_o value is incorrect ( %b instead of %b), instruction: %s %s", mem_req_o , grm_mem_req_o, raw_instr, instr_str ); + err_count++; + end + + mem_we_prop : assert property ( + @(posedge clk) + mem_we_check |-> (grm_mem_we_o === mem_we_o ) + ) + else begin + $display("mem_we_o value is incorrect ( %b instead of %b), instruction: %s %s", mem_we_o , grm_mem_we_o, raw_instr, instr_str ); + err_count++; + end + + mem_size_prop: assert property ( + @(posedge clk) disable iff(grm_illegal_instr_o) + mem_size_check |-> (grm_mem_size_o === mem_size_o) + ) + else begin + $display("mem_size_o value is incorrect ( %03b instead of %03b), instruction: %s %s", mem_size_o, grm_mem_size_o, raw_instr, instr_str); + err_count++; + end + + gpr_we_prop : assert property ( + @(posedge clk) + gpr_we_check |-> (grm_gpr_we_o === gpr_we_o ) + ) + else begin + $display("gpr_we_o value is incorrect ( %b instead of %b), instruction: %s %s", gpr_we_o , grm_gpr_we_o, raw_instr, instr_str ); + err_count++; + end + + wb_sel_prop : assert property ( + @(posedge clk) disable iff(grm_illegal_instr_o) + wb_sel_check |-> (grm_wb_sel_o === wb_sel_o ) + ) + else begin + $display("wb_sel_o value is incorrect ( %b instead of %b), instruction: %s %s", wb_sel_o , grm_wb_sel_o, raw_instr, instr_str ); + err_count++; + end + + branch_prop : assert property ( + @(posedge clk) + branch_check |-> (grm_branch_o === branch_o ) + ) + else begin + $display("branch_o value is incorrect ( %b instead of %b), instruction: %s %s", branch_o , grm_branch_o, raw_instr, instr_str ); + err_count++; + end + + jal_prop : assert property ( + @(posedge clk) + jal_check |-> (grm_jal_o === jal_o ) + ) + else begin + $display("jal_o value is incorrect ( %b instead of %b), instruction: %s %s", jal_o , grm_jal_o , raw_instr, instr_str ); + err_count++; + end + + jalr_prop : assert property ( + @(posedge clk) + jalr_check |-> (grm_jalr_o === jalr_o ) + ) + else begin + $display("jalr_o value is incorrect ( %b instead of %b), instruction: %s %s", jalr_o , grm_jalr_o , raw_instr, instr_str ); + err_count++; + end + + mret_prop : assert property ( + @(posedge clk) + mret_check |-> (grm_mret_o === mret_o ) + ) + else begin + $display("mret_o value is incorrect ( %b instead of %b), instruction: %s %s", mret_o , grm_mret_o , raw_instr, instr_str ); + err_count++; + end + + always_comb begin case (opcode) LUI_OPCODE, AUIPC_OPCODE, JAL_OPCODE: - instr_type = $sformatf("%020b %05b %07b ", instr[31:12], instr[11:7], instr[6:0]); + raw_instr = $sformatf("%020b %05b %07b " , fetched_instr_i[31:12], fetched_instr_i[11:7], fetched_instr_i[6:0]); JALR_OPCODE, LOAD_OPCODE, OP_IMM_OPCODE, SYSTEM_OPCODE: - instr_type = $sformatf("%012b %05b %03b %05b %07b ", instr[31:20], instr[19:15], instr[14:12], instr[11:7], instr[6:0]); + raw_instr = $sformatf("%012b %05b %03b %05b %07b " , fetched_instr_i[31:20], fetched_instr_i[19:15], fetched_instr_i[14:12], fetched_instr_i[11:7], fetched_instr_i[6:0]); BRANCH_OPCODE, STORE_OPCODE, OP_OPCODE: - instr_type = $sformatf("%07b %05b %05b %03b %05b %07b", instr[31:25], instr[24:20], instr[19:15], instr[14:12], instr[11:7], instr[6:0]); - MISC_MEM_OPCODE: - instr_type = $sformatf("%017b %03b %05b %07b ", instr[31:15], instr[14:12], instr[11:7], instr[6:0]); - default: - instr_type = $sformatf("%032b ", instr); + raw_instr = $sformatf("%07b %05b %05b %03b %05b %07b", fetched_instr_i[31:25], fetched_instr_i[24:20], fetched_instr_i[19:15], fetched_instr_i[14:12], fetched_instr_i[11:7], fetched_instr_i[6:0]); + MISC_MEM_OPCODE: + raw_instr = $sformatf("%017b %03b %05b %07b " , fetched_instr_i[31:15], fetched_instr_i[14:12], fetched_instr_i[11:7], fetched_instr_i[6:0]); + default: + raw_instr = $sformatf("%032b " , fetched_instr_i); endcase end - always @(*) begin - a_sel_miss = 'b0; - b_sel_miss = 'b0; - alu_op_miss = 'b0; - csr_op_miss = 'b0; - csr_we_miss = 'b0; - mem_req_miss = 'b0; - mem_we_miss = 'b0; - mem_size_miss = 'b0; - gpr_we_miss = 'b0; - wb_sel_miss = 'b0; - illegal_miss = 'b0; - branch_miss = 'b0; - jal_miss = 'b0; - jalr_miss = 'b0; - mret_miss = 'b0; - illegal_miss = grm.illegal_instr_o !== illegal_instr; - case (opcode) - LOAD_OPCODE, STORE_OPCODE: - begin - a_sel_miss = (grm.a_sel_o !== a_sel) & !illegal_instr; - b_sel_miss = (grm.b_sel_o !== b_sel) & !illegal_instr; - alu_op_miss = (grm.alu_op_o !== alu_op) & !illegal_instr; - csr_we_miss = (grm.csr_we_o !== csr_we); - mem_req_miss = grm.mem_req_o !== mem_req; - mem_we_miss = grm.mem_we_o !== mem_we; - mem_size_miss = (grm.mem_size_o !== mem_size) & !illegal_instr; - gpr_we_miss = grm.gpr_we_o !== gpr_we; - wb_sel_miss = (grm.wb_sel_o !== wb_sel) & !illegal_instr; - branch_miss = grm.branch_o !== branch; - jal_miss = grm.jal_o !== jal; - jalr_miss = grm.jalr_o !== jalr; - mret_miss = grm.mret_o !== mret; - end - - JAL_OPCODE, JALR_OPCODE, - AUIPC_OPCODE, - OP_IMM_OPCODE, OP_OPCODE: - begin - a_sel_miss = (grm.a_sel_o !== a_sel) & !illegal_instr; - b_sel_miss = (grm.b_sel_o !== b_sel) & !illegal_instr; - alu_op_miss = (grm.alu_op_o !== alu_op) & !illegal_instr; - csr_we_miss = (grm.csr_we_o !== csr_we); - mem_req_miss = grm.mem_req_o !== mem_req; - mem_we_miss = grm.mem_we_o !== mem_we; - //mem_size_miss = (grm.mem_size_o !== mem_size) & !illegal_instr; - gpr_we_miss = grm.gpr_we_o !== gpr_we; - wb_sel_miss = (grm.wb_sel_o !== wb_sel) & !illegal_instr; - branch_miss = grm.branch_o !== branch; - jal_miss = grm.jal_o !== jal; - jalr_miss = grm.jalr_o !== jalr; - mret_miss = grm.mret_o !== mret; - end - - BRANCH_OPCODE: - begin - a_sel_miss = (grm.a_sel_o !== a_sel) & !illegal_instr; - b_sel_miss = (grm.b_sel_o !== b_sel) & !illegal_instr; - alu_op_miss = (grm.alu_op_o !== alu_op) & !illegal_instr; - csr_we_miss = (grm.csr_we_o !== csr_we); - mem_req_miss = grm.mem_req_o !== mem_req; - mem_we_miss = grm.mem_we_o !== mem_we; - //mem_size_miss = (grm.mem_size_o !== mem_size) & !illegal_instr; - gpr_we_miss = grm.gpr_we_o !== gpr_we; - //wb_sel_miss = (grm.wb_sel_o !== wb_sel) & !illegal_instr; - branch_miss = grm.branch_o !== branch; - jal_miss = grm.jal_o !== jal; - jalr_miss = grm.jalr_o !== jalr; - mret_miss = grm.mret_o !== mret; - end - - LUI_OPCODE: begin - a_sel_miss = (grm.a_sel_o !== a_sel) & !illegal_instr; - b_sel_miss = (grm.b_sel_o !== b_sel) & !illegal_instr; - alu_op_miss = ((alu_op !== ALU_ADD)&(alu_op !== ALU_XOR)&(alu_op !== ALU_OR)) & !illegal_instr; - csr_we_miss = (grm.csr_we_o !== csr_we); - mem_req_miss = grm.mem_req_o !== mem_req; - mem_we_miss = grm.mem_we_o !== mem_we; - //mem_size_miss = (grm.mem_size_o !== mem_size) & !illegal_instr; - gpr_we_miss = grm.gpr_we_o !== gpr_we; - wb_sel_miss = (grm.wb_sel_o !== wb_sel) & !illegal_instr; - branch_miss = grm.branch_o !== branch; - jal_miss = grm.jal_o !== jal; - jalr_miss = grm.jalr_o !== jalr; - mret_miss = grm.mret_o !== mret; - end - - SYSTEM_OPCODE: begin - //a_sel_miss = (grm.a_sel_o !== a_sel) & !illegal_instr; - //b_sel_miss = (grm.b_sel_o !== b_sel) & !illegal_instr; - //alu_op_miss = ((alu_op !== ALU_ADD)&(alu_op !== ALU_XOR)&(alu_op !== ALU_OR)) & !illegal_instr; - csr_we_miss = (grm.csr_we_o !== csr_we); - mem_req_miss = grm.mem_req_o !== mem_req; - mem_we_miss = grm.mem_we_o !== mem_we; - //mem_size_miss = (grm.mem_size_o !== mem_size) & !illegal_instr; - gpr_we_miss = grm.gpr_we_o !== gpr_we; - wb_sel_miss = (grm.wb_sel_o !== wb_sel) & !illegal_instr & !mret; - branch_miss = grm.branch_o !== branch; - jal_miss = grm.jal_o !== jal; - jalr_miss = grm.jalr_o !== jalr; - mret_miss = grm.mret_o !== mret; - end - default: //MISC_MEM_OPCODE and other - begin - //a_sel_miss = grm.a_sel_o !== a_sel; - //b_sel_miss = grm.b_sel_o !== b_sel; - //alu_op_miss = grm.alu_op_o !== alu_op; - csr_we_miss = (grm.csr_we_o !== csr_we); - mem_req_miss = grm.mem_req_o !== mem_req; - mem_we_miss = grm.mem_we_o !== mem_we; - //mem_size_miss = grm.mem_size_o !== mem_size; - gpr_we_miss = grm.gpr_we_o !== gpr_we; - //wb_sel_miss = grm.wb_sel_o !== wb_sel; - branch_miss = grm.branch_o !== branch; - jal_miss = grm.jal_o !== jal; - jalr_miss = grm.jalr_o !== jalr; - mret_miss = grm.mret_o !== mret; - end - endcase - end - - integer X; - reg [$clog2(cycle+1)-1:0] V; - integer error; - - initial begin - $timeformat(-9, 2, " ns", 3); - error = 0; - end - - initial begin - $display( "\nStart test: \n\n==========================\nCLICK THE BUTTON 'Run All'\n==========================\n"); $stop(); - - for (V=0; V !(func3 inside {3'h3, 3'h6, 3'h7});} + + constraint misc_mem_opcode { (opcode == MISC_MEM_OPCODE) -> (func3 == 3'b000);} + + constraint op_imm_opcode1 {((opcode == OP_IMM_OPCODE ) && (func3 == 3'h1)) -> (func7 == 7'h00);} + constraint op_imm_opcode2 {((opcode == OP_IMM_OPCODE ) && (func3 == 3'h5)) -> (func7 inside {7'h00, 7'h20});} + + constraint store_opcode { (opcode == STORE_OPCODE ) -> (func3 inside {3'h0, 3'h1, 3'h2});} + + constraint op_opcode1 {((opcode == OP_OPCODE ) && (func3 inside {3'b000, 3'b101})) -> (func7 inside {7'h00, 7'h20});} + constraint op_opcode2 {((opcode == OP_OPCODE ) && !(func3 inside {3'b000, 3'b101})) -> (func7 == 7'h00);} + + constraint branch_opcode { (opcode == BRANCH_OPCODE ) -> !(func3 inside {3'h2, 3'h3});} + + constraint jalr_opcode { (opcode == JALR_OPCODE ) -> (func3 == 3'h0);} + + constraint system_opcode { (opcode == SYSTEM_OPCODE ) -> !(func3 == 3'h4);} + + function void post_randomize(); + case(opcode) + LOAD_OPCODE, MISC_MEM_OPCODE, JALR_OPCODE: begin + bits = {imm[11:0], rs1, func3, rd, opcode, 2'b11}; + end + OP_IMM_OPCODE: begin + if(func3 inside {3'h1, 3'h5}) begin + bits = {func7, shamt, rs1, func3, rd, opcode, 2'b11}; + end + else begin + bits = {imm[11:0], rs1, func3, rd, opcode, 2'b11}; + end + end + AUIPC_OPCODE, LUI_OPCODE: begin + bits = {imm, opcode, 2'b11}; + end + STORE_OPCODE: begin + bits = {imm[11:5], rs2, rs1, func3, imm[4:0], opcode, 2'b11}; + end + OP_OPCODE: begin + bits = {func7, rs2, rs1, func3, rd, opcode, 2'b11}; + end + BRANCH_OPCODE: begin + bits = {imm[12], imm[10:5], rs2, rs1, func3, imm[4:1], imm[11], opcode, 2'b11}; + end + JAL_OPCODE: begin + bits = {imm[20], imm[10:1], imm[11], imm[19:12], rd, opcode, 2'b11}; + end + SYSTEM_OPCODE: begin + if(func3 == 3'h0) begin + bits = system_instrs[$urandom_range(3)]; + end + else begin + bits = {imm[11:0], rs1, func3, rd, opcode, 2'b11}; + end + end + default: begin + $fatal(1, "Missing opcode %0h in post_randomize", opcode); + end + endcase + endfunction + + endclass + endmodule -////////////////////////////////////////////////////////////////////////////////// -// Company: MIET -// Engineer: Alexey Kozin -// -// Create Date: 10/08/2023 07:39:15 AM -// Design Name: -// Module Name: decoder_riscv -// Project Name: RISCV_practicum -// Target Devices: Nexys A7-100T -// Tool Versions: -// Description: main decoder for risc-v processor -// -// Dependencies: -// -// Revision: -// Revision 0.01 - File Created -// Additional Comments: -// -////////////////////////////////////////////////////////////////////////////////// +/* ----------------------------------------------------------------------------- +* Project Name : Architectures of Processor Systems (APS) lab work +* Organization : National Research University of Electronic Technology (MIET) +* Department : Institute of Microdevices and Control Systems +* Author(s) : Alexey Kozin +* Email(s) : @edu.miet.ru +See https://github.com/MPSU/APS/blob/master/LICENSE file for licensing details. +* ------------------------------------------------------------------------------ +*/ module gpr_we_table (gis_ew_rpg, edocpo_6, edocpo_5, edocpo_4, edocpo_3, edocpo_2); output logic gis_ew_rpg; input edocpo_6, edocpo_5, edocpo_4, edocpo_3, edocpo_2; @@ -536,8 +897,6 @@ module csr_we_table (gis_ew_rsc, edocpo_6, edocpo_5, edocpo_4, edocpo_3, edocpo_ endcase endmodule - - module mem_req_table (gis_qer_mem, edocpo_6, edocpo_5, edocpo_4, edocpo_3, edocpo_2); output logic gis_qer_mem; input edocpo_6, edocpo_5, edocpo_4, edocpo_3, edocpo_2;