From ac1fb44a4a3f08597959978e33e8d975ee359d1b Mon Sep 17 00:00:00 2001 From: taoliug <34581368+taoliug@users.noreply.github.com> Date: Sun, 24 Nov 2019 00:23:22 -0800 Subject: [PATCH] Add new experimental instruction class (#323) --- run.py | 5 +- src/isa/riscv_amo_instr.sv | 60 ++++ src/isa/riscv_compressed_instr.sv | 337 +++++++++++++++++ src/isa/riscv_floating_point_instr.sv | 70 ++++ src/isa/riscv_instr.sv | 499 ++++++++++++++++++++++++++ src/isa/riscv_vector_instr.sv | 25 ++ src/isa/rv128c_instr.sv | 7 + src/isa/rv32a_instr.sv | 11 + src/isa/rv32c_instr.sv | 27 ++ src/isa/rv32d_instr.sv | 26 ++ src/isa/rv32dc_instr.sv | 4 + src/isa/rv32f_instr.sv | 26 ++ src/isa/rv32fc_instr.sv | 4 + src/isa/rv32i_instr.sv | 64 ++++ src/isa/rv32m_instr.sv | 9 + src/isa/rv64a_instr.sv | 11 + src/isa/rv64c_instr.sv | 7 + src/isa/rv64d_instr.sv | 6 + src/isa/rv64f_instr.sv | 4 + src/isa/rv64i_instr.sv | 14 + src/isa/rv64m_instr.sv | 5 + src/riscv_asm_program_gen.sv | 4 +- src/riscv_defines.svh | 44 +++ src/riscv_instr_pkg.sv | 29 ++ target/exp/riscvOVPsim.ic | 18 + target/exp/riscv_core_setting.sv | 144 ++++++++ target/exp/testlist.yaml | 40 +++ test/riscv_instr_test.sv | 58 +++ test/riscv_instr_test_pkg.sv | 3 + yaml/base_testlist.yaml | 4 - 30 files changed, 1559 insertions(+), 6 deletions(-) create mode 100644 src/isa/riscv_amo_instr.sv create mode 100644 src/isa/riscv_compressed_instr.sv create mode 100644 src/isa/riscv_floating_point_instr.sv create mode 100644 src/isa/riscv_instr.sv create mode 100644 src/isa/riscv_vector_instr.sv create mode 100644 src/isa/rv128c_instr.sv create mode 100644 src/isa/rv32a_instr.sv create mode 100644 src/isa/rv32c_instr.sv create mode 100644 src/isa/rv32d_instr.sv create mode 100644 src/isa/rv32dc_instr.sv create mode 100644 src/isa/rv32f_instr.sv create mode 100644 src/isa/rv32fc_instr.sv create mode 100644 src/isa/rv32i_instr.sv create mode 100644 src/isa/rv32m_instr.sv create mode 100644 src/isa/rv64a_instr.sv create mode 100644 src/isa/rv64c_instr.sv create mode 100644 src/isa/rv64d_instr.sv create mode 100644 src/isa/rv64f_instr.sv create mode 100644 src/isa/rv64i_instr.sv create mode 100644 src/isa/rv64m_instr.sv create mode 100644 target/exp/riscvOVPsim.ic create mode 100644 target/exp/riscv_core_setting.sv create mode 100644 target/exp/testlist.yaml create mode 100644 test/riscv_instr_test.sv diff --git a/run.py b/run.py index a44c00ff..134f8adf 100644 --- a/run.py +++ b/run.py @@ -553,8 +553,11 @@ def main(): elif args.target == "ml": args.mabi = "lp64" args.isa = "rv64imc" + elif args.target == "exp": + args.mabi = "lp64" + args.isa = "rv64gc" else: - print ("Unsupported pre-defined target: %0s" % args.target) + sys.exit("Unsupported pre-defined target: %0s" % args.target) else: if re.match(".*gcc_compile.*", args.steps) or re.match(".*iss_sim.*", args.steps): if (not args.mabi) or (not args.isa): diff --git a/src/isa/riscv_amo_instr.sv b/src/isa/riscv_amo_instr.sv new file mode 100644 index 00000000..29458fa6 --- /dev/null +++ b/src/isa/riscv_amo_instr.sv @@ -0,0 +1,60 @@ +class riscv_amo_instr extends riscv_instr; + + rand bit aq; + rand bit rl; + + constraint aq_rl_c { + aq && rl == 0; + } + + `uvm_object_utils(riscv_amo_instr) + + function new(string name = ""); + super.new(name); + endfunction + + virtual function string get_instr_name(); + get_instr_name = instr_name.name(); + if (group == RV32A) begin + get_instr_name = {get_instr_name.substr(0, get_instr_name.len() - 3), ".w"}; + get_instr_name = aq ? {get_instr_name, ".aq"} : + rl ? {get_instr_name, ".rl"} : get_instr_name; + end else if (group == RV64A) begin + get_instr_name = {get_instr_name.substr(0, get_instr_name.len() - 3), ".d"}; + get_instr_name = aq ? {get_instr_name, ".aq"} : + rl ? {get_instr_name, ".rl"} : get_instr_name; + end else begin + `uvm_fatal(`gfn, $sformatf("Unexpected amo instr group: %0s / %0s", + group.name(), instr_name.name())) + end + return get_instr_name; + endfunction : get_instr_name + + // Convert the instruction to assembly code + virtual function string convert2asm(string prefix = ""); + string asm_str; + asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN); + if (group inside {RV32A, RV64A}) begin + if (instr_name inside {LR_W, LR_D}) begin + asm_str = $sformatf("%0s %0s, (%0s)", asm_str, rd.name(), rs1.name()); + end else begin + asm_str = $sformatf("%0s %0s, %0s, (%0s)", asm_str, rd.name(), rs2.name(), rs1.name()); + end + end else begin + `uvm_fatal(`gfn, $sformatf("Unexpected amo instr group: %0s / %0s", + group.name(), instr_name.name())) + end + if(comment != "") + asm_str = {asm_str, " #",comment}; + return asm_str.tolower(); + endfunction : convert2asm + + virtual function void do_copy(uvm_object rhs); + riscv_amo_instr rhs_; + super.copy(rhs); + assert($cast(rhs_, rhs)); + this.aq = rhs_.aq; + this.rl = rhs_.rl; + endfunction : do_copy + +endclass diff --git a/src/isa/riscv_compressed_instr.sv b/src/isa/riscv_compressed_instr.sv new file mode 100644 index 00000000..3687e55c --- /dev/null +++ b/src/isa/riscv_compressed_instr.sv @@ -0,0 +1,337 @@ +class riscv_compressed_instr extends riscv_instr; + + int imm_align; + + constraint rvc_csr_c { + // Registers specified by the three-bit rs1’, rs2’, and rd’ + if(format inside {CIW_FORMAT, CL_FORMAT, CS_FORMAT, CB_FORMAT, CA_FORMAT}) { + rs1 inside {[S0:A5]}; + rs2 inside {[S0:A5]}; + rd inside {[S0:A5]}; + } + // C_ADDI16SP is only valid when rd == SP + if(instr_name == C_ADDI16SP) { + rd == SP; + rs1 == SP; + } + + if(instr_name inside {C_JR, C_JALR}) { + rs2 == ZERO; + rs1 != ZERO; + } + } + + // Non-zero immediate value + constraint imm_val_c { + if(imm_type inside {NZIMM, NZUIMM}) { + imm[5:0] != 0; + if (instr_name == C_LUI) { + // TODO(taliu) Check why bit 6 cannot be zero + imm[31:5] == 0; + } + if (instr_name inside {C_SRAI, C_SRLI, SLLI}) { + imm[31:5] == 0; + } + } + } + + // C_JAL is RV32C only instruction + constraint jal_c { + if (XLEN != 32) { + instr_name != C_JAL; + } + } + + // Avoid generating HINT or illegal instruction by default as it's not supported by the compiler + constraint no_hint_illegal_instr_c { + if (instr_name inside {C_ADDI, C_ADDIW, C_LI, C_LUI, C_SLLI, C_SLLI64, + C_LQSP, C_LDSP, C_MV, C_ADD, C_LWSP}) { + rd != ZERO; + } + if (instr_name == C_JR) { + rs1 != ZERO; + } + if (instr_name inside {C_ADD, C_MV}) { + rs2 != ZERO; + } + (instr_name == C_LUI) -> (rd != SP); + } + + `uvm_object_utils(riscv_compressed_instr) + + function new(string name = ""); + super.new(name); + rs1 = S0; + rs2 = S0; + rd = S0; + endfunction : new + + virtual function void set_imm_len(); + if (format inside {CI_FORMAT, CSS_FORMAT}) begin + imm_len = 6; + end else if (format inside {CL_FORMAT, CS_FORMAT}) begin + imm_len = 5; + end else if (format inside {CJ_FORMAT}) begin + imm_len = 11; + end else if (format inside {CB_FORMAT}) begin + if (instr_name == C_ANDI) begin + imm_len = 6; + end else begin + imm_len = 7; + end + end else if (format inside {CB_FORMAT, CIW_FORMAT}) begin + imm_len = 8; + end + if (instr_name inside {C_SQ, C_LQ, C_LQSP, C_SQSP, C_ADDI16SP}) begin + imm_align = 4; + end else if (instr_name inside {C_SD, C_LD, C_LDSP, C_SDSP}) begin + imm_align = 3; + end else if (instr_name inside {C_SW, C_LW, C_LWSP, C_SWSP, C_ADDI4SPN}) begin + imm_align = 2; + end else if (instr_name inside {C_LUI}) begin + imm_align = 12; + end else if (instr_name inside {C_J, C_JAL, C_BNEZ, C_BEQZ}) begin + imm_align = 1; + end + endfunction : set_imm_len + + virtual function void do_copy(uvm_object rhs); + riscv_compressed_instr rhs_; + super.copy(rhs); + assert($cast(rhs_, rhs)); + this.imm_align = rhs_.imm_align; + endfunction : do_copy + + virtual function void extend_imm(); + if (instr_name != C_LUI) begin + super.extend_imm(); + imm = imm << imm_align; + end + comment = $sformatf("imm:0x%0x, imm_mask:0x%0x, align:%0d", imm, imm_mask, imm_align); + endfunction : extend_imm + + // Convert the instruction to assembly code + virtual function string convert2asm(string prefix = ""); + string asm_str; + asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN); + if (category != SYSTEM) begin + case(format) + CI_FORMAT, CIW_FORMAT: + if (instr_name == C_NOP) + asm_str = "c.nop"; + else if (instr_name == C_ADDI16SP) + asm_str = $sformatf("%0ssp, %0s", asm_str, get_imm()); + else if (instr_name inside {C_LDSP, C_LWSP, C_LQSP}) + asm_str = $sformatf("%0s%0s, %0s(sp)", asm_str, rd.name(), get_imm()); + else + asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), get_imm()); + CL_FORMAT: + asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rd.name(), get_imm(), rs1.name()); + CS_FORMAT: + if (category == STORE) + asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rs2.name(), get_imm(), rs1.name()); + else + asm_str = $sformatf("%0s%0s, %0s", asm_str, rs1.name(), rs2.name()); + CA_FORMAT: + asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), rs2.name()); + CB_FORMAT: + asm_str = $sformatf("%0s%0s, %0s", asm_str, rs1.name(), get_imm()); + CSS_FORMAT: + if (category == STORE) + asm_str = $sformatf("%0s%0s, %0s(sp)", asm_str, rs2.name(), get_imm()); + else + asm_str = $sformatf("%0s%0s, %0s", asm_str, rs2.name(), get_imm()); + CR_FORMAT: + if (instr_name inside {C_JR, C_JALR}) begin + asm_str = $sformatf("%0s%0s", asm_str, rs1.name()); + end else begin + asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), rs2.name()); + end + CJ_FORMAT: + asm_str = $sformatf("%0s%0s", asm_str, get_imm()); + endcase + end else begin + // For EBREAK,C.EBREAK, making sure pc+4 is a valid instruction boundary + // This is needed to resume execution from epc+4 after ebreak handling + if (instr_name == C_EBREAK) begin + asm_str = "c.ebreak;c.nop;"; + end + end + if (comment != "") + asm_str = {asm_str, " #",comment}; + return asm_str.tolower(); + endfunction : convert2asm + + // Convert the instruction to assembly code + virtual function string convert2bin(string prefix = ""); + string binary; + case (instr_name) inside + C_ADDI4SPN: + binary = $sformatf("%4h", {get_func3(), imm[5:4], imm[9:6], + imm[2], imm[3], get_c_gpr(rd), get_c_opcode()}); + C_LQ: + binary = $sformatf("%4h", {get_func3(), imm[5:4], imm[8], + get_c_gpr(rs1), imm[7:6], get_c_gpr(rd), get_c_opcode()}); + C_FLD, C_LD: + binary = $sformatf("%4h", {get_func3(), imm[5:3], get_c_gpr(rs1), + imm[7:6], get_c_gpr(rd), get_c_opcode()}); + C_LW, C_FLW: + binary = $sformatf("%4h", {get_func3(), imm[5:3], get_c_gpr(rs1), + imm[2], imm[6], get_c_gpr(rd), get_c_opcode()}); + C_SQ: + binary = $sformatf("%4h", {get_func3(), imm[5:4], imm[8], + get_c_gpr(rs1), imm[7:6], get_c_gpr(rs2), get_c_opcode()}); + C_FSD, C_SD: + binary = $sformatf("%4h", {get_func3(), imm[5:3], get_c_gpr(rs1), + imm[7:6], get_c_gpr(rs2), get_c_opcode()}); + C_SW, C_FSW: + binary = $sformatf("%4h", {get_func3(), imm[5:3], get_c_gpr(rs1), + imm[2], imm[6], get_c_gpr(rs2), get_c_opcode()}); + C_NOP, C_ADDI, C_LI, C_ADDIW: + binary = $sformatf("%4h", {get_func3(), imm[5], rd, imm[4:0], get_c_opcode()}); + C_JAL, C_J: + binary = $sformatf("%4h", {get_func3(), imm[11], imm[4], imm[9:8], + imm[10], imm[6], imm[7], imm[3:1], imm[5], get_c_opcode()}); + C_ADDI16SP: + binary = $sformatf("%4h", {get_func3(), imm[9], 5'b10, + imm[4], imm[6], imm[8:7], imm[5], get_c_opcode()}); + C_LUI: + binary = $sformatf("%4h", {get_func3(), imm[5], rd, imm[4:0], get_c_opcode()}); + C_SRLI: + binary = $sformatf("%4h", {get_func3(), imm[5], + 2'b0, get_c_gpr(rd), imm[4:0], get_c_opcode()}); + C_SRLI64: + binary = $sformatf("%4h", {get_func3(), 3'b0, get_c_gpr(rd), 5'b0, get_c_opcode()}); + C_SRAI: + binary = $sformatf("%4h", {get_func3(), imm[5], + 2'b01, get_c_gpr(rd), imm[4:0], get_c_opcode()}); + C_SRAI64: + binary = $sformatf("%4h", {get_func3(), 3'b001, + get_c_gpr(rd), 5'b0, get_c_opcode()}); + C_ANDI: + binary = $sformatf("%4h", {get_func3(), imm[5], + 2'b10, get_c_gpr(rd), imm[4:0], get_c_opcode()}); + C_SUB: + binary = $sformatf("%4h", {get_func3(), 3'b011, get_c_gpr(rd), + 2'b00, get_c_gpr(rs2), get_c_opcode()}); + C_XOR: + binary = $sformatf("%4h", {get_func3(), 3'b011, get_c_gpr(rd), + 2'b01, get_c_gpr(rs2), get_c_opcode()}); + C_OR: + binary = $sformatf("%4h", {get_func3(), 3'b011, get_c_gpr(rd), + 2'b10, get_c_gpr(rs2), get_c_opcode()}); + C_AND: + binary = $sformatf("%4h", {get_func3(), 3'b011, get_c_gpr(rd), + 2'b11, get_c_gpr(rs2), get_c_opcode()}); + C_SUBW: + binary = $sformatf("%4h", {get_func3(), 3'b111, get_c_gpr(rd), + 2'b00, get_c_gpr(rs2), get_c_opcode()}); + C_ADDW: + binary = $sformatf("%4h", {get_func3(), 3'b111, get_c_gpr(rd), + 2'b01, get_c_gpr(rs2), get_c_opcode()}); + C_BEQZ, C_BNEZ: + binary = $sformatf("%4h", {get_func3(), imm[8], imm[4:3], + get_c_gpr(rs1), imm[7:6], imm[2:1], imm[5], get_c_opcode()}); + C_SLLI: + binary = $sformatf("%4h", {get_func3(), imm[5], rd, imm[4:0], get_c_opcode()}); + C_SLLI64: + binary = $sformatf("%4h", {get_func3(), 1'b0, rd, 5'b0, get_c_opcode()}); + C_FLDSP, C_LDSP: + binary = $sformatf("%4h", {get_func3(), imm[5], rd, imm[4:3], imm[8:6], get_c_opcode()}); + C_LQSP: + binary = $sformatf("%4h", {get_func3(), imm[5], rd, imm[4], imm[9:6], get_c_opcode()}); + C_LWSP, C_FLWSP: + binary = $sformatf("%4h", {get_func3(), imm[5], rd, imm[4:2], imm[7:6], get_c_opcode()}); + C_JR: + binary = $sformatf("%4h", {get_func3(), 1'b0, rs1, 5'b0, get_c_opcode()}); + C_MV: + binary = $sformatf("%4h", {get_func3(), 1'b0, rd, rs2, get_c_opcode()}); + C_EBREAK: + binary = $sformatf("%4h", {get_func3(), 1'b1, 10'b0, get_c_opcode()}); + C_JALR: + binary = $sformatf("%4h", {get_func3(), 1'b1, 10'b0, get_c_opcode()}); + C_ADD: + binary = $sformatf("%4h", {get_func3(), 1'b1, rd, rs2, get_c_opcode()}); + C_FSDSP, C_SDSP: + binary = $sformatf("%4h", {get_func3(), 1'b0, imm[5:3], imm[8:6], rs2, get_c_opcode()}); + C_SQSP: + binary = $sformatf("%4h", {get_func3(), 1'b0, imm[5:4], imm[9:6], rs2, get_c_opcode()}); + C_SWSP, C_FSWSP: + binary = $sformatf("%4h", {get_func3(), 1'b0, imm[5:2], imm[7:6], rs2, get_c_opcode()}); + default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name())) + endcase + return {prefix, binary}; + endfunction : convert2bin + + // Get opcode for compressed instruction + virtual function bit [1:0] get_c_opcode(); + case (instr_name) inside + C_ADDI4SPN, C_FLD, C_FLD, C_LQ, C_LW, C_FLW, + C_LD, C_FSD, C_SQ, C_SW, C_FSW, C_SD : get_c_opcode = 2'b00; + C_NOP, C_ADDI, C_JAL, C_ADDIW, C_LI, C_ADDI16SP, + C_LUI, C_SRLI, C_SRLI64, C_SRAI, C_SRAI64, + C_ANDI, C_SUB, C_XOR, C_OR, C_AND, C_SUBW, + C_ADDW, C_J, C_BEQZ, C_BNEZ : get_c_opcode = 2'b01; + C_SLLI, C_SLLI64, C_FLDSP, C_LQSP, C_LWSP, + C_FLWSP, C_LDSP, C_JR, C_MV, C_EBREAK, C_JALR, + C_ADD, C_FSDSP, C_SQSP, C_SWSP, C_FSWSP, C_SDSP : get_c_opcode = 2'b10; + default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name())) + endcase + endfunction : get_c_opcode + + virtual function bit [2:0] get_func3(); + case (instr_name) inside + C_ADDI4SPN : get_func3 = 3'b000; + C_FLD : get_func3 = 3'b001; + C_LQ : get_func3 = 3'b001; + C_LW : get_func3 = 3'b010; + C_FLW : get_func3 = 3'b011; + C_LD : get_func3 = 3'b011; + C_FSD : get_func3 = 3'b101; + C_SQ : get_func3 = 3'b101; + C_SW : get_func3 = 3'b110; + C_FSW : get_func3 = 3'b111; + C_SD : get_func3 = 3'b111; + C_NOP : get_func3 = 3'b000; + C_ADDI : get_func3 = 3'b000; + C_JAL : get_func3 = 3'b001; + C_ADDIW : get_func3 = 3'b001; + C_LI : get_func3 = 3'b010; + C_ADDI16SP : get_func3 = 3'b011; + C_LUI : get_func3 = 3'b011; + C_SRLI : get_func3 = 3'b100; + C_SRLI64 : get_func3 = 3'b100; + C_SRAI : get_func3 = 3'b100; + C_SRAI64 : get_func3 = 3'b100; + C_ANDI : get_func3 = 3'b100; + C_SUB : get_func3 = 3'b100; + C_XOR : get_func3 = 3'b100; + C_OR : get_func3 = 3'b100; + C_AND : get_func3 = 3'b100; + C_SUBW : get_func3 = 3'b100; + C_ADDW : get_func3 = 3'b100; + C_J : get_func3 = 3'b101; + C_BEQZ : get_func3 = 3'b110; + C_BNEZ : get_func3 = 3'b111; + C_SLLI : get_func3 = 3'b000; + C_SLLI64 : get_func3 = 3'b000; + C_FLDSP : get_func3 = 3'b001; + C_LQSP : get_func3 = 3'b001; + C_LWSP : get_func3 = 3'b010; + C_FLWSP : get_func3 = 3'b011; + C_LDSP : get_func3 = 3'b011; + C_JR : get_func3 = 3'b100; + C_MV : get_func3 = 3'b100; + C_EBREAK : get_func3 = 3'b100; + C_JALR : get_func3 = 3'b100; + C_ADD : get_func3 = 3'b100; + C_FSDSP : get_func3 = 3'b101; + C_SQSP : get_func3 = 3'b101; + C_SWSP : get_func3 = 3'b110; + C_FSWSP : get_func3 = 3'b111; + C_SDSP : get_func3 = 3'b111; + default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name())) + endcase + endfunction : get_func3 + +endclass : riscv_compressed_instr diff --git a/src/isa/riscv_floating_point_instr.sv b/src/isa/riscv_floating_point_instr.sv new file mode 100644 index 00000000..850c1787 --- /dev/null +++ b/src/isa/riscv_floating_point_instr.sv @@ -0,0 +1,70 @@ +class riscv_floating_point_instr extends riscv_instr; + + rand riscv_fpr_t fs1; + rand riscv_fpr_t fs2; + rand riscv_fpr_t fs3; + rand riscv_fpr_t fd; + + `uvm_object_utils(riscv_floating_point_instr) + + function new(string name = ""); + super.new(name); + rs2.rand_mode(0); + endfunction + + // Convert the instruction to assembly code + virtual function string convert2asm(string prefix = ""); + string asm_str; + asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN); + case (format) + I_FORMAT: + if (category == LOAD) begin + asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, fd.name(), get_imm(), rs1.name()); + end else if (instr_name inside {FMV_X_W, FMV_X_D, FCVT_W_S, FCVT_WU_S, + FCVT_L_S, FCVT_LU_S, FCVT_L_D, FCVT_LU_D, FCVT_LU_S, + FCVT_W_D, FCVT_WU_D}) begin + asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), fs1.name()); + end else if (instr_name inside {FMV_W_X, FMV_D_X, FCVT_S_W, FCVT_S_WU, + FCVT_S_L, FCVT_D_L, FCVT_S_LU, FCVT_D_W, + FCVT_D_LU, FCVT_D_WU}) begin + asm_str = $sformatf("%0s%0s, %0s", asm_str, fd.name(), rs1.name()); + end else begin + asm_str = $sformatf("%0s%0s, %0s", asm_str, fd.name(), fs1.name()); + end + S_FORMAT: + asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, fs2.name(), get_imm(), rs1.name()); + R_FORMAT: + if (category == COMPARE) begin + asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, rd.name(), fs1.name(), fs2.name()); + end else if (instr_name inside {FCLASS_S, FCLASS_D}) begin + asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), fs1.name()); + end else begin + asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, fd.name(), fs1.name(), fs2.name()); + end + R4_FORMAT: + asm_str = $sformatf("%0s%0s, %0s, %0s, %0s", asm_str, fd.name(), fs1.name(), + fs2.name(), fs3.name()); + CL_FORMAT: + asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, fd.name(), get_imm(), rs1.name()); + CS_FORMAT: + asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, fs2.name(), get_imm(), rs1.name()); + default: + `uvm_fatal(`gfn, $sformatf("Unsupported floating point format: %0s", format.name())) + endcase + if(comment != "") + asm_str = {asm_str, " #",comment}; + return asm_str.tolower(); + endfunction + + + virtual function void do_copy(uvm_object rhs); + riscv_floating_point_instr rhs_; + super.copy(rhs); + assert($cast(rhs_, rhs)); + this.fs3 = rhs_.fs3; + this.fs2 = rhs_.fs2; + this.fs1 = rhs_.fs1; + this.fd = rhs_.fd; + endfunction : do_copy + +endclass diff --git a/src/isa/riscv_instr.sv b/src/isa/riscv_instr.sv new file mode 100644 index 00000000..87eee0cf --- /dev/null +++ b/src/isa/riscv_instr.sv @@ -0,0 +1,499 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class riscv_instr extends uvm_object; + + // All derived instructions + static bit instr_registry[riscv_instr_name_t]; + + // Instruction list + static riscv_instr instr[riscv_instr_name_t]; + static riscv_instr_name_t instr_names[$]; + + // Categorized instruction list + static riscv_instr_name_t instr_group[riscv_instr_group_t][$]; + static riscv_instr_name_t instr_category[riscv_instr_category_t][$]; + + // Instruction attributes + riscv_instr_group_t group; + riscv_instr_format_t format; + riscv_instr_category_t category; + riscv_instr_name_t instr_name; + imm_t imm_type; + bit [4:0] imm_len; + + // Operands + rand bit [11:0] csr; + rand riscv_reg_t rs2; + rand riscv_reg_t rs1; + rand riscv_reg_t rd; + rand bit [31:0] imm; + + // Helper fields + bit [31:0] imm_mask = 32'hFFFF_FFFF; + bit is_branch_target; + bit has_label = 1'b1; + bit atomic = 0; + bit branch_assigned; + bit process_load_store = 1'b1; + bit is_compressed; + bit is_illegal_instr; + bit is_hint_instr; + bit has_imm; + bit is_floating_point; + bit [31:0] imm_mask = '1; + string imm_str; + string comment; + string label; + bit is_local_numeric_label; + int idx = -1; + + constraint imm_c { + (instr_name inside {SLLI, SRLI, SRAI, SLLIW, SRLIW, SRAIW}) -> (imm[11:5] == 0); + } + + `uvm_object_utils(riscv_instr) + `uvm_object_new + + static function bit register(riscv_instr_name_t instr_name); + `uvm_info("riscv_instr", $sformatf("Registering %0s", instr_name.name()), UVM_LOW) + instr_registry[instr_name] = 1; + return 1; + endfunction : register + + // Create the list of instructions based on the supported ISA extensions and configuration of the + // generator. + static function void create_instr_list(riscv_instr_gen_config cfg); + uvm_object obj; + string instr_class_name; + uvm_coreservice_t coreservice = uvm_coreservice_t::get(); + uvm_factory factory = coreservice.get_factory(); + foreach (instr_registry[instr_name]) begin + riscv_instr instr_inst; + instr_class_name = {"riscv_", instr_name.name(), "_instr"}; + `uvm_info("riscv_instr", $sformatf("Creating instruction template : %s", + instr_class_name), UVM_LOW) + obj = factory.create_object_by_name(instr_class_name, "riscv_instr", instr_class_name); + if (obj == null) begin + `uvm_fatal("riscv_instr", $sformatf("Failed to create instr: %0s", instr_class_name)) + end + if (!$cast(instr_inst, obj)) begin + `uvm_fatal("riscv_instr", $sformatf("Failed to cast instr: %0s", instr_class_name)) + end + // C_JAL is RV32C only instruction + if ((XLEN != 32) && (instr_name == C_JAL)) continue; + // TODO: gcc compile issue + if (instr_name == C_ADDI4SPN) continue; + if (instr_inst.group inside {supported_isa}) begin + instr[instr_name] = instr_inst; + instr_category[instr_inst.category].push_back(instr_name); + instr_group[instr_inst.group].push_back(instr_name); + instr_names.push_back(instr_name); + end + end + endfunction : create_instr_list + + static function riscv_instr get_rand_instr(riscv_instr_name_t include_instr[] = {}, + riscv_instr_name_t exclude_instr[] = {}, + riscv_instr_category_t include_category[] = {}, + riscv_instr_category_t exclude_category[] = {}, + riscv_instr_group_t include_group[] = {}, + riscv_instr_group_t exclude_group[] = {}); + riscv_instr_name_t name; + riscv_instr_name_t allowed_instr[]; + riscv_instr_name_t disallowed_instr[]; + riscv_instr_category_t allowed_categories[]; + foreach (include_category[i]) begin + allowed_instr = {allowed_instr, instr_category[include_category[i]]}; + end + foreach (exclude_category[i]) begin + disallowed_instr = {disallowed_instr, instr_category[exclude_category[i]]}; + end + foreach (include_group[i]) begin + allowed_instr = {allowed_instr, instr_group[include_group[i]]}; + end + foreach (exclude_group[i]) begin + disallowed_instr = {disallowed_instr, instr_group[exclude_group[i]]}; + end + if (!std::randomize(name) with { + name inside {instr_names}; + if (include_instr.size() > 0) { + name inside {include_instr}; + } + if (exclude_instr.size() > 0) { + !(name inside {exclude_instr}); + } + if (allowed_instr.size() > 0) { + name inside {allowed_instr}; + } + if (disallowed_instr.size() > 0) { + !(name inside {disallowed_instr}); + } + }) begin + `uvm_fatal("riscv_instr", "Cannot generate random instruction") + end + return instr[name]; + endfunction : get_rand_instr + + // Disable the rand mode for unused operands to randomization performance + virtual function void set_rand_mode(); + case (format) inside + R_FORMAT, CR_FORMAT, CL_FORMAT : imm.rand_mode(0); + I_FORMAT, CI_FORMAT : rs2.rand_mode(0); + S_FORMAT, B_FORMAT, CSS_FORMAT, CS_FORMAT : rd.rand_mode(0); + U_FORMAT, J_FORMAT, CJ_FORMAT, CIW_FORMAT: begin + rs1.rand_mode(0); + rs2.rand_mode(0); + end + CB_FORMAT: begin + rd.rand_mode(0); + rs2.rand_mode(0); + end + endcase + endfunction + + virtual function void set_imm_len(); + if(format inside {U_FORMAT, J_FORMAT}) begin + imm_len = 20; + end else if(format inside {I_FORMAT, S_FORMAT, B_FORMAT}) begin + if(imm_type == UIMM) begin + imm_len = 5; + end else begin + imm_len = 11; + end + end + imm_mask = imm_mask << imm_len; + endfunction + + virtual function void extend_imm(); + bit sign; + imm = imm << (32 - imm_len); + sign = imm[31]; + imm = imm >> (32 - imm_len); + // Signed extension + if (sign && !((format == U_FORMAT) || (imm_type inside {UIMM, NZUIMM}))) begin + imm = imm_mask | imm; + end + comment = $sformatf("imm:0x%0x, imm_mask:0x%0x", imm, imm_mask); + endfunction : extend_imm + + function void post_randomize(); + extend_imm(); + update_imm_str(); + endfunction : post_randomize + + // Convert the instruction to assembly code + virtual function string convert2asm(string prefix = ""); + string asm_str; + asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN); + if(category != SYSTEM) begin + case(format) + J_FORMAT, U_FORMAT : // instr rd,imm + asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), get_imm()); + I_FORMAT: // instr rd,rs1,imm + if(instr_name == NOP) + asm_str = "nop"; + else if(instr_name == WFI) + asm_str = "wfi"; + else if(instr_name == FENCE) + asm_str = $sformatf("fence"); // TODO: Support all fence combinations + else if(instr_name == FENCE_I) + asm_str = "fence.i"; + else if(category == LOAD) // Use psuedo instruction format + asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rd.name(), get_imm(), rs1.name()); + else if(category == CSR) + asm_str = $sformatf("%0s%0s, 0x%0x, %0s", asm_str, rd.name(), csr, get_imm()); + else + asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, rd.name(), rs1.name(), get_imm()); + S_FORMAT, B_FORMAT: // instr rs1,rs2,imm + if(category == STORE) // Use psuedo instruction format + asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rs2.name(), get_imm(), rs1.name()); + else + asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, rs1.name(), rs2.name(), get_imm()); + R_FORMAT: // instr rd,rs1,rs2 + if(category == CSR) begin + asm_str = $sformatf("%0s%0s, 0x%0x, %0s", asm_str, rd.name(), csr, rs1.name()); + end else if(instr_name == SFENCE_VMA) begin + asm_str = "sfence.vma x0, x0"; // TODO: Support all possible sfence + end else begin + asm_str = $sformatf("%0s%0s, %0s, %0s", asm_str, rd.name(), rs1.name(), rs2.name()); + end + endcase + end else begin + // For EBREAK,C.EBREAK, making sure pc+4 is a valid instruction boundary + // This is needed to resume execution from epc+4 after ebreak handling + if(instr_name == EBREAK) begin + asm_str = ".4byte 0x00100073 # ebreak"; + end + end + if(comment != "") + asm_str = {asm_str, " #",comment}; + return asm_str.tolower(); + endfunction + + function bit [6:0] get_opcode(); + case (instr_name) inside + LUI : get_opcode = 7'b0110111; + AUIPC : get_opcode = 7'b0010111; + JAL : get_opcode = 7'b1101111; + JALR : get_opcode = 7'b1100111; + BEQ, BNE, BLT, BGE, BLTU, BGEU : get_opcode = 7'b1100011; + LB, LH, LW, LBU, LHU, LWU, LD : get_opcode = 7'b0000011; + SB, SH, SW, SD : get_opcode = 7'b0100011; + ADDI, SLTI, SLTIU, XORI, ORI, ANDI, SLLI, SRLI, SRAI, NOP : get_opcode = 7'b0010011; + ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND, MUL, + MULH, MULHSU, MULHU, DIV, DIVU, REM, REMU : get_opcode = 7'b0110011; + ADDIW, SLLIW, SRLIW, SRAIW : get_opcode = 7'b0011011; + MULH, MULHSU, MULHU, DIV, DIVU, REM, REMU : get_opcode = 7'b0110011; + FENCE, FENCE_I : get_opcode = 7'b0001111; + ECALL, EBREAK, CSRRW, CSRRS, CSRRC, CSRRWI, CSRRSI, CSRRCI : get_opcode = 7'b1110011; + ADDW, SUBW, SLLW, SRLW, SRAW, MULW, DIVW, DIVUW, REMW, REMUW : get_opcode = 7'b0111011; + ECALL, EBREAK, URET, SRET, MRET, DRET, WFI, SFENCE_VMA : get_opcode = 7'b1110011; + default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name())) + endcase + endfunction + + virtual function bit [2:0] get_func3(); + case (instr_name) inside + JALR : get_func3 = 3'b000; + BEQ : get_func3 = 3'b000; + BNE : get_func3 = 3'b001; + BLT : get_func3 = 3'b100; + BGE : get_func3 = 3'b101; + BLTU : get_func3 = 3'b110; + BGEU : get_func3 = 3'b111; + LB : get_func3 = 3'b000; + LH : get_func3 = 3'b001; + LW : get_func3 = 3'b010; + LBU : get_func3 = 3'b100; + LHU : get_func3 = 3'b101; + SB : get_func3 = 3'b000; + SH : get_func3 = 3'b001; + SW : get_func3 = 3'b010; + ADDI : get_func3 = 3'b000; + NOP : get_func3 = 3'b000; + SLTI : get_func3 = 3'b010; + SLTIU : get_func3 = 3'b011; + XORI : get_func3 = 3'b100; + ORI : get_func3 = 3'b110; + ANDI : get_func3 = 3'b111; + SLLI : get_func3 = 3'b001; + SRLI : get_func3 = 3'b101; + SRAI : get_func3 = 3'b101; + ADD : get_func3 = 3'b000; + SUB : get_func3 = 3'b000; + SLL : get_func3 = 3'b001; + SLT : get_func3 = 3'b010; + SLTU : get_func3 = 3'b011; + XOR : get_func3 = 3'b100; + SRL : get_func3 = 3'b101; + SRA : get_func3 = 3'b101; + OR : get_func3 = 3'b110; + AND : get_func3 = 3'b111; + FENCE : get_func3 = 3'b000; + FENCE_I : get_func3 = 3'b001; + ECALL : get_func3 = 3'b000; + EBREAK : get_func3 = 3'b000; + CSRRW : get_func3 = 3'b001; + CSRRS : get_func3 = 3'b010; + CSRRC : get_func3 = 3'b011; + CSRRWI : get_func3 = 3'b101; + CSRRSI : get_func3 = 3'b110; + CSRRCI : get_func3 = 3'b111; + LWU : get_func3 = 3'b110; + LD : get_func3 = 3'b011; + SD : get_func3 = 3'b011; + ADDIW : get_func3 = 3'b000; + SLLIW : get_func3 = 3'b001; + SRLIW : get_func3 = 3'b101; + SRAIW : get_func3 = 3'b101; + ADDW : get_func3 = 3'b000; + SUBW : get_func3 = 3'b000; + SLLW : get_func3 = 3'b001; + SRLW : get_func3 = 3'b101; + SRAW : get_func3 = 3'b101; + MUL : get_func3 = 3'b000; + MULH : get_func3 = 3'b001; + MULHSU : get_func3 = 3'b010; + MULHU : get_func3 = 3'b011; + DIV : get_func3 = 3'b100; + DIVU : get_func3 = 3'b101; + REM : get_func3 = 3'b110; + REMU : get_func3 = 3'b111; + MULW : get_func3 = 3'b000; + DIVW : get_func3 = 3'b100; + DIVUW : get_func3 = 3'b101; + REMW : get_func3 = 3'b110; + REMUW : get_func3 = 3'b111; + ECALL, EBREAK, URET, SRET, MRET, DRET, WFI, SFENCE_VMA : get_func3 = 3'b000; + default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name())) + endcase + endfunction + + function bit [6:0] get_func7(); + case (instr_name) + SLLI : get_func7 = 7'b0000000; + SRLI : get_func7 = 7'b0000000; + SRAI : get_func7 = 7'b0100000; + ADD : get_func7 = 7'b0000000; + SUB : get_func7 = 7'b0100000; + SLL : get_func7 = 7'b0000000; + SLT : get_func7 = 7'b0000000; + SLTU : get_func7 = 7'b0000000; + XOR : get_func7 = 7'b0000000; + SRL : get_func7 = 7'b0000000; + SRA : get_func7 = 7'b0100000; + OR : get_func7 = 7'b0000000; + AND : get_func7 = 7'b0000000; + FENCE : get_func7 = 7'b0000000; + FENCE_I : get_func7 = 7'b0000000; + SLLIW : get_func7 = 7'b0000000; + SRLIW : get_func7 = 7'b0000000; + SRAIW : get_func7 = 7'b0100000; + ADDW : get_func7 = 7'b0000000; + SUBW : get_func7 = 7'b0100000; + SLLW : get_func7 = 7'b0000000; + SRLW : get_func7 = 7'b0000000; + SRAW : get_func7 = 7'b0100000; + MUL : get_func7 = 7'b0000001; + MULH : get_func7 = 7'b0000001; + MULHSU : get_func7 = 7'b0000001; + MULHU : get_func7 = 7'b0000001; + DIV : get_func7 = 7'b0000001; + DIVU : get_func7 = 7'b0000001; + REM : get_func7 = 7'b0000001; + REMU : get_func7 = 7'b0000001; + MULW : get_func7 = 7'b0000001; + DIVW : get_func7 = 7'b0000001; + DIVUW : get_func7 = 7'b0000001; + REMW : get_func7 = 7'b0000001; + REMUW : get_func7 = 7'b0000001; + ECALL : get_func7 = 7'b0000000; + EBREAK : get_func7 = 7'b0000000; + URET : get_func7 = 7'b0000000; + SRET : get_func7 = 7'b0001000; + MRET : get_func7 = 7'b0011000; + DRET : get_func7 = 7'b0111101; + WFI : get_func7 = 7'b0001000; + SFENCE_VMA: get_func7 = 7'b0001001; + default : `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name())) + endcase + endfunction + + // Convert the instruction to assembly code + virtual function string convert2bin(string prefix = ""); + string binary; + case(format) + J_FORMAT: begin + binary = $sformatf("%8h", {imm[20], imm[10:1], imm[11], imm[19:12], rd, get_opcode()}); + end + U_FORMAT: begin + binary = $sformatf("%8h", {imm[31:12], rd, get_opcode()}); + end + I_FORMAT: begin + if(instr_name inside {FENCE, FENCE_I}) + binary = $sformatf("%8h", {17'b0, get_func3(), 5'b0, get_opcode()}); + else if(category == CSR) + binary = $sformatf("%8h", {csr[10:0], imm[4:0], get_func3(), rd, get_opcode()}); + else if(instr_name == ECALL) + binary = $sformatf("%8h", {get_func7(), 18'b0, get_opcode()}); + else if(instr_name inside {URET, SRET, MRET}) + binary = $sformatf("%8h", {get_func7(), 5'b10, 13'b0, get_opcode()}); + else if(instr_name inside {DRET}) + binary = $sformatf("%8h", {get_func7(), 5'b10010, 13'b0, get_opcode()}); + else if(instr_name == EBREAK) + binary = $sformatf("%8h", {get_func7(), 5'b01, 13'b0, get_opcode()}); + else if(instr_name == WFI) + binary = $sformatf("%8h", {get_func7(), 5'b101, 13'b0, get_opcode()}); + else + binary = $sformatf("%8h", {imm[11:0], rs1, get_func3(), rd, get_opcode()}); + end + S_FORMAT: begin + binary = $sformatf("%8h", {imm[11:5], rs2, rs1, get_func3(), imm[4:0], get_opcode()}); + end + B_FORMAT: begin + binary = $sformatf("%8h", + {imm[12], imm[10:5], rs2, rs1, get_func3(), + imm[4:1], imm[11], get_opcode()}); + end + R_FORMAT: begin + if(category == CSR) + binary = $sformatf("%8h", {csr[10:0], rs1, get_func3(), rd, get_opcode()}); + else if(instr_name == SFENCE_VMA) + binary = $sformatf("%8h", {get_func7(), 18'b0, get_opcode()}); + else + binary = $sformatf("%8h", {get_func7(), rs2, rs1, get_func3(), rd, get_opcode()}); + end + endcase + return {prefix, binary}; + endfunction + + virtual function string get_instr_name(); + get_instr_name = instr_name.name(); + if(get_instr_name.substr(0, 1) == "C_") begin + get_instr_name = {"c.", get_instr_name.substr(2, get_instr_name.len() - 1)}; + end else if (group inside {RV32F, RV64F, RV32D, RV64D}) begin + foreach(get_instr_name[i]) begin + if (get_instr_name[i] == "_") begin + get_instr_name[i] = "."; + end + end + end + return get_instr_name; + endfunction + + // Get RVC register name for CIW, CL, CS, CB format + function bit [2:0] get_c_gpr(riscv_reg_t gpr); + return gpr[2:0]; + endfunction + + // Default return imm value directly, can be overriden to use labels and symbols + // Example: %hi(symbol), %pc_rel(label) ... + virtual function string get_imm(); + return imm_str; + endfunction + + virtual function void clear_unused_label(); + if(has_label && !is_branch_target && is_local_numeric_label) begin + has_label = 1'b0; + end + endfunction + + virtual function void do_copy(uvm_object rhs); + riscv_instr rhs_; + super.copy(rhs); + assert($cast(rhs_, rhs)); + this.group = rhs_.group; + this.format = rhs_.format; + this.category = rhs_.category; + this.instr_name = rhs_.instr_name; + this.rs2 = rhs_.rs2; + this.rs1 = rhs_.rs1; + this.rd = rhs_.rd; + this.imm = rhs_.imm; + this.imm_type = rhs_.imm_type; + this.imm_len = rhs_.imm_len; + this.imm_mask = rhs_.imm_mask; + this.imm_str = rhs_.imm_str; + this.imm_mask = rhs_.imm_mask; + this.is_compressed = rhs_.is_compressed; + endfunction : do_copy + + virtual function void update_imm_str(); + imm_str = $sformatf("%0d", $signed(imm)); + endfunction + +endclass diff --git a/src/isa/riscv_vector_instr.sv b/src/isa/riscv_vector_instr.sv new file mode 100644 index 00000000..fba526fe --- /dev/null +++ b/src/isa/riscv_vector_instr.sv @@ -0,0 +1,25 @@ +class riscv_vector_instr extends riscv_instr; + + // TODO : Add vector instruction operands here + + `uvm_object_utils(riscv_vector_instr) + + function new(string name = ""); + super.new(name); + endfunction + + virtual function string get_instr_name(); + // TODO : Implement this function for vector instructions + endfunction + + // Convert the instruction to assembly code + virtual function string convert2asm(string prefix = ""); + string asm_str; + asm_str = format_string(get_instr_name(), MAX_INSTR_STR_LEN); + // TODO : Implement this function for vector instructions + if(comment != "") + asm_str = {asm_str, " #",comment}; + return asm_str.tolower(); + endfunction + +endclass diff --git a/src/isa/rv128c_instr.sv b/src/isa/rv128c_instr.sv new file mode 100644 index 00000000..30af2ea5 --- /dev/null +++ b/src/isa/rv128c_instr.sv @@ -0,0 +1,7 @@ +`DEFINE_C_INSTR(C_SRLI64, CB_FORMAT, SHIFT, RV128C, NZUIMM) +`DEFINE_C_INSTR(C_SRAI64, CB_FORMAT, SHIFT, RV128C, NZUIMM) +`DEFINE_C_INSTR(C_SLLI64, CI_FORMAT, SHIFT, RV128C, NZUIMM) +`DEFINE_C_INSTR(C_LQ, CL_FORMAT, LOAD, RV32DC, UIMM) +`DEFINE_C_INSTR(C_SQ, CS_FORMAT, STORE, RV32DC, UIMM) +`DEFINE_C_INSTR(C_LQSP, CI_FORMAT, LOAD, RV32DC, UIMM) +`DEFINE_C_INSTR(C_SQSP, CSS_FORMAT, STORE, RV32DC, UIMM) diff --git a/src/isa/rv32a_instr.sv b/src/isa/rv32a_instr.sv new file mode 100644 index 00000000..c5374100 --- /dev/null +++ b/src/isa/rv32a_instr.sv @@ -0,0 +1,11 @@ +`DEFINE_AMO_INSTR(LR_W, R_FORMAT, LOAD, RV32A) +`DEFINE_AMO_INSTR(SC_W, R_FORMAT, STORE, RV32A) +`DEFINE_AMO_INSTR(AMOSWAP_W, R_FORMAT, AMO, RV32A) +`DEFINE_AMO_INSTR(AMOADD_W, R_FORMAT, AMO, RV32A) +`DEFINE_AMO_INSTR(AMOAND_W, R_FORMAT, AMO, RV32A) +`DEFINE_AMO_INSTR(AMOOR_W, R_FORMAT, AMO, RV32A) +`DEFINE_AMO_INSTR(AMOXOR_W, R_FORMAT, AMO, RV32A) +`DEFINE_AMO_INSTR(AMOMIN_W, R_FORMAT, AMO, RV32A) +`DEFINE_AMO_INSTR(AMOMAX_W, R_FORMAT, AMO, RV32A) +`DEFINE_AMO_INSTR(AMOMINU_W, R_FORMAT, AMO, RV32A) +`DEFINE_AMO_INSTR(AMOMAXU_W, R_FORMAT, AMO, RV32A) diff --git a/src/isa/rv32c_instr.sv b/src/isa/rv32c_instr.sv new file mode 100644 index 00000000..c2df949a --- /dev/null +++ b/src/isa/rv32c_instr.sv @@ -0,0 +1,27 @@ +`DEFINE_C_INSTR(C_LW, CL_FORMAT, LOAD, RV32C, UIMM) +`DEFINE_C_INSTR(C_SW, CS_FORMAT, STORE, RV32C, UIMM) +`DEFINE_C_INSTR(C_LWSP, CI_FORMAT, LOAD, RV32C, UIMM) +`DEFINE_C_INSTR(C_SWSP, CSS_FORMAT, STORE, RV32C, UIMM) +`DEFINE_C_INSTR(C_ADDI4SPN, CIW_FORMAT, ARITHMETIC, RV32C, NZUIMM) +`DEFINE_C_INSTR(C_ADDI, CI_FORMAT, ARITHMETIC, RV32C, NZIMM) +`DEFINE_C_INSTR(C_ADDI16SP, CI_FORMAT, ARITHMETIC, RV32C, NZIMM) +`DEFINE_C_INSTR(C_LI, CI_FORMAT, ARITHMETIC, RV32C) +`DEFINE_C_INSTR(C_LUI, CI_FORMAT, ARITHMETIC, RV32C, NZIMM) +`DEFINE_C_INSTR(C_SUB, CA_FORMAT, ARITHMETIC, RV32C) +`DEFINE_C_INSTR(C_ADD, CR_FORMAT, ARITHMETIC, RV32C) +`DEFINE_C_INSTR(C_NOP, CI_FORMAT, ARITHMETIC, RV32C) +`DEFINE_C_INSTR(C_MV, CR_FORMAT, ARITHMETIC, RV32C) +`DEFINE_C_INSTR(C_ANDI, CB_FORMAT, LOGICAL, RV32C) +`DEFINE_C_INSTR(C_XOR, CA_FORMAT, LOGICAL, RV32C) +`DEFINE_C_INSTR(C_OR, CA_FORMAT, LOGICAL, RV32C) +`DEFINE_C_INSTR(C_AND, CA_FORMAT, LOGICAL, RV32C) +`DEFINE_C_INSTR(C_BEQZ, CB_FORMAT, BRANCH, RV32C) +`DEFINE_C_INSTR(C_BNEZ, CB_FORMAT, BRANCH, RV32C) +`DEFINE_C_INSTR(C_SRLI, CB_FORMAT, SHIFT, RV32C, NZUIMM) +`DEFINE_C_INSTR(C_SRAI, CB_FORMAT, SHIFT, RV32C, NZUIMM) +`DEFINE_C_INSTR(C_SLLI, CI_FORMAT, SHIFT, RV32C, NZUIMM) +`DEFINE_C_INSTR(C_J, CJ_FORMAT, JUMP, RV32C) +`DEFINE_C_INSTR(C_JAL, CJ_FORMAT, JUMP, RV32C) +`DEFINE_C_INSTR(C_JR, CR_FORMAT, JUMP, RV32C) +`DEFINE_C_INSTR(C_JALR, CR_FORMAT, JUMP, RV32C) +`DEFINE_C_INSTR(C_EBREAK, CI_FORMAT, SYSTEM, RV32C) diff --git a/src/isa/rv32d_instr.sv b/src/isa/rv32d_instr.sv new file mode 100644 index 00000000..dc53a262 --- /dev/null +++ b/src/isa/rv32d_instr.sv @@ -0,0 +1,26 @@ +`DEFINE_FP_INSTR(FLD, I_FORMAT, LOAD, RV32D) +`DEFINE_FP_INSTR(FSD, S_FORMAT, STORE, RV32D) +`DEFINE_FP_INSTR(FMADD_D, R4_FORMAT, ARITHMETIC, RV32D) +`DEFINE_FP_INSTR(FMSUB_D, R4_FORMAT, ARITHMETIC, RV32D) +`DEFINE_FP_INSTR(FNMSUB_D, R4_FORMAT, ARITHMETIC, RV32D) +`DEFINE_FP_INSTR(FNMADD_D, R4_FORMAT, ARITHMETIC, RV32D) +`DEFINE_FP_INSTR(FADD_D, R_FORMAT, ARITHMETIC, RV32D) +`DEFINE_FP_INSTR(FSUB_D, R_FORMAT, ARITHMETIC, RV32D) +`DEFINE_FP_INSTR(FMUL_D, R_FORMAT, ARITHMETIC, RV32D) +`DEFINE_FP_INSTR(FDIV_D, R_FORMAT, ARITHMETIC, RV32D) +`DEFINE_FP_INSTR(FSQRT_D, I_FORMAT, ARITHMETIC, RV32D) +`DEFINE_FP_INSTR(FSGNJ_D, R_FORMAT, ARITHMETIC, RV32D) +`DEFINE_FP_INSTR(FSGNJN_D, R_FORMAT, ARITHMETIC, RV32D) +`DEFINE_FP_INSTR(FSGNJX_D, R_FORMAT, ARITHMETIC, RV32D) +`DEFINE_FP_INSTR(FMIN_D, R_FORMAT, ARITHMETIC, RV32D) +`DEFINE_FP_INSTR(FMAX_D, R_FORMAT, ARITHMETIC, RV32D) +`DEFINE_FP_INSTR(FCVT_S_D, I_FORMAT, ARITHMETIC, RV32D) +`DEFINE_FP_INSTR(FCVT_D_S, I_FORMAT, ARITHMETIC, RV32D) +`DEFINE_FP_INSTR(FEQ_D, R_FORMAT, COMPARE, RV32D) +`DEFINE_FP_INSTR(FLT_D, R_FORMAT, COMPARE, RV32D) +`DEFINE_FP_INSTR(FLE_D, R_FORMAT, COMPARE, RV32D) +`DEFINE_FP_INSTR(FCLASS_D, R_FORMAT, ARITHMETIC, RV32D) +`DEFINE_FP_INSTR(FCVT_W_D, I_FORMAT, ARITHMETIC, RV32D) +`DEFINE_FP_INSTR(FCVT_WU_D, I_FORMAT, ARITHMETIC, RV32D) +`DEFINE_FP_INSTR(FCVT_D_W, I_FORMAT, ARITHMETIC, RV32D) +`DEFINE_FP_INSTR(FCVT_D_WU, I_FORMAT, ARITHMETIC, RV32D) diff --git a/src/isa/rv32dc_instr.sv b/src/isa/rv32dc_instr.sv new file mode 100644 index 00000000..e93116fd --- /dev/null +++ b/src/isa/rv32dc_instr.sv @@ -0,0 +1,4 @@ +`DEFINE_FC_INSTR(C_FLD, CL_FORMAT, LOAD, RV32DC, UIMM) +`DEFINE_FC_INSTR(C_FSD, CS_FORMAT, STORE, RV32DC, UIMM) +`DEFINE_FC_INSTR(C_FLDSP, CI_FORMAT, LOAD, RV32DC, UIMM) +`DEFINE_FC_INSTR(C_FSDSP, CSS_FORMAT, STORE, RV32DC, UIMM) diff --git a/src/isa/rv32f_instr.sv b/src/isa/rv32f_instr.sv new file mode 100644 index 00000000..ee2ebd90 --- /dev/null +++ b/src/isa/rv32f_instr.sv @@ -0,0 +1,26 @@ +`DEFINE_FP_INSTR(FLW, I_FORMAT, LOAD, RV32F) +`DEFINE_FP_INSTR(FSW, S_FORMAT, STORE, RV32F) +`DEFINE_FP_INSTR(FMADD_S, R4_FORMAT, ARITHMETIC, RV32F) +`DEFINE_FP_INSTR(FMSUB_S, R4_FORMAT, ARITHMETIC, RV32F) +`DEFINE_FP_INSTR(FNMSUB_S, R4_FORMAT, ARITHMETIC, RV32F) +`DEFINE_FP_INSTR(FNMADD_S, R4_FORMAT, ARITHMETIC, RV32F) +`DEFINE_FP_INSTR(FADD_S, R_FORMAT, ARITHMETIC, RV32F) +`DEFINE_FP_INSTR(FSUB_S, R_FORMAT, ARITHMETIC, RV32F) +`DEFINE_FP_INSTR(FMUL_S, R_FORMAT, ARITHMETIC, RV32F) +`DEFINE_FP_INSTR(FDIV_S, R_FORMAT, ARITHMETIC, RV32F) +`DEFINE_FP_INSTR(FSQRT_S, I_FORMAT, ARITHMETIC, RV32F) +`DEFINE_FP_INSTR(FSGNJ_S, R_FORMAT, ARITHMETIC, RV32F) +`DEFINE_FP_INSTR(FSGNJN_S, R_FORMAT, ARITHMETIC, RV32F) +`DEFINE_FP_INSTR(FSGNJX_S, R_FORMAT, ARITHMETIC, RV32F) +`DEFINE_FP_INSTR(FMIN_S, R_FORMAT, ARITHMETIC, RV32F) +`DEFINE_FP_INSTR(FMAX_S, R_FORMAT, ARITHMETIC, RV32F) +`DEFINE_FP_INSTR(FCVT_W_S, I_FORMAT, ARITHMETIC, RV32F) +`DEFINE_FP_INSTR(FCVT_WU_S, I_FORMAT, ARITHMETIC, RV32F) +`DEFINE_FP_INSTR(FMV_X_W, I_FORMAT, ARITHMETIC, RV32F) +`DEFINE_FP_INSTR(FEQ_S, R_FORMAT, COMPARE, RV32F) +`DEFINE_FP_INSTR(FLT_S, R_FORMAT, COMPARE, RV32F) +`DEFINE_FP_INSTR(FLE_S, R_FORMAT, COMPARE, RV32F) +`DEFINE_FP_INSTR(FCLASS_S, R_FORMAT, ARITHMETIC, RV32F) +`DEFINE_FP_INSTR(FCVT_S_W, I_FORMAT, ARITHMETIC, RV32F) +`DEFINE_FP_INSTR(FCVT_S_WU, I_FORMAT, ARITHMETIC, RV32F) +`DEFINE_FP_INSTR(FMV_W_X, I_FORMAT, ARITHMETIC, RV32F) diff --git a/src/isa/rv32fc_instr.sv b/src/isa/rv32fc_instr.sv new file mode 100644 index 00000000..04d5d1bd --- /dev/null +++ b/src/isa/rv32fc_instr.sv @@ -0,0 +1,4 @@ +`DEFINE_FC_INSTR(C_FLW, CL_FORMAT, LOAD, RV32FC, UIMM) +`DEFINE_FC_INSTR(C_FSW, CS_FORMAT, STORE, RV32FC, UIMM) +`DEFINE_FC_INSTR(C_FLWSP, CI_FORMAT, LOAD, RV32FC, UIMM) +`DEFINE_FC_INSTR(C_FSWSP, CSS_FORMAT, STORE, RV32FC, UIMM) diff --git a/src/isa/rv32i_instr.sv b/src/isa/rv32i_instr.sv new file mode 100644 index 00000000..9073a689 --- /dev/null +++ b/src/isa/rv32i_instr.sv @@ -0,0 +1,64 @@ +// LOAD instructions +`DEFINE_INSTR(LB, I_FORMAT, LOAD, RV32I) +`DEFINE_INSTR(LH, I_FORMAT, LOAD, RV32I) +`DEFINE_INSTR(LW, I_FORMAT, LOAD, RV32I) +`DEFINE_INSTR(LBU, I_FORMAT, LOAD, RV32I) +`DEFINE_INSTR(LHU, I_FORMAT, LOAD, RV32I) +// STORE instructions +`DEFINE_INSTR(SB, S_FORMAT, STORE, RV32I) +`DEFINE_INSTR(SH, S_FORMAT, STORE, RV32I) +`DEFINE_INSTR(SW, S_FORMAT, STORE, RV32I) +// SHIFT intructions +`DEFINE_INSTR(SLL, R_FORMAT, SHIFT, RV32I) +`DEFINE_INSTR(SLLI, I_FORMAT, SHIFT, RV32I) +`DEFINE_INSTR(SRL, R_FORMAT, SHIFT, RV32I) +`DEFINE_INSTR(SRLI, I_FORMAT, SHIFT, RV32I) +`DEFINE_INSTR(SRA, R_FORMAT, SHIFT, RV32I) +`DEFINE_INSTR(SRAI, I_FORMAT, SHIFT, RV32I) +// ARITHMETIC intructions +`DEFINE_INSTR(ADD, R_FORMAT, ARITHMETIC, RV32I) +`DEFINE_INSTR(ADDI, I_FORMAT, ARITHMETIC, RV32I) +`DEFINE_INSTR(NOP, I_FORMAT, ARITHMETIC, RV32I) +`DEFINE_INSTR(SUB, R_FORMAT, ARITHMETIC, RV32I) +`DEFINE_INSTR(LUI, U_FORMAT, ARITHMETIC, RV32I, UIMM) +`DEFINE_INSTR(AUIPC, U_FORMAT, ARITHMETIC, RV32I, UIMM) +// LOGICAL instructions +`DEFINE_INSTR(XOR, R_FORMAT, LOGICAL, RV32I) +`DEFINE_INSTR(XORI, I_FORMAT, LOGICAL, RV32I) +`DEFINE_INSTR(OR, R_FORMAT, LOGICAL, RV32I) +`DEFINE_INSTR(ORI, I_FORMAT, LOGICAL, RV32I) +`DEFINE_INSTR(AND, R_FORMAT, LOGICAL, RV32I) +`DEFINE_INSTR(ANDI, I_FORMAT, LOGICAL, RV32I) +// COMPARE instructions +`DEFINE_INSTR(SLT, R_FORMAT, COMPARE, RV32I) +`DEFINE_INSTR(SLTI, I_FORMAT, COMPARE, RV32I) +`DEFINE_INSTR(SLTU, R_FORMAT, COMPARE, RV32I) +`DEFINE_INSTR(SLTIU, I_FORMAT, COMPARE, RV32I) +// BRANCH instructions +`DEFINE_INSTR(BEQ, B_FORMAT, BRANCH, RV32I) +`DEFINE_INSTR(BNE, B_FORMAT, BRANCH, RV32I) +`DEFINE_INSTR(BLT, B_FORMAT, BRANCH, RV32I) +`DEFINE_INSTR(BGE, B_FORMAT, BRANCH, RV32I) +`DEFINE_INSTR(BLTU, B_FORMAT, BRANCH, RV32I) +`DEFINE_INSTR(BGEU, B_FORMAT, BRANCH, RV32I) +// JUMP instructions +`DEFINE_INSTR(JAL, J_FORMAT, JUMP, RV32I) +`DEFINE_INSTR(JALR, I_FORMAT, JUMP, RV32I) +// SYNCH instructions +`DEFINE_INSTR(FENCE, I_FORMAT, SYNCH, RV32I) +`DEFINE_INSTR(FENCE_I, I_FORMAT, SYNCH, RV32I) +// SYSTEM instructions +`DEFINE_INSTR(ECALL, I_FORMAT, SYSTEM, RV32I) +`DEFINE_INSTR(EBREAK, I_FORMAT, SYSTEM, RV32I) +`DEFINE_INSTR(URET, I_FORMAT, SYSTEM, RV32I) +`DEFINE_INSTR(SRET, I_FORMAT, SYSTEM, RV32I) +`DEFINE_INSTR(MRET, I_FORMAT, SYSTEM, RV32I) +`DEFINE_INSTR(DRET, I_FORMAT, SYSTEM, RV32I) +`DEFINE_INSTR(WFI, I_FORMAT, INTERRUPT, RV32I) +// CSR instructions +`DEFINE_INSTR(CSRRW, R_FORMAT, CSR, RV32I, UIMM) +`DEFINE_INSTR(CSRRS, R_FORMAT, CSR, RV32I, UIMM) +`DEFINE_INSTR(CSRRC, R_FORMAT, CSR, RV32I, UIMM) +`DEFINE_INSTR(CSRRWI, I_FORMAT, CSR, RV32I, UIMM) +`DEFINE_INSTR(CSRRSI, I_FORMAT, CSR, RV32I, UIMM) +`DEFINE_INSTR(CSRRCI, I_FORMAT, CSR, RV32I, UIMM) diff --git a/src/isa/rv32m_instr.sv b/src/isa/rv32m_instr.sv new file mode 100644 index 00000000..16765b6b --- /dev/null +++ b/src/isa/rv32m_instr.sv @@ -0,0 +1,9 @@ +//////////// RV32M instructions ////////////// +`DEFINE_INSTR(MUL, R_FORMAT, ARITHMETIC, RV32M) +`DEFINE_INSTR(MULH, R_FORMAT, ARITHMETIC, RV32M) +`DEFINE_INSTR(MULHSU, R_FORMAT, ARITHMETIC, RV32M) +`DEFINE_INSTR(MULHU, R_FORMAT, ARITHMETIC, RV32M) +`DEFINE_INSTR(DIV, R_FORMAT, ARITHMETIC, RV32M) +`DEFINE_INSTR(DIVU, R_FORMAT, ARITHMETIC, RV32M) +`DEFINE_INSTR(REM, R_FORMAT, ARITHMETIC, RV32M) +`DEFINE_INSTR(REMU, R_FORMAT, ARITHMETIC, RV32M) diff --git a/src/isa/rv64a_instr.sv b/src/isa/rv64a_instr.sv new file mode 100644 index 00000000..4e1e3985 --- /dev/null +++ b/src/isa/rv64a_instr.sv @@ -0,0 +1,11 @@ +`DEFINE_AMO_INSTR(LR_D, R_FORMAT, LOAD, RV64A) +`DEFINE_AMO_INSTR(SC_D, R_FORMAT, STORE, RV64A) +`DEFINE_AMO_INSTR(AMOSWAP_D, R_FORMAT, AMO, RV64A) +`DEFINE_AMO_INSTR(AMOADD_D, R_FORMAT, AMO, RV64A) +`DEFINE_AMO_INSTR(AMOAND_D, R_FORMAT, AMO, RV64A) +`DEFINE_AMO_INSTR(AMOOR_D, R_FORMAT, AMO, RV64A) +`DEFINE_AMO_INSTR(AMOXOR_D, R_FORMAT, AMO, RV64A) +`DEFINE_AMO_INSTR(AMOMIN_D, R_FORMAT, AMO, RV64A) +`DEFINE_AMO_INSTR(AMOMAX_D, R_FORMAT, AMO, RV64A) +`DEFINE_AMO_INSTR(AMOMINU_D, R_FORMAT, AMO, RV64A) +`DEFINE_AMO_INSTR(AMOMAXU_D, R_FORMAT, AMO, RV64A) diff --git a/src/isa/rv64c_instr.sv b/src/isa/rv64c_instr.sv new file mode 100644 index 00000000..cf9e2826 --- /dev/null +++ b/src/isa/rv64c_instr.sv @@ -0,0 +1,7 @@ +`DEFINE_C_INSTR(C_ADDIW, CI_FORMAT, ARITHMETIC, RV64C) +`DEFINE_C_INSTR(C_SUBW, CA_FORMAT, ARITHMETIC, RV64C) +`DEFINE_C_INSTR(C_ADDW, CA_FORMAT, ARITHMETIC, RV64C) +`DEFINE_C_INSTR(C_LD, CL_FORMAT, LOAD, RV64C, UIMM) +`DEFINE_C_INSTR(C_SD, CS_FORMAT, STORE, RV64C, UIMM) +`DEFINE_C_INSTR(C_LDSP, CI_FORMAT, LOAD, RV64C, UIMM) +`DEFINE_C_INSTR(C_SDSP, CSS_FORMAT, STORE, RV64C, UIMM) diff --git a/src/isa/rv64d_instr.sv b/src/isa/rv64d_instr.sv new file mode 100644 index 00000000..2c0f86ed --- /dev/null +++ b/src/isa/rv64d_instr.sv @@ -0,0 +1,6 @@ +`DEFINE_FP_INSTR(FMV_X_D, I_FORMAT, ARITHMETIC, RV64D) +`DEFINE_FP_INSTR(FMV_D_X, I_FORMAT, ARITHMETIC, RV64D) +`DEFINE_FP_INSTR(FCVT_L_D, I_FORMAT, ARITHMETIC, RV64D) +`DEFINE_FP_INSTR(FCVT_LU_D, I_FORMAT, ARITHMETIC, RV64D) +`DEFINE_FP_INSTR(FCVT_D_L, I_FORMAT, ARITHMETIC, RV64D) +`DEFINE_FP_INSTR(FCVT_D_LU, I_FORMAT, ARITHMETIC, RV64D) diff --git a/src/isa/rv64f_instr.sv b/src/isa/rv64f_instr.sv new file mode 100644 index 00000000..2ecab638 --- /dev/null +++ b/src/isa/rv64f_instr.sv @@ -0,0 +1,4 @@ +`DEFINE_FP_INSTR(FCVT_L_S, I_FORMAT, ARITHMETIC, RV64F) +`DEFINE_FP_INSTR(FCVT_LU_S, I_FORMAT, ARITHMETIC, RV64F) +`DEFINE_FP_INSTR(FCVT_S_L, I_FORMAT, ARITHMETIC, RV64F) +`DEFINE_FP_INSTR(FCVT_S_LU, I_FORMAT, ARITHMETIC, RV64F) diff --git a/src/isa/rv64i_instr.sv b/src/isa/rv64i_instr.sv new file mode 100644 index 00000000..4e94c1eb --- /dev/null +++ b/src/isa/rv64i_instr.sv @@ -0,0 +1,14 @@ +`DEFINE_INSTR(LWU, I_FORMAT, LOAD, RV64I) +`DEFINE_INSTR(LD, I_FORMAT, LOAD, RV64I) +`DEFINE_INSTR(SD, S_FORMAT, STORE, RV64I) +// SHIFT intructions +`DEFINE_INSTR(SLLW, R_FORMAT, SHIFT, RV64I) +`DEFINE_INSTR(SLLIW, I_FORMAT, SHIFT, RV64I) +`DEFINE_INSTR(SRLW, R_FORMAT, SHIFT, RV64I) +`DEFINE_INSTR(SRLIW, I_FORMAT, SHIFT, RV64I) +`DEFINE_INSTR(SRAW, R_FORMAT, SHIFT, RV64I) +`DEFINE_INSTR(SRAIW, I_FORMAT, SHIFT, RV64I) +// ARITHMETIC intructions +`DEFINE_INSTR(ADDW, R_FORMAT, ARITHMETIC, RV64I) +`DEFINE_INSTR(ADDIW, I_FORMAT, ARITHMETIC, RV64I) +`DEFINE_INSTR(SUBW, R_FORMAT, ARITHMETIC, RV64I) diff --git a/src/isa/rv64m_instr.sv b/src/isa/rv64m_instr.sv new file mode 100644 index 00000000..126f9842 --- /dev/null +++ b/src/isa/rv64m_instr.sv @@ -0,0 +1,5 @@ +`DEFINE_INSTR(MULW, R_FORMAT, ARITHMETIC, RV64M) +`DEFINE_INSTR(DIVW, R_FORMAT, ARITHMETIC, RV64M) +`DEFINE_INSTR(DIVUW, R_FORMAT, ARITHMETIC, RV64M) +`DEFINE_INSTR(REMW, R_FORMAT, ARITHMETIC, RV64M) +`DEFINE_INSTR(REMUW, R_FORMAT, ARITHMETIC, RV64M) diff --git a/src/riscv_asm_program_gen.sv b/src/riscv_asm_program_gen.sv index e9c27837..50571ec8 100644 --- a/src/riscv_asm_program_gen.sv +++ b/src/riscv_asm_program_gen.sv @@ -1041,7 +1041,9 @@ class riscv_asm_program_gen extends uvm_object; virtual function void dump_perf_stats(); foreach(implemented_csr[i]) begin if (implemented_csr[i] inside {[MCYCLE:MHPMCOUNTER31H]}) begin - gen_signature_handshake(.instr(instr_stream), .signature_type(WRITE_CSR), .csr(implemented_csr[i])); + gen_signature_handshake(.instr(instr_stream), + .signature_type(WRITE_CSR), + .csr(implemented_csr[i])); end end endfunction diff --git a/src/riscv_defines.svh b/src/riscv_defines.svh index fe3c7fff..252400fb 100644 --- a/src/riscv_defines.svh +++ b/src/riscv_defines.svh @@ -33,3 +33,47 @@ } \ } +`define INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \ + static bit valid = riscv_instr::register(instr_n); \ + `uvm_object_utils(riscv_``instr_n``_instr) \ + function new(string name = ""); \ + super.new(name); \ + this.instr_name = ``instr_n; \ + this.format = ``instr_format; \ + this.group = ``instr_group; \ + this.category = ``instr_category; \ + this.imm_type = ``imm_tp; \ + set_imm_len(); \ + set_rand_mode(); \ + endfunction \ + endclass + +// Regular integer instruction +`define DEFINE_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \ + class riscv_``instr_n``_instr extends riscv_instr; \ + `INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp) + +// Floating point instruction +`define DEFINE_FP_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \ + class riscv_``instr_n``_instr extends riscv_floating_point_instr; \ + `INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp) + +// A-extension instruction +`define DEFINE_AMO_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \ + class riscv_``instr_n``_instr extends riscv_amo_instr; \ + `INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp) + +// Compressed instruction +`define DEFINE_C_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \ + class riscv_``instr_n``_instr extends riscv_compressed_instr; \ + `INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp) + +// Floating point compressed instruction +`define DEFINE_FC_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \ + class riscv_``instr_n``_instr extends riscv_compressed_instr; \ + `INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp) + +// Vector instruction +`define DEFINE_V_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \ + class riscv_``instr_n``_instr extends riscv_vector_instr; \ + `INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp) diff --git a/src/riscv_instr_pkg.sv b/src/riscv_instr_pkg.sv index 1fbdd85b..9c214641 100644 --- a/src/riscv_instr_pkg.sv +++ b/src/riscv_instr_pkg.sv @@ -867,6 +867,35 @@ package riscv_instr_pkg; riscv_reg_t compressed_gpr[] = {S0, S1, A0, A1, A2, A3, A4, A5}; + riscv_instr_category_t all_categories[] = { + LOAD, STORE, SHIFT, ARITHMETIC, LOGICAL, COMPARE, BRANCH, JUMP, + SYNCH, SYSTEM, COUNTER, CSR, CHANGELEVEL, TRAP, INTERRUPT, AMO + }; + + // New experimenal instruction class + `ifdef EXPERIMENTAL + `include "isa/riscv_instr.sv" + `include "isa/riscv_amo_instr.sv" + `include "isa/riscv_floating_point_instr.sv" + `include "isa/riscv_vector_instr.sv" + `include "isa/riscv_compressed_instr.sv" + `include "isa/rv32a_instr.sv" + `include "isa/rv32c_instr.sv" + `include "isa/rv32dc_instr.sv" + `include "isa/rv32d_instr.sv" + `include "isa/rv32fc_instr.sv" + `include "isa/rv32f_instr.sv" + `include "isa/rv32i_instr.sv" + `include "isa/rv32m_instr.sv" + `include "isa/rv64a_instr.sv" + `include "isa/rv64c_instr.sv" + `include "isa/rv64d_instr.sv" + `include "isa/rv64f_instr.sv" + `include "isa/rv64i_instr.sv" + `include "isa/rv64m_instr.sv" + `include "isa/rv128c_instr.sv" + `endif + `include "riscv_instr_base.sv" `include "riscv_instr_gen_config.sv" `include "riscv_illegal_instr.sv" diff --git a/target/exp/riscvOVPsim.ic b/target/exp/riscvOVPsim.ic new file mode 100644 index 00000000..efe857bc --- /dev/null +++ b/target/exp/riscvOVPsim.ic @@ -0,0 +1,18 @@ +# riscOVPsim configuration file converted from YAML +--variant RV64GC +--override riscvOVPsim/cpu/misa_MXL=2 +--override riscvOVPsim/cpu/misa_MXL_mask=0x0 # 0 +--override riscvOVPsim/cpu/misa_Extensions_mask=0x0 # 0 +--override riscvOVPsim/cpu/unaligned=T +--override riscvOVPsim/cpu/mtvec_mask=0x0 # 0 +--override riscvOVPsim/cpu/user_version=2.3 +--override riscvOVPsim/cpu/priv_version=1.11 +--override riscvOVPsim/cpu/mvendorid=0 +--override riscvOVPsim/cpu/marchid=0 +--override riscvOVPsim/cpu/mimpid=0 +--override riscvOVPsim/cpu/mhartid=0 +--override riscvOVPsim/cpu/cycle_undefined=F +--override riscvOVPsim/cpu/instret_undefined=F +--override riscvOVPsim/cpu/time_undefined=T +--override riscvOVPsim/cpu/reset_address=0x80000000 +--override riscvOVPsim/cpu/simulateexceptions=T diff --git a/target/exp/riscv_core_setting.sv b/target/exp/riscv_core_setting.sv new file mode 100644 index 00000000..aafb3b67 --- /dev/null +++ b/target/exp/riscv_core_setting.sv @@ -0,0 +1,144 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//----------------------------------------------------------------------------- +// Processor feature configuration +//----------------------------------------------------------------------------- +// XLEN +parameter int XLEN = 64; + +// Parameter for SATP mode, set to BARE if address translation is not supported +parameter satp_mode_t SATP_MODE = SV39; + +// Supported Privileged mode +privileged_mode_t supported_privileged_mode[] = {USER_MODE, SUPERVISOR_MODE, MACHINE_MODE}; + +// Unsupported instructions +riscv_instr_name_t unsupported_instr[]; + +// ISA supported by the processor +riscv_instr_group_t supported_isa[$] = {RV32I, RV32M, RV64I, RV64M, RV32C, RV64C, RV32A, RV64A, + RV32F, RV64F, RV32D, RV64D}; + +// Interrupt mode support +mtvec_mode_t supported_interrupt_mode[$] = {DIRECT, VECTORED}; + +// The number of interrupt vectors to be generated, only used if VECTORED interrupt mode is +// supported +int max_interrupt_vector_num = 16; + +// Debug mode support +bit support_debug_mode = 0; + +// Support delegate trap to user mode +bit support_umode_trap = 0; + +// Support sfence.vma instruction +bit support_sfence = 1; + +// ---------------------------------------------------------------------------- +// Previleged CSR implementation +// ---------------------------------------------------------------------------- + +// Implemented previlieged CSR list +`ifdef DSIM +privileged_reg_t implemented_csr[] = { +`else +parameter privileged_reg_t implemented_csr[] = { +`endif + // User mode CSR + USTATUS, // User status + UIE, // User interrupt-enable register + UTVEC, // User trap-handler base address + USCRATCH, // Scratch register for user trap handlers + UEPC, // User exception program counter + UCAUSE, // User trap cause + UTVAL, // User bad address or instruction + UIP, // User interrupt pending + // Supervisor mode CSR + SSTATUS, // Supervisor status + SEDELEG, // Supervisor exception delegation register + SIDELEG, // Supervisor interrupt delegation register + SIE, // Supervisor interrupt-enable register + STVEC, // Supervisor trap-handler base address + SCOUNTEREN, // Supervisor counter enable + SSCRATCH, // Scratch register for supervisor trap handlers + SEPC, // Supervisor exception program counter + SCAUSE, // Supervisor trap cause + STVAL, // Supervisor bad address or instruction + SIP, // Supervisor interrupt pending + SATP, // Supervisor address translation and protection + // Machine mode mode CSR + MVENDORID, // Vendor ID + MARCHID, // Architecture ID + MIMPID, // Implementation ID + MHARTID, // Hardware thread ID + MSTATUS, // Machine status + MISA, // ISA and extensions + MEDELEG, // Machine exception delegation register + MIDELEG, // Machine interrupt delegation register + MIE, // Machine interrupt-enable register + MTVEC, // Machine trap-handler base address + MCOUNTEREN, // Machine counter enable + MSCRATCH, // Scratch register for machine trap handlers + MEPC, // Machine exception program counter + MCAUSE, // Machine trap cause + MTVAL, // Machine bad address or instruction + MIP, // Machine interrupt pending + // Floating point CSR + FCSR // Floating point control and status +}; + +// ---------------------------------------------------------------------------- +// Supported interrupt/exception setting, used for functional coverage +// ---------------------------------------------------------------------------- + +`ifdef DSIM +interrupt_cause_t implemented_interrupt[] = { +`else +parameter interrupt_cause_t implemented_interrupt[] = { +`endif + U_SOFTWARE_INTR, + S_SOFTWARE_INTR, + M_SOFTWARE_INTR, + U_TIMER_INTR, + S_TIMER_INTR, + M_TIMER_INTR, + U_EXTERNAL_INTR, + S_EXTERNAL_INTR, + M_EXTERNAL_INTR +}; + +`ifdef DSIM +exception_cause_t implemented_exception[] = { +`else +parameter exception_cause_t implemented_exception[] = { +`endif + INSTRUCTION_ADDRESS_MISALIGNED, + INSTRUCTION_ACCESS_FAULT, + ILLEGAL_INSTRUCTION, + BREAKPOINT, + LOAD_ADDRESS_MISALIGNED, + LOAD_ACCESS_FAULT, + STORE_AMO_ADDRESS_MISALIGNED, + STORE_AMO_ACCESS_FAULT, + ECALL_UMODE, + ECALL_SMODE, + ECALL_MMODE, + INSTRUCTION_PAGE_FAULT, + LOAD_PAGE_FAULT, + STORE_AMO_PAGE_FAULT +}; diff --git a/target/exp/testlist.yaml b/target/exp/testlist.yaml new file mode 100644 index 00000000..9b6e1bbe --- /dev/null +++ b/target/exp/testlist.yaml @@ -0,0 +1,40 @@ +# Copyright Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# ================================================================================ +# Regression test list format +# -------------------------------------------------------------------------------- +# test : Assembly test name +# description : Description of this test +# gen_opts : Instruction generator options +# iterations : Number of iterations of this test +# no_iss : Enable/disable ISS simulator (Optional) +# gen_test : Test name used by the instruction generator +# rtl_test : RTL simulation test name +# cmp_opts : Compile options passed to the instruction generator +# sim_opts : Simulation options passed to the instruction generator +# no_post_compare : Enable/disable comparison of trace log and ISS log (Optional) +# compare_opts : Options for the RTL & ISS trace comparison +# gcc_opts : gcc compile options +# -------------------------------------------------------------------------------- + +- test: riscv_instr_test + description: > + New experimental instruction class test + iterations: 1 + gen_test: riscv_instr_test + gen_opts: > + +instr_cnt=10000 + +num_of_sub_program=5 + +boot_mode=m diff --git a/test/riscv_instr_test.sv b/test/riscv_instr_test.sv new file mode 100644 index 00000000..779b6a7b --- /dev/null +++ b/test/riscv_instr_test.sv @@ -0,0 +1,58 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Sanity test for riscv_instr_test class +class riscv_instr_test extends riscv_instr_base_test; + + `uvm_component_utils(riscv_instr_test) + `uvm_component_new + + task run_phase(uvm_phase phase); + int fd; + riscv_instr instr; + riscv_instr_name_t instr_name; + string test_name = $sformatf("%0s_0.S", asm_file_name); + fd = $fopen(test_name,"w"); + `uvm_info(`gfn, "Creating instruction list", UVM_LOW) + riscv_instr::create_instr_list(cfg); + `uvm_info(`gfn, "Randomizing instruction list now...", UVM_LOW) + repeat (10000) begin + instr = riscv_instr::get_rand_instr(); + `DV_CHECK_RANDOMIZE_FATAL(instr); + $fwrite(fd, {instr.convert2asm(),"\n"}); + end + repeat (10000) begin + instr = riscv_instr::get_rand_instr(.include_category({LOAD, STORE})); + `DV_CHECK_RANDOMIZE_FATAL(instr); + $fwrite(fd, {instr.convert2asm(),"\n"}); + end + repeat (10000) begin + instr = riscv_instr::get_rand_instr(.exclude_category({LOAD, STORE , BRANCH}), + .include_group({RV32I, RV32M})); + `DV_CHECK_RANDOMIZE_FATAL(instr); + $fwrite(fd, {instr.convert2asm(),"\n"}); + end + $fclose(fd); + `uvm_info(get_full_name(), $sformatf("%0s is generated", test_name), UVM_LOW) + endtask + + virtual function void randomize_cfg(); + `DV_CHECK_RANDOMIZE_FATAL(cfg); + `uvm_info(`gfn, $sformatf("riscv_instr_gen_config is randomized:\n%0s", + cfg.sprint()), UVM_LOW) + endfunction + +endclass diff --git a/test/riscv_instr_test_pkg.sv b/test/riscv_instr_test_pkg.sv index 5e93bd0a..da0342af 100644 --- a/test/riscv_instr_test_pkg.sv +++ b/test/riscv_instr_test_pkg.sv @@ -23,5 +23,8 @@ package riscv_instr_test_pkg; `include "riscv_instr_test_lib.sv" `include "riscv_instr_cov_debug_test.sv" `include "riscv_instr_cov_test.sv" + `ifdef EXPERIMENTAL + `include "riscv_instr_test.sv" + `endif endpackage diff --git a/yaml/base_testlist.yaml b/yaml/base_testlist.yaml index e02753f9..19c44137 100644 --- a/yaml/base_testlist.yaml +++ b/yaml/base_testlist.yaml @@ -151,10 +151,8 @@ gen_opts: > +instr_cnt=6000 +no_ebreak=0 - +require_signature_addr=1 rtl_test: core_base_test sim_opts: > - +require_signature_addr=1 +enable_debug_seq=1 compare_opts: > +compare_final_value_only=1 @@ -166,11 +164,9 @@ gen_test: riscv_rand_instr_test gen_opts: > +enable_interrupt=1 - +require_signature_addr=1 rtl_test: core_base_test sim_opts: > +enable_irq_seq=1 - +require_signature_addr=1 compare_opts: > +compare_final_value_only=1