diff --git a/src/isa/riscv_instr.sv b/src/isa/riscv_instr.sv index f44e972a2..8ef885e5a 100644 --- a/src/isa/riscv_instr.sv +++ b/src/isa/riscv_instr.sv @@ -111,7 +111,7 @@ class riscv_instr extends uvm_object; if (cfg.no_fence && (instr_name inside {FENCE, FENCE_I, SFENCE_VMA})) continue; if ((instr_inst.group inside {supported_isa}) && !(cfg.disable_compressed_instr && - (instr_inst.group inside {RV32C, RV64C, RV32DC, RV32FC, RV128C})) && + (instr_inst.group inside {RV32C, RV64C, RV32DC, RV32FC, RV128C, RV32ZCB, RV64ZCB})) && !(!cfg.enable_floating_point && (instr_inst.group inside {RV32F, RV64F, RV32D, RV64D})) && !(!cfg.enable_vector_extension && diff --git a/src/isa/riscv_instr_cov.svh b/src/isa/riscv_instr_cov.svh index 6819f3836..3fd3b223b 100644 --- a/src/isa/riscv_instr_cov.svh +++ b/src/isa/riscv_instr_cov.svh @@ -408,6 +408,22 @@ // c.j imm get_val(operands[0], imm); end + CU_FORMAT: begin + rs1 = get_gpr(operands[0]); + rs1_value = get_gpr_state(operands[0]); + end + CLB_FORMAT, CLH_FORMAT: begin + get_val(operands[2], imm); + rs1 = get_gpr(operands[1]); + rs1_value = get_gpr_state(operands[1]); + end + CSB_FORMAT, CSH_FORMAT: begin + rs2 = get_gpr(operands[0]); + rs2_value = get_gpr_state(operands[0]); + get_val(operands[2], imm); + rs1 = get_gpr(operands[1]); + rs1_value = get_gpr_state(operands[1]); + end default: `uvm_fatal(`gfn, $sformatf("Unsupported format %0s", format)) endcase endfunction : update_src_regs diff --git a/src/isa/riscv_zcb_instr.sv b/src/isa/riscv_zcb_instr.sv new file mode 100644 index 000000000..7eb7ce4b6 --- /dev/null +++ b/src/isa/riscv_zcb_instr.sv @@ -0,0 +1,225 @@ +/* + * Copyright 2020 Google LLC + * Copyright 2023 Frontgrade Gaisler + * + * 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_zcb_instr extends riscv_instr; + + // This code is based on the frozen v.1.0.1 code reduction specification. + // Most of the code is copied from the riscv_compressed_instr class. + + constraint rvc_csr_c { + // Registers specified by the three-bit rs1’, rs2’, and rd/rs1’ + if (format inside {CLB_FORMAT, CSB_FORMAT, CLH_FORMAT, CSH_FORMAT, CU_FORMAT, CA_FORMAT}) { + if (has_rs1) { + rs1 inside {[S0:A5]}; + } + if (has_rs2) { + rs2 inside {[S0:A5]}; + } + if (has_rd) { + rd inside {[S0:A5]}; + } + } + // CU_FORMAT and CA_FORMAT has rd == rs1 + if (format inside {CU_FORMAT, CA_FORMAT}) { + if (has_rd && has_rs1) { + rd == rs1; + } + } + } + + `uvm_object_utils(riscv_zcb_instr) + + function new(string name = ""); + super.new(name); + rs1 = S0; + rs2 = S0; + rd = S0; + is_compressed = 1'b1; + endfunction : new + + virtual function void set_imm_len(); + if (format inside {CLB_FORMAT, CSB_FORMAT}) begin + imm_len = 2; + end else if (format inside {CLH_FORMAT, CSH_FORMAT}) begin + imm_len = 1; + end + endfunction : set_imm_len + + virtual function void set_rand_mode(); + case (format) inside + CLB_FORMAT: begin + has_rs2 = 1'b0; + end + CSB_FORMAT: begin + has_rd = 1'b0; + end + CLH_FORMAT: begin + has_rs2 = 1'b0; + end + CSH_FORMAT: begin + has_rd = 1'b0; + end + CU_FORMAT: begin + has_rs2 = 1'b0; + has_imm = 1'b0; + end + CA_FORMAT: begin + has_imm = 1'b0; + end + default: `uvm_info(`gfn, $sformatf("Unsupported format %0s", format.name()), UVM_LOW) + endcase + 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) + CLB_FORMAT, CLH_FORMAT: + asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rd.name(), get_imm(), rs1.name()); + CSB_FORMAT, CSH_FORMAT: + asm_str = $sformatf("%0s%0s, %0s(%0s)", asm_str, rs2.name(), get_imm(), rs1.name()); + CU_FORMAT: + asm_str = $sformatf("%0s%0s", asm_str, rs1.name); + CA_FORMAT: + asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), rs2.name()); + default: `uvm_info(`gfn, $sformatf("Unsupported format %0s", format.name()), UVM_LOW) + endcase + + 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_LBU: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rs1), imm[0], imm[1], + get_c_gpr(rd), get_c_opcode()}); + C_LHU: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rs1), 1'b0, imm[1], + get_c_gpr(rd), get_c_opcode()}); + C_LH: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rs1), 1'b1, imm[1], + get_c_gpr(rd), get_c_opcode()}); + C_SB: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rs1), imm[0], imm[1], + get_c_gpr(rs2), get_c_opcode()}); + C_SH: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rs1), 1'b0, imm[1], + get_c_gpr(rs2), get_c_opcode()}); + C_ZEXT_B: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rd), 5'b11000, + get_c_opcode()}); + C_SEXT_B: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rd), 5'b11001, + get_c_opcode()}); + C_ZEXT_H: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rd), 5'b11010, + get_c_opcode()}); + C_SEXT_H: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rd), 5'b11011, + get_c_opcode()}); + C_ZEXT_W: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rd), 5'b11100, + get_c_opcode()}); + C_NOT: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rd), 5'b11101, + get_c_opcode()}); + C_MUL: + binary = $sformatf("0x%4h", {get_func6(), get_c_gpr(rd), 2'b10, + get_c_gpr(rs2), get_c_opcode()}); + default: `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name())) + endcase + return {prefix, binary}; + endfunction : convert2bin + + // Get opcode for zcb instruction + virtual function bit [1:0] get_c_opcode(); + case (instr_name) inside + C_ZEXT_B, C_SEXT_B, C_ZEXT_H, C_SEXT_H, + C_ZEXT_W, C_NOT, C_MUL : get_c_opcode = 2'b01; + C_LBU, C_LHU, C_LH, C_SB, C_SH : get_c_opcode = 2'b00; + default: `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name())) + endcase + endfunction : get_c_opcode + + virtual function bit [5:0] get_func6(); + case (instr_name) + C_LBU: get_func6 = 6'b100000; + C_LHU: get_func6 = 6'b100001; + C_LH: get_func6 = 6'b100001; + C_SB: get_func6 = 6'b100010; + C_SH: get_func6 = 6'b100011; + C_ZEXT_B: get_func6 = 6'b100011; + C_SEXT_B: get_func6 = 6'b100111; + C_ZEXT_H: get_func6 = 6'b100111; + C_SEXT_H: get_func6 = 6'b100111; + C_ZEXT_W: get_func6 = 6'b100111; + C_NOT: get_func6 = 6'b100111; + C_MUL: get_func6 = 6'b100111; + default: `uvm_fatal(`gfn, $sformatf("Unsupported instruction %0s", instr_name.name())) + endcase + endfunction : get_func6 + + virtual function bit is_supported(riscv_instr_gen_config cfg); + return (cfg.enable_zcb_extension && + // RV32C, RV32Zbb, RV32Zba, M/Zmmul is prerequisites for this extension + (RV32ZBB inside {supported_isa}) && + (RV32C inside {supported_isa}) && + (RV32ZBA inside {supported_isa}) && + ((RV32M inside {supported_isa}) || (RV32ZMMUL inside {supported_isa})) && + ((RV32ZCB inside {supported_isa} || RV64ZCB inside {supported_isa})) && + instr_name inside { + C_ZEXT_B, C_SEXT_B, C_ZEXT_H, C_SEXT_H, C_ZEXT_W, + C_NOT, C_MUL, C_LBU, C_LHU, C_LH, C_SB, C_SH + }); + endfunction : is_supported + + // For coverage + virtual function void update_src_regs(string operands[$]); + case(format) + CU_FORMAT: begin + rs1 = get_gpr(operands[0]); + rs1_value = get_gpr_state(operands[0]); + end + CLB_FORMAT, CLH_FORMAT: begin + get_val(operands[2], imm); + rs1 = get_gpr(operands[1]); + rs1_value = get_gpr_state(operands[1]); + end + CSB_FORMAT, CSH_FORMAT: begin + rs2 = get_gpr(operands[0]); + rs2_value = get_gpr_state(operands[0]); + get_val(operands[2], imm); + rs1 = get_gpr(operands[1]); + rs1_value = get_gpr_state(operands[1]); + end + CA_FORMAT: begin + rs2 = get_gpr(operands[1]); + rs2_value = get_gpr_state(operands[1]); + rs1 = get_gpr(operands[0]); + rs1_value = get_gpr_state(operands[0]); + end + default: ; + endcase + super.update_src_regs(operands); + endfunction : update_src_regs + +endclass : riscv_zcb_instr; diff --git a/src/isa/rv32zcb_instr.sv b/src/isa/rv32zcb_instr.sv new file mode 100644 index 000000000..d83fbd806 --- /dev/null +++ b/src/isa/rv32zcb_instr.sv @@ -0,0 +1,29 @@ +/* + * Copyright 2020 Google LLC + * Copyright 2023 Frontgrade Gaisler + * + * 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. + */ + +`DEFINE_ZCB_INSTR(C_LBU, CLB_FORMAT, LOAD, RV32ZCB, UIMM) +`DEFINE_ZCB_INSTR(C_LHU, CLH_FORMAT, LOAD, RV32ZCB, UIMM) +`DEFINE_ZCB_INSTR(C_LH, CLH_FORMAT, LOAD, RV32ZCB, UIMM) +`DEFINE_ZCB_INSTR(C_SB, CSB_FORMAT, STORE, RV32ZCB, UIMM) +`DEFINE_ZCB_INSTR(C_SH, CSH_FORMAT, STORE, RV32ZCB, UIMM) +`DEFINE_ZCB_INSTR(C_ZEXT_B, CU_FORMAT, ARITHMETIC, RV32ZCB) +`DEFINE_ZCB_INSTR(C_SEXT_B, CU_FORMAT, ARITHMETIC, RV32ZCB) +`DEFINE_ZCB_INSTR(C_ZEXT_H, CU_FORMAT, ARITHMETIC, RV32ZCB) +`DEFINE_ZCB_INSTR(C_SEXT_H, CU_FORMAT, ARITHMETIC, RV32ZCB) +`DEFINE_ZCB_INSTR(C_NOT, CU_FORMAT, LOGICAL, RV32ZCB) +`DEFINE_ZCB_INSTR(C_MUL, CA_FORMAT, ARITHMETIC, RV32ZCB) + diff --git a/src/isa/rv64zcb_instr.sv b/src/isa/rv64zcb_instr.sv new file mode 100644 index 000000000..8225b8235 --- /dev/null +++ b/src/isa/rv64zcb_instr.sv @@ -0,0 +1,18 @@ +/* + * Copyright 2020 Google LLC + * Copyright 2023 Frontgrade Gaisler + * + * 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. + */ + +`DEFINE_ZCB_INSTR(C_ZEXT_W, CU_FORMAT, ARITHMETIC, RV64ZCB) diff --git a/src/riscv_asm_program_gen.sv b/src/riscv_asm_program_gen.sv index 4c969241a..ed3be75d8 100644 --- a/src/riscv_asm_program_gen.sv +++ b/src/riscv_asm_program_gen.sv @@ -459,6 +459,7 @@ class riscv_asm_program_gen extends uvm_object; RV32X, RV64X : misa[MISA_EXT_X] = 1'b1; RV32ZBA, RV32ZBB, RV32ZBC, RV32ZBS, RV64ZBA, RV64ZBB, RV64ZBC, RV64ZBS : ; // No Misa bit for Zb* extensions + RV32ZCB, RV64ZCB : ; // No Misa bit for Zc* extensions default : `uvm_fatal(`gfn, $sformatf("%0s is not yet supported", supported_isa[i].name())) endcase diff --git a/src/riscv_defines.svh b/src/riscv_defines.svh index 4d078e164..b6cb34efb 100644 --- a/src/riscv_defines.svh +++ b/src/riscv_defines.svh @@ -129,3 +129,8 @@ `define DEFINE_ZBS_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \ class riscv_``instr_n``_instr extends riscv_zbs_instr; \ `INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp) + +//Zcb-extension instruction +`define DEFINE_ZCB_INSTR(instr_n, instr_format, instr_category, instr_group, imm_tp = IMM) \ + class riscv_``instr_n``_instr extends riscv_zcb_instr; \ + `INSTR_BODY(instr_n, instr_format, instr_category, instr_group, imm_tp) diff --git a/src/riscv_directed_instr_lib.sv b/src/riscv_directed_instr_lib.sv index f3bc7080a..bafb1bca2 100644 --- a/src/riscv_directed_instr_lib.sv +++ b/src/riscv_directed_instr_lib.sv @@ -474,7 +474,7 @@ class riscv_int_numeric_corner_stream extends riscv_directed_instr_stream; for (int i = 0; i < num_of_instr; i++) begin riscv_instr instr = riscv_instr::get_rand_instr( .include_category({ARITHMETIC}), - .exclude_group({RV32C, RV64C, RV32F, RV64F, RV32D, RV64D})); + .exclude_group({RV32C, RV64C, RV32ZCB, RV64ZCB, RV32F, RV64F, RV32D, RV64D})); randomize_gpr(instr); instr_list.push_back(instr); end diff --git a/src/riscv_illegal_instr.sv b/src/riscv_illegal_instr.sv index 60ff4b546..48233358b 100644 --- a/src/riscv_illegal_instr.sv +++ b/src/riscv_illegal_instr.sv @@ -213,6 +213,37 @@ class riscv_illegal_instr extends uvm_object; } } + constraint zcb_extension_c { + // zcb adds instructions to the reserved funct6 space 6'b100111 + // this constraint defines the subset of that op-code space which is still + // reserved. Only way to trigger this constraint should be with + // kReservedC0/C1 or by kIllegalCompressedOpcode. Since the reserved + // instructions at c_msb = 3'b100 && c_op = 2'b00 are not added to + // legal_c00_opcode this combination could occur. + if (RV32ZCB inside {supported_isa}) { + if (exception inside {kIllegalCompressedOpcode, kReservedCompressedInstr} + && c_msb == 3'b100) { + if (c_op == 2'b00) { + !(instr_bin[12:10] inside {3'b000, 3'b001, 3'b010, 3'b011}); //load/store + // bits 9:2 don't have any inavlid combinations, hence only bit 12:10 + // can yield an op-code which is reserved. + } else if (c_op == 2'b01 && instr_bin[12:10] == 3'b111) { + // if funct2 = 2'b10 there are no reserved op-codes + !(instr_bin[6:5] inside {2'b10}); //funct2 + if (instr_bin[6:5] == 2'b11) { + if (XLEN == 32){ + // c.zext.w not allowed in 32-bit mode + (instr_bin[4:2] inside {3'b100, 3'b110, 3'b111}); + } else { + // reserved opcodes + (instr_bin[4:2] inside {3'b110, 3'b111}); + } + } + } + } + } + } + constraint illegal_compressed_op_c { if (exception == kIllegalCompressedOpcode) { c_op != 2'b01; diff --git a/src/riscv_instr_cover_group.sv b/src/riscv_instr_cover_group.sv index badc423d6..1b6521216 100644 --- a/src/riscv_instr_cover_group.sv +++ b/src/riscv_instr_cover_group.sv @@ -38,6 +38,7 @@ `define SAMPLE_ZBB(cg, val) `SAMPLE_W_TYPE(cg, val, riscv_zbb_instr) `define SAMPLE_ZBC(cg, val) `SAMPLE_W_TYPE(cg, val, riscv_zbc_instr) `define SAMPLE_ZBS(cg, val) `SAMPLE_W_TYPE(cg, val, riscv_zbs_instr) +`define SAMPLE_ZCB(cg, val) `SAMPLE_W_TYPE(cg, val, riscv_zcb_instr) `define INSTR_CG_BEGIN(INSTR_NAME, INSTR_CLASS = riscv_instr) \ covergroup ``INSTR_NAME``_cg with function sample(INSTR_CLASS instr); @@ -433,6 +434,13 @@ cp_rd : coverpoint instr.rd; \ `DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) \ +`define ZCB_I_INSTR_CG_BEGIN(INSTR_NAME) \ + `INSTR_CG_BEGIN(INSTR_NAME) \ + cp_rs1 : coverpoint instr.rs1 { \ + bins gpr[] = {S0, S1, A0, A1, A2, A3, A4, A5}; \ + } \ + `DV(cp_gpr_hazard : coverpoint instr.gpr_hazard;) + `define B_I_INSTR_CG_BEGIN(INSTR_NAME) \ `INSTR_CG_BEGIN(INSTR_NAME, riscv_b_instr) \ cp_rs1 : coverpoint instr.rs1; \ @@ -1646,6 +1654,44 @@ class riscv_instr_cover_group; `CA_INSTR_CG_BEGIN(c_addw) `CG_END + // RV32ZCB + `CL_INSTR_CG_BEGIN(c_lbu) + `CG_END + + `CL_INSTR_CG_BEGIN(c_lhu) + `CG_END + + `CL_INSTR_CG_BEGIN(c_lh) + `CG_END + + `CS_INSTR_CG_BEGIN(c_sb) + `CG_END + + `CS_INSTR_CG_BEGIN(c_sh) + `CG_END + + // Similar to zbb with the exception of which registers can be used + `ZCB_I_INSTR_CG_BEGIN(c_zext_b) + `CG_END + + `ZCB_I_INSTR_CG_BEGIN(c_sext_b) + `CG_END + + `ZCB_I_INSTR_CG_BEGIN(c_zext_h) + `CG_END + + `ZCB_I_INSTR_CG_BEGIN(c_sext_h) + `CG_END + + `ZCB_I_INSTR_CG_BEGIN(c_not) + `CG_END + + `CA_INSTR_CG_BEGIN(c_mul) + `CG_END + + // RV64ZCB + `ZCB_I_INSTR_CG_BEGIN(c_zext_w) + `CG_END `INSTR_CG_BEGIN(hint) cp_hint : coverpoint instr.binary[15:0] { wildcard bins addi = {16'b0000_1xxx_x000_0001, @@ -2071,6 +2117,20 @@ class riscv_instr_cover_group; bseti_cg = new(); `CG_SELECTOR_END + `CG_SELECTOR_BEGIN(RV32ZCB) + c_lbu_cg = new(); + c_lhu_cg = new(); + c_lh_cg = new(); + c_sb_cg = new(); + c_sh_cg = new(); + c_zext_b_cg = new(); + c_sext_b_cg = new(); + c_zext_h_cg = new(); + c_sext_h_cg = new(); + c_not_cg = new(); + c_mul_cg = new(); + `CG_SELECTOR_END + `CG_SELECTOR_BEGIN(RV32B) pack_cg = new(); packh_cg = new(); @@ -2118,6 +2178,10 @@ class riscv_instr_cover_group; roriw_cg = new(); `CG_SELECTOR_END + `CG_SELECTOR_BEGIN(RV64ZCB) + c_zext_w_cg = new(); + `CG_SELECTOR_END + `CG_SELECTOR_BEGIN(RV64B) packw_cg = new(); packuw_cg = new(); @@ -2396,6 +2460,18 @@ class riscv_instr_cover_group; BINVI : `SAMPLE_ZBS(binvi_cg, instr) BSET : `SAMPLE_ZBS(bset_cg, instr) BSETI : `SAMPLE_ZBS(bseti_cg, instr) + // RV32ZCB + C_LBU : `SAMPLE_ZCB(c_lbu_cg, instr) + C_LHU : `SAMPLE_ZCB(c_lhu_cg, instr) + C_LH : `SAMPLE_ZCB(c_lh_cg, instr) + C_SB : `SAMPLE_ZCB(c_sb_cg, instr) + C_SH : `SAMPLE_ZCB(c_sh_cg, instr) + C_ZEXT_B : `SAMPLE_ZCB(c_zext_b_cg, instr) + C_SEXT_B : `SAMPLE_ZCB(c_sext_b_cg, instr) + C_ZEXT_H : `SAMPLE_ZCB(c_zext_h_cg, instr) + C_SEXT_H : `SAMPLE_ZCB(c_sext_h_cg, instr) + C_NOT : `SAMPLE_ZCB(c_not_cg, instr) + C_MUL : `SAMPLE_ZCB(c_mul_cg, instr) // RV32B PACK : `SAMPLE_B(pack_cg, instr) PACKH : `SAMPLE_B(packh_cg, instr) @@ -2438,6 +2514,8 @@ class riscv_instr_cover_group; ROLW : `SAMPLE_ZBB(rolw_cg, instr) RORW : `SAMPLE_ZBB(rorw_cg, instr) RORIW : `SAMPLE_ZBB(roriw_cg, instr) + // RV64ZCB + C_ZEXT_W : `SAMPLE_ZCB(c_zext_w_cg, instr) // RV64B PACKW : `SAMPLE_B(packw_cg, instr) PACKUW : `SAMPLE_B(packuw_cg, instr) @@ -2544,8 +2622,8 @@ class riscv_instr_cover_group; if ((instr.group inside {supported_isa}) && (instr.group inside {RV32I, RV32M, RV64M, RV64I, RV32C, RV64C, RVV, RV64B, RV32B, - RV32ZBA, RV32ZBB, RV32ZBC, RV32ZBS, - RV64ZBA, RV64ZBB, RV64ZBC, RV64ZBS})) begin + RV32ZBA, RV32ZBB, RV32ZBC, RV32ZBS, RV32ZCB, + RV64ZBA, RV64ZBB, RV64ZBC, RV64ZBS, RV64ZCB})) begin if (((instr_name inside {URET}) && !support_umode_trap) || ((instr_name inside {SRET, SFENCE_VMA}) && !(SUPERVISOR_MODE inside {supported_privileged_mode})) || diff --git a/src/riscv_instr_gen_config.sv b/src/riscv_instr_gen_config.sv index 0712821e5..b5b8e73b9 100644 --- a/src/riscv_instr_gen_config.sv +++ b/src/riscv_instr_gen_config.sv @@ -264,6 +264,7 @@ class riscv_instr_gen_config extends uvm_object; bit enable_zbb_extension; bit enable_zbc_extension; bit enable_zbs_extension; + bit enable_zcb_extension; b_ext_group_t enable_bitmanip_groups[] = {ZBB, ZBS, ZBP, ZBE, ZBF, ZBC, ZBR, ZBM, ZBT, ZB_TMP}; @@ -541,6 +542,7 @@ class riscv_instr_gen_config extends uvm_object; `uvm_field_int(enable_zbb_extension, UVM_DEFAULT) `uvm_field_int(enable_zbc_extension, UVM_DEFAULT) `uvm_field_int(enable_zbs_extension, UVM_DEFAULT) + `uvm_field_int(enable_zcb_extension, UVM_DEFAULT) `uvm_field_int(use_push_data_section, UVM_DEFAULT) `uvm_object_utils_end @@ -611,6 +613,7 @@ class riscv_instr_gen_config extends uvm_object; get_bool_arg_value("+enable_zbb_extension=", enable_zbb_extension); get_bool_arg_value("+enable_zbc_extension=", enable_zbc_extension); get_bool_arg_value("+enable_zbs_extension=", enable_zbs_extension); + get_bool_arg_value("+enable_zcb_extension=", enable_zcb_extension); cmdline_enum_processor #(b_ext_group_t)::get_array_values("+enable_bitmanip_groups=", 1'b0, enable_bitmanip_groups); if(inst.get_arg_value("+boot_mode=", boot_mode_opts)) begin @@ -657,6 +660,11 @@ class riscv_instr_gen_config extends uvm_object; enable_zbs_extension = 0; end + + if (!((RV32ZCB inside {supported_isa}) || + (RV64ZCB inside {supported_isa}))) begin + enable_zcb_extension = 0; + end vector_cfg = riscv_vector_cfg::type_id::create("vector_cfg"); pmp_cfg = riscv_pmp_cfg::type_id::create("pmp_cfg"); pmp_cfg.rand_mode(pmp_cfg.pmp_randomize); diff --git a/src/riscv_instr_pkg.sv b/src/riscv_instr_pkg.sv index 96207667a..df29cfeba 100644 --- a/src/riscv_instr_pkg.sv +++ b/src/riscv_instr_pkg.sv @@ -80,7 +80,7 @@ package riscv_instr_pkg; MACHINE_MODE = 2'b11 } privileged_mode_t; - typedef enum bit [4:0] { + typedef enum bit [5:0] { RV32I, RV64I, RV32M, @@ -108,6 +108,10 @@ package riscv_instr_pkg; RV64ZBB, RV64ZBC, RV64ZBS, + RV32ZCB, + RV64ZCB, + RV32ZMMUL, + RV64ZMMUL, RV32X, RV64X } riscv_instr_group_t; @@ -271,6 +275,20 @@ package riscv_instr_pkg; PACKW, PACKUW, XPERM_W, + // RV32ZCB + C_LBU, + C_LHU, + C_LH, + C_SB, + C_SH, + C_ZEXT_B, + C_SEXT_B, + C_ZEXT_H, + C_SEXT_H, + C_NOT, + C_MUL, + // RV64ZCB instructions + C_ZEXT_W, // RV32M instructions MUL, MULH, @@ -693,6 +711,12 @@ package riscv_instr_pkg; CS_FORMAT, CSS_FORMAT, CIW_FORMAT, + // Zc compressed instruction format + CLB_FORMAT, + CSB_FORMAT, + CLH_FORMAT, + CSH_FORMAT, + CU_FORMAT, // Vector instruction format VSET_FORMAT, VA_FORMAT, @@ -1532,6 +1556,7 @@ package riscv_instr_pkg; typedef class riscv_zbb_instr; typedef class riscv_zbc_instr; typedef class riscv_zbs_instr; + typedef class riscv_zcb_instr; typedef class riscv_b_instr; `include "riscv_instr_gen_config.sv" `include "isa/riscv_instr.sv" @@ -1557,6 +1582,9 @@ package riscv_instr_pkg; `include "isa/rv32zbb_instr.sv" `include "isa/rv32zbc_instr.sv" `include "isa/rv32zbs_instr.sv" + `include "isa/riscv_zcb_instr.sv" + `include "isa/rv32zcb_instr.sv" + `include "isa/rv64zcb_instr.sv" `include "isa/rv32m_instr.sv" `include "isa/rv64a_instr.sv" `include "isa/rv64b_instr.sv" diff --git a/src/riscv_load_store_instr_lib.sv b/src/riscv_load_store_instr_lib.sv index cae087313..d822fd010 100644 --- a/src/riscv_load_store_instr_lib.sv +++ b/src/riscv_load_store_instr_lib.sv @@ -119,19 +119,33 @@ class riscv_load_store_base_instr_stream extends riscv_mem_access_stream; // Generate each load/store instruction virtual function void gen_load_store_instr(); - bit enable_compressed_load_store; + bit enable_compressed_load_store, enable_zcb; riscv_instr instr; randomize_avail_regs(); if ((rs1_reg inside {[S0 : A5], SP}) && !cfg.disable_compressed_instr) begin enable_compressed_load_store = 1; end + if ((RV32C inside {riscv_instr_pkg::supported_isa}) && + (RV32ZCB inside {riscv_instr_pkg::supported_isa} && cfg.enable_zcb_extension)) begin + enable_zcb = 1; + end foreach (addr[i]) begin // Assign the allowed load/store instructions based on address alignment // This is done separately rather than a constraint to improve the randomization performance allowed_instr = {LB, LBU, SB}; + if((offset[i] inside {[0:2]}) && enable_compressed_load_store && + enable_zcb && rs1_reg != SP) begin + `uvm_info(`gfn, "Add ZCB byte load/store to allowed instr", UVM_LOW) + allowed_instr = {C_LBU, C_SB}; + end if (!cfg.enable_unaligned_load_store) begin if (addr[i][0] == 1'b0) begin allowed_instr = {LH, LHU, SH, allowed_instr}; + if(((offset[i] == 0) || (offset[i] == 2)) && enable_compressed_load_store && + enable_zcb && rs1_reg != SP) begin + `uvm_info(`gfn, "Add ZCB half-word load/store to allowed instr", UVM_LOW) + allowed_instr = {C_LHU, C_LH, C_SH}; + end end if (addr[i] % 4 == 0) begin allowed_instr = {LW, SW, allowed_instr}; diff --git a/test/riscv_instr_cov_test.sv b/test/riscv_instr_cov_test.sv index 8d3ceff89..b8f0370c5 100644 --- a/test/riscv_instr_cov_test.sv +++ b/test/riscv_instr_cov_test.sv @@ -133,8 +133,8 @@ class riscv_instr_cov_test extends uvm_test; instr = riscv_instr::get_instr(instr_name); if ((instr.group inside {RV32I, RV32M, RV32C, RV64I, RV64M, RV64C, RV32F, RV64F, RV32D, RV64D, RV32B, RV64B, - RV32ZBA, RV32ZBB, RV32ZBC, RV32ZBS, - RV64ZBA, RV64ZBB, RV64ZBC, RV64ZBS}) && + RV32ZBA, RV32ZBB, RV32ZBC, RV32ZBS, RV32ZCB, + RV64ZBA, RV64ZBB, RV64ZBC, RV64ZBS, RV64ZCB}) && (instr.group inside {supported_isa})) begin assign_trace_info_to_instr(instr); instr.pre_sample();