blob: 0cf2266c76e248bc7d76efee806291b26ef37479 [file] [log] [blame]
/*
* Copyright 2018 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_base extends uvm_object;
rand riscv_instr_group_t group;
rand riscv_instr_format_t format;
rand riscv_instr_category_t category;
rand riscv_instr_name_t instr_name;
rand bit [11:0] csr;
rand riscv_reg_t rs2;
rand riscv_reg_t rs1;
rand riscv_reg_t rd;
rand riscv_fpr_t fs1;
rand riscv_fpr_t fs2;
rand riscv_fpr_t fs3;
rand riscv_fpr_t fd;
rand bit [31:0] imm;
rand imm_t imm_type;
rand bit [4:0] imm_len;
rand bit is_pseudo_instr;
rand bit aq;
rand bit rl;
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 has_rs1;
bit has_rs2;
bit has_rd;
bit has_fs1;
bit has_fs2;
bit has_fs3;
bit has_fd;
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;
`uvm_object_utils(riscv_instr_base)
constraint default_c {
soft is_pseudo_instr == 0;
instr_name != INVALID_INSTR;
}
// Immediate bit length for different instruction format
constraint imm_len_c {
solve imm_type before imm_len;
if(format inside {U_FORMAT, J_FORMAT}) {
imm_len == 20;
}
if(format inside {I_FORMAT, S_FORMAT, B_FORMAT}) {
if(imm_type == UIMM) {
imm_len == 5;
} else {
imm_len == 11;
}
}
if(format inside {CI_FORMAT, CSS_FORMAT}) {
// TODO: gcc compiler seems to not support 6 bits unsigned imm for c.lui,
// hardcoded to 5 bits for now
if(instr_name == C_LUI) {
imm_len == 5;
} else {
imm_len == 6;
}
}
if(format inside {CL_FORMAT, CS_FORMAT}) {
imm_len == 5;
}
if(format inside {CJ_FORMAT}) {
imm_len == 11;
}
if(format inside {CB_FORMAT, CIW_FORMAT}) {
if(instr_name == C_ANDI) {
imm_len == 6;
} else {
imm_len == 8;
}
}
imm_len <= 20;
}
constraint legal_operand_c {
(instr_name == C_LUI) -> (rd != SP);
}
constraint imm_val_c {
if(imm_type inside {NZIMM, NZUIMM}) {
imm != 0;
}
}
constraint aq_rl_c {
aq && rl == 0;
}
// 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}) {
rd != ZERO;
}
if (instr_name == C_JR) {
rs1 != ZERO;
}
if (instr_name inside {C_ADD, C_MV}) {
rs2 != ZERO;
}
}
// Cannot shift more than the width of the bus
constraint shift_imm_val_c {
solve category before imm;
if(category == SHIFT) {
if(group == RV64I) {
// The new instruction in RV64I only handles 32 bits value
imm < 32;
} else {
imm < XLEN;
}
}
}
constraint load_store_c {
if(category inside {LOAD, STORE}) {
rs1 != ZERO; // x0 cannot be used to save the base address
}
}
constraint nop_c {
if(instr_name inside {NOP, C_NOP}) {
rs1 == ZERO;
rs2 == ZERO;
rd == ZERO;
}
}
constraint jal_c {
if (XLEN != 32) {
soft instr_name != C_JAL;
}
}
constraint system_instr_c {
if (category inside {SYSTEM, SYNCH}) {
rd == ZERO;
rs1 == ZERO;
}
}
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;
}
}
//////////// RV32I instructions //////////////
// LOAD instructions
`add_instr(LB, I_FORMAT, LOAD, RV32I)
`add_instr(LH, I_FORMAT, LOAD, RV32I)
`add_instr(LW, I_FORMAT, LOAD, RV32I)
`add_instr(LBU, I_FORMAT, LOAD, RV32I)
`add_instr(LHU, I_FORMAT, LOAD, RV32I)
// STORE instructions
`add_instr(SB, S_FORMAT, STORE, RV32I)
`add_instr(SH, S_FORMAT, STORE, RV32I)
`add_instr(SW, S_FORMAT, STORE, RV32I)
// SHIFT intructions
`add_instr(SLL, R_FORMAT, SHIFT, RV32I)
`add_instr(SLLI, I_FORMAT, SHIFT, RV32I)
`add_instr(SRL, R_FORMAT, SHIFT, RV32I)
`add_instr(SRLI, I_FORMAT, SHIFT, RV32I)
`add_instr(SRA, R_FORMAT, SHIFT, RV32I)
`add_instr(SRAI, I_FORMAT, SHIFT, RV32I)
// ARITHMETIC intructions
`add_instr(ADD, R_FORMAT, ARITHMETIC, RV32I)
`add_instr(ADDI, I_FORMAT, ARITHMETIC, RV32I)
`add_instr(NOP, I_FORMAT, ARITHMETIC, RV32I)
`add_instr(SUB, R_FORMAT, ARITHMETIC, RV32I)
`add_instr(LUI, U_FORMAT, ARITHMETIC, RV32I, UIMM)
`add_instr(AUIPC, U_FORMAT, ARITHMETIC, RV32I, UIMM)
// LOGICAL instructions
`add_instr(XOR, R_FORMAT, LOGICAL, RV32I)
`add_instr(XORI, I_FORMAT, LOGICAL, RV32I)
`add_instr(OR, R_FORMAT, LOGICAL, RV32I)
`add_instr(ORI, I_FORMAT, LOGICAL, RV32I)
`add_instr(AND, R_FORMAT, LOGICAL, RV32I)
`add_instr(ANDI, I_FORMAT, LOGICAL, RV32I)
// COMPARE instructions
`add_instr(SLT, R_FORMAT, COMPARE, RV32I)
`add_instr(SLTI, I_FORMAT, COMPARE, RV32I)
`add_instr(SLTU, R_FORMAT, COMPARE, RV32I)
`add_instr(SLTIU, I_FORMAT, COMPARE, RV32I)
// BRANCH instructions
`add_instr(BEQ, B_FORMAT, BRANCH, RV32I)
`add_instr(BNE, B_FORMAT, BRANCH, RV32I)
`add_instr(BLT, B_FORMAT, BRANCH, RV32I)
`add_instr(BGE, B_FORMAT, BRANCH, RV32I)
`add_instr(BLTU, B_FORMAT, BRANCH, RV32I)
`add_instr(BGEU, B_FORMAT, BRANCH, RV32I)
// JUMP instructions
`add_instr(JAL, J_FORMAT, JUMP, RV32I)
`add_instr(JALR, I_FORMAT, JUMP, RV32I)
// SYNCH instructions
`add_instr(FENCE, I_FORMAT, SYNCH, RV32I)
`add_instr(FENCE_I, I_FORMAT, SYNCH, RV32I)
// SYSTEM instructions
`add_instr(ECALL, I_FORMAT, SYSTEM, RV32I)
`add_instr(EBREAK, I_FORMAT, SYSTEM, RV32I)
`add_instr(URET, I_FORMAT, SYSTEM, RV32I)
`add_instr(SRET, I_FORMAT, SYSTEM, RV32I)
`add_instr(MRET, I_FORMAT, SYSTEM, RV32I)
`add_instr(DRET, I_FORMAT, SYSTEM, RV32I)
`add_instr(WFI, I_FORMAT, INTERRUPT, RV32I)
// CSR instructions
`add_instr(CSRRW, R_FORMAT, CSR, RV32I, UIMM)
`add_instr(CSRRS, R_FORMAT, CSR, RV32I, UIMM)
`add_instr(CSRRC, R_FORMAT, CSR, RV32I, UIMM)
`add_instr(CSRRWI, I_FORMAT, CSR, RV32I, UIMM)
`add_instr(CSRRSI, I_FORMAT, CSR, RV32I, UIMM)
`add_instr(CSRRCI, I_FORMAT, CSR, RV32I, UIMM)
//////////// RV32M instructions //////////////
`add_instr(MUL, R_FORMAT, ARITHMETIC, RV32M)
`add_instr(MULH, R_FORMAT, ARITHMETIC, RV32M)
`add_instr(MULHSU, R_FORMAT, ARITHMETIC, RV32M)
`add_instr(MULHU, R_FORMAT, ARITHMETIC, RV32M)
`add_instr(DIV, R_FORMAT, ARITHMETIC, RV32M)
`add_instr(DIVU, R_FORMAT, ARITHMETIC, RV32M)
`add_instr(REM, R_FORMAT, ARITHMETIC, RV32M)
`add_instr(REMU, R_FORMAT, ARITHMETIC, RV32M)
//////////// RV64M instructions //////////////
`add_instr(MULW, R_FORMAT, ARITHMETIC, RV64M)
`add_instr(DIVW, R_FORMAT, ARITHMETIC, RV64M)
`add_instr(DIVUW, R_FORMAT, ARITHMETIC, RV64M)
`add_instr(REMW, R_FORMAT, ARITHMETIC, RV64M)
`add_instr(REMUW, R_FORMAT, ARITHMETIC, RV64M)
//////////// RV32F instructions //////////////
`add_instr(FLW, I_FORMAT, LOAD, RV32F)
`add_instr(FSW, S_FORMAT, STORE, RV32F)
`add_instr(FMADD_S, R4_FORMAT, ARITHMETIC, RV32F)
`add_instr(FMSUB_S, R4_FORMAT, ARITHMETIC, RV32F)
`add_instr(FNMSUB_S, R4_FORMAT, ARITHMETIC, RV32F)
`add_instr(FNMADD_S, R4_FORMAT, ARITHMETIC, RV32F)
`add_instr(FADD_S, R_FORMAT, ARITHMETIC, RV32F)
`add_instr(FSUB_S, R_FORMAT, ARITHMETIC, RV32F)
`add_instr(FMUL_S, R_FORMAT, ARITHMETIC, RV32F)
`add_instr(FDIV_S, R_FORMAT, ARITHMETIC, RV32F)
`add_instr(FSQRT_S, I_FORMAT, ARITHMETIC, RV32F)
`add_instr(FSGNJ_S, R_FORMAT, ARITHMETIC, RV32F)
`add_instr(FSGNJN_S, R_FORMAT, ARITHMETIC, RV32F)
`add_instr(FSGNJX_S, R_FORMAT, ARITHMETIC, RV32F)
`add_instr(FMIN_S, R_FORMAT, ARITHMETIC, RV32F)
`add_instr(FMAX_S, R_FORMAT, ARITHMETIC, RV32F)
`add_instr(FCVT_W_S, I_FORMAT, ARITHMETIC, RV32F)
`add_instr(FCVT_WU_S, I_FORMAT, ARITHMETIC, RV32F)
`add_instr(FMV_X_W, I_FORMAT, ARITHMETIC, RV32F)
`add_instr(FEQ_S, R_FORMAT, COMPARE, RV32F)
`add_instr(FLT_S, R_FORMAT, COMPARE, RV32F)
`add_instr(FLE_S, R_FORMAT, COMPARE, RV32F)
`add_instr(FCLASS_S, R_FORMAT, ARITHMETIC, RV32F)
`add_instr(FCVT_S_W, I_FORMAT, ARITHMETIC, RV32F)
`add_instr(FCVT_S_WU, I_FORMAT, ARITHMETIC, RV32F)
`add_instr(FMV_W_X, I_FORMAT, ARITHMETIC, RV32F)
///////////// RV64F instruction /////////////////
`add_instr(FCVT_L_S, I_FORMAT, ARITHMETIC, RV64F)
`add_instr(FCVT_LU_S, I_FORMAT, ARITHMETIC, RV64F)
`add_instr(FCVT_S_L, I_FORMAT, ARITHMETIC, RV64F)
`add_instr(FCVT_S_LU, I_FORMAT, ARITHMETIC, RV64F)
//////////// RV32D instructions ////////////////
`add_instr(FLD, I_FORMAT, LOAD, RV32D)
`add_instr(FSD, S_FORMAT, STORE, RV32D)
`add_instr(FMADD_D, R4_FORMAT, ARITHMETIC, RV32D)
`add_instr(FMSUB_D, R4_FORMAT, ARITHMETIC, RV32D)
`add_instr(FNMSUB_D, R4_FORMAT, ARITHMETIC, RV32D)
`add_instr(FNMADD_D, R4_FORMAT, ARITHMETIC, RV32D)
`add_instr(FADD_D, R_FORMAT, ARITHMETIC, RV32D)
`add_instr(FSUB_D, R_FORMAT, ARITHMETIC, RV32D)
`add_instr(FMUL_D, R_FORMAT, ARITHMETIC, RV32D)
`add_instr(FDIV_D, R_FORMAT, ARITHMETIC, RV32D)
`add_instr(FSQRT_D, I_FORMAT, ARITHMETIC, RV32D)
`add_instr(FSGNJ_D, R_FORMAT, ARITHMETIC, RV32D)
`add_instr(FSGNJN_D, R_FORMAT, ARITHMETIC, RV32D)
`add_instr(FSGNJX_D, R_FORMAT, ARITHMETIC, RV32D)
`add_instr(FMIN_D, R_FORMAT, ARITHMETIC, RV32D)
`add_instr(FMAX_D, R_FORMAT, ARITHMETIC, RV32D)
`add_instr(FCVT_S_D, I_FORMAT, ARITHMETIC, RV32D)
`add_instr(FCVT_D_S, I_FORMAT, ARITHMETIC, RV32D)
`add_instr(FEQ_D, R_FORMAT, COMPARE, RV32D)
`add_instr(FLT_D, R_FORMAT, COMPARE, RV32D)
`add_instr(FLE_D, R_FORMAT, COMPARE, RV32D)
`add_instr(FCLASS_D, R_FORMAT, ARITHMETIC, RV32D)
`add_instr(FCVT_W_D, I_FORMAT, ARITHMETIC, RV32D)
`add_instr(FCVT_WU_D, I_FORMAT, ARITHMETIC, RV32D)
`add_instr(FCVT_D_W, I_FORMAT, ARITHMETIC, RV32D)
`add_instr(FCVT_D_WU, I_FORMAT, ARITHMETIC, RV32D)
////////////// RV64D instruction ///////////////
`add_instr(FMV_X_D, I_FORMAT, ARITHMETIC, RV64D)
`add_instr(FMV_D_X, I_FORMAT, ARITHMETIC, RV64D)
`add_instr(FCVT_L_D, I_FORMAT, ARITHMETIC, RV64D)
`add_instr(FCVT_LU_D, I_FORMAT, ARITHMETIC, RV64D)
`add_instr(FCVT_D_L, I_FORMAT, ARITHMETIC, RV64D)
`add_instr(FCVT_D_LU, I_FORMAT, ARITHMETIC, RV64D)
// RV64I instructions
// LOAD/STORE instructions
`add_instr(LWU, I_FORMAT, LOAD, RV64I)
`add_instr(LD, I_FORMAT, LOAD, RV64I)
`add_instr(SD, S_FORMAT, STORE, RV64I)
// SHIFT intructions
`add_instr(SLLW, R_FORMAT, SHIFT, RV64I)
`add_instr(SLLIW, I_FORMAT, SHIFT, RV64I)
`add_instr(SRLW, R_FORMAT, SHIFT, RV64I)
`add_instr(SRLIW, I_FORMAT, SHIFT, RV64I)
`add_instr(SRAW, R_FORMAT, SHIFT, RV64I)
`add_instr(SRAIW, I_FORMAT, SHIFT, RV64I)
// ARITHMETIC intructions
`add_instr(ADDW, R_FORMAT, ARITHMETIC, RV64I)
`add_instr(ADDIW, I_FORMAT, ARITHMETIC, RV64I)
`add_instr(SUBW, R_FORMAT, ARITHMETIC, RV64I)
// RV32IC
`add_instr(C_LW, CL_FORMAT, LOAD, RV32C, UIMM)
`add_instr(C_SW, CS_FORMAT, STORE, RV32C, UIMM)
`add_instr(C_LWSP, CI_FORMAT, LOAD, RV32C, UIMM)
`add_instr(C_SWSP, CSS_FORMAT, STORE, RV32C, UIMM)
`add_instr(C_ADDI4SPN, CIW_FORMAT, ARITHMETIC, RV32C, NZUIMM)
`add_instr(C_ADDI, CI_FORMAT, ARITHMETIC, RV32C, NZIMM)
`add_instr(C_ADDI16SP, CI_FORMAT, ARITHMETIC, RV32C, NZIMM)
`add_instr(C_LI, CI_FORMAT, ARITHMETIC, RV32C)
`add_instr(C_LUI, CI_FORMAT, ARITHMETIC, RV32C, NZUIMM)
`add_instr(C_SUB, CA_FORMAT, ARITHMETIC, RV32C)
`add_instr(C_ADD, CR_FORMAT, ARITHMETIC, RV32C)
`add_instr(C_NOP, CI_FORMAT, ARITHMETIC, RV32C)
`add_instr(C_MV, CR_FORMAT, ARITHMETIC, RV32C)
`add_instr(C_ANDI, CB_FORMAT, LOGICAL, RV32C)
`add_instr(C_XOR, CA_FORMAT, LOGICAL, RV32C)
`add_instr(C_OR, CA_FORMAT, LOGICAL, RV32C)
`add_instr(C_AND, CA_FORMAT, LOGICAL, RV32C)
`add_instr(C_BEQZ, CB_FORMAT, BRANCH, RV32C)
`add_instr(C_BNEZ, CB_FORMAT, BRANCH, RV32C)
`add_instr(C_SRLI, CB_FORMAT, SHIFT, RV32C, NZUIMM)
`add_instr(C_SRAI, CB_FORMAT, SHIFT, RV32C, NZUIMM)
`add_instr(C_SLLI, CI_FORMAT, SHIFT, RV32C, NZUIMM)
`add_instr(C_J, CJ_FORMAT, JUMP, RV32C)
`add_instr(C_JAL, CJ_FORMAT, JUMP, RV32C)
`add_instr(C_JR, CR_FORMAT, JUMP, RV32C)
`add_instr(C_JALR, CR_FORMAT, JUMP, RV32C)
`add_instr(C_EBREAK, CI_FORMAT, SYSTEM, RV32C)
// RV64C
`add_instr(C_ADDIW, CI_FORMAT, ARITHMETIC, RV64C)
`add_instr(C_SUBW, CA_FORMAT, ARITHMETIC, RV64C)
`add_instr(C_ADDW, CA_FORMAT, ARITHMETIC, RV64C)
`add_instr(C_LD, CL_FORMAT, LOAD, RV64C, UIMM)
`add_instr(C_SD, CS_FORMAT, STORE, RV64C, UIMM)
`add_instr(C_LDSP, CI_FORMAT, LOAD, RV64C, UIMM)
`add_instr(C_SDSP, CSS_FORMAT, STORE, RV64C, UIMM)
// RV128C
`add_instr(C_SRLI64, CB_FORMAT, SHIFT, RV128C, NZUIMM)
`add_instr(C_SRAI64, CB_FORMAT, SHIFT, RV128C, NZUIMM)
`add_instr(C_SLLI64, CI_FORMAT, SHIFT, RV128C, NZUIMM)
`add_instr(C_LQ, CL_FORMAT, LOAD, RV32DC, UIMM)
`add_instr(C_SQ, CS_FORMAT, STORE, RV32DC, UIMM)
`add_instr(C_LQSP, CI_FORMAT, LOAD, RV32DC, UIMM)
`add_instr(C_SQSP, CSS_FORMAT, STORE, RV32DC, UIMM)
// RV32FC
`add_instr(C_FLW, CL_FORMAT, LOAD, RV32FC, UIMM)
`add_instr(C_FSW, CS_FORMAT, STORE, RV32FC, UIMM)
`add_instr(C_FLWSP, CI_FORMAT, LOAD, RV32FC, UIMM)
`add_instr(C_FSWSP, CSS_FORMAT, STORE, RV32FC, UIMM)
// RV32DC
`add_instr(C_FLD, CL_FORMAT, LOAD, RV32DC, UIMM)
`add_instr(C_FSD, CS_FORMAT, STORE, RV32DC, UIMM)
`add_instr(C_FLDSP, CI_FORMAT, LOAD, RV32DC, UIMM)
`add_instr(C_FSDSP, CSS_FORMAT, STORE, RV32DC, UIMM)
// RV32A
`add_instr(LR_W, R_FORMAT, LOAD, RV32A)
`add_instr(SC_W, R_FORMAT, STORE, RV32A)
`add_instr(AMOSWAP_W, R_FORMAT, AMO, RV32A)
`add_instr(AMOADD_W, R_FORMAT, AMO, RV32A)
`add_instr(AMOAND_W, R_FORMAT, AMO, RV32A)
`add_instr(AMOOR_W, R_FORMAT, AMO, RV32A)
`add_instr(AMOXOR_W, R_FORMAT, AMO, RV32A)
`add_instr(AMOMIN_W, R_FORMAT, AMO, RV32A)
`add_instr(AMOMAX_W, R_FORMAT, AMO, RV32A)
`add_instr(AMOMINU_W, R_FORMAT, AMO, RV32A)
`add_instr(AMOMAXU_W, R_FORMAT, AMO, RV32A)
// RV64A
`add_instr(LR_D, R_FORMAT, LOAD, RV64A)
`add_instr(SC_D, R_FORMAT, STORE, RV64A)
`add_instr(AMOSWAP_D, R_FORMAT, AMO, RV64A)
`add_instr(AMOADD_D, R_FORMAT, AMO, RV64A)
`add_instr(AMOAND_D, R_FORMAT, AMO, RV64A)
`add_instr(AMOOR_D, R_FORMAT, AMO, RV64A)
`add_instr(AMOXOR_D, R_FORMAT, AMO, RV64A)
`add_instr(AMOMIN_D, R_FORMAT, AMO, RV64A)
`add_instr(AMOMAX_D, R_FORMAT, AMO, RV64A)
`add_instr(AMOMINU_D, R_FORMAT, AMO, RV64A)
`add_instr(AMOMAXU_D, R_FORMAT, AMO, RV64A)
// Supervisor Instructions
`add_instr(SFENCE_VMA, R_FORMAT,SYNCH,RV32I)
function void post_randomize();
if (group inside {RV32C, RV64C, RV128C, RV32DC, RV32FC}) begin
is_compressed = 1'b1;
end
if (!(format inside {R_FORMAT, CR_FORMAT})) begin
imm_mask = '1;
imm_mask = imm_mask << imm_len;
has_imm = 1'b1;
mask_imm();
if (imm_str == "") begin
update_imm_str();
end
end
if (format inside {R_FORMAT, S_FORMAT, B_FORMAT, CSS_FORMAT,
CS_FORMAT, CR_FORMAT, CA_FORMAT}) begin
has_rs2 = 1'b1;
end
if (!(format inside {J_FORMAT, U_FORMAT, CJ_FORMAT, CSS_FORMAT,
CA_FORMAT, CR_FORMAT, CI_FORMAT})) begin
has_rs1 = 1'b1;
end else if (instr_name inside {C_JR, C_JALR}) begin
has_rs1 = 1'b1;
end
if (!(format inside {CJ_FORMAT, CB_FORMAT, CS_FORMAT, CSS_FORMAT, B_FORMAT, S_FORMAT})) begin
has_rd = 1'b1;
end
if (category == CSR) begin
has_rs2 = 1'b0;
if (instr_name inside {CSRRWI, CSRRSI, CSRRCI}) begin
has_rs1 = 1'b0;
end
end
// TODO(taliu) Add support for compressed floating point format
if (group inside {RV32F, RV64F, RV32D, RV64D, RV32FC, RV32DC}) begin
is_floating_point = 1'b1;
has_rs1 = 1'b0;
has_rs2 = 1'b0;
has_rd = 1'b0;
has_fs1 = 1'b1;
if (format == R4_FORMAT) begin
has_fs3 = 1'b1;
end
if (format != S_FORMAT) begin
if ((category == COMPARE) || (instr_name inside {FCLASS_S, FCLASS_D})) begin
has_rd = 1'b1;
end else begin
has_fd = 1'b1;
end
end
if (format != I_FORMAT) begin
has_fs2 = 1'b1;
end
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
// Floating point to integer operation
has_rd = 1'b1;
has_fs1 = 1'b1;
has_fd = 1'b0;
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, FLW, FLD, FSW, FSD,
C_FLW, C_FLD, C_FSW, C_FSD}) begin
// Integer to floating point operation
has_fd = 1'b1;
has_fs1 = 1'b0;
has_rs1 = 1'b1;
end
end
endfunction
function void mask_imm();
// Process the immediate value and sign extension
if (imm_type inside {UIMM, NZUIMM}) begin
imm = imm & ~imm_mask;
end else begin
if (imm[imm_len-1]) begin
imm = imm | imm_mask;
end else begin
imm = imm & ~imm_mask;
end
end
// Give a random value if imm is zero after masking unexpectedly
if((imm_type inside {NZIMM, NZUIMM}) && (imm == '0)) begin
imm = $urandom_range(2 ** (imm_len-1) - 1, 1);
end
endfunction
function void gen_rand_imm();
if (!randomize(imm)) begin
`uvm_fatal(`gfn, "Cannot randomize imm")
end
mask_imm();
update_imm_str();
endfunction
function void update_imm_str();
imm_str = $sformatf("%0d", $signed(imm));
endfunction
function void set_imm(int imm);
this.imm = imm;
mask_imm();
update_imm_str();
endfunction
function riscv_reg_t gen_rand_gpr(riscv_reg_t included_reg[] = {},
riscv_reg_t excluded_reg[] = {});
riscv_reg_t gpr;
int unsigned i;
riscv_reg_t legal_gpr[$];
if (included_reg.size() > 0) begin
legal_gpr = included_reg;
if (is_compressed && !(format inside {CR_FORMAT, CI_FORMAT, CSS_FORMAT})) begin
while (i < legal_gpr.size()) begin
if (legal_gpr[i] < S0 || legal_gpr[i] > A5) begin
legal_gpr.delete(i);
end else begin
i++;
end
end
end
end else if (is_compressed &&
!(format inside {CR_FORMAT, CI_FORMAT, CSS_FORMAT})) begin
legal_gpr = riscv_instr_pkg::compressed_gpr;
end else begin
legal_gpr = riscv_instr_pkg::all_gpr;
end
if (format inside {CR_FORMAT, CI_FORMAT}) begin
excluded_reg = {excluded_reg, ZERO};
end
if (excluded_reg.size() > 0) begin
i = 0;
while (i < legal_gpr.size()) begin
if (legal_gpr[i] inside {excluded_reg}) begin
legal_gpr.delete(i);
end else begin
i++;
end
end
end
`DV_CHECK_FATAL(legal_gpr.size() > 0)
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(i, i < legal_gpr.size();)
gpr = legal_gpr[i];
return gpr;
endfunction
function riscv_fpr_t gen_rand_fpr(riscv_fpr_t excluded_reg[] = {});
riscv_fpr_t fpr;
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(fpr,
if (excluded_reg.size() > 0) {
!(fpr inside {excluded_reg});
}
if (is_compressed) {
fpr inside {[F8:F15]};
});
return fpr;
endfunction
function void gen_rand_csr(bit illegal_csr_instr = 0,
bit enable_floating_point = 0,
privileged_mode_t privileged_mode = MACHINE_MODE);
privileged_reg_t preg[$];
if (illegal_csr_instr) begin
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(csr, !(csr inside {implemented_csr});)
end else begin
// Use scratch register to avoid the side effect of modifying other privileged mode CSR.
if (privileged_mode == MACHINE_MODE)
preg = {MSCRATCH};
else if (privileged_mode == SUPERVISOR_MODE)
preg = {SSCRATCH};
else
preg = {USCRATCH};
if (enable_floating_point) begin
preg = {preg, FFLAGS, FRM, FCSR};
`DV_CHECK_STD_RANDOMIZE_WITH_FATAL(csr, csr inside {preg};)
end else begin
csr = preg[0];
end
end
endfunction
function new(string name = "");
super.new(name);
endfunction
// Convert the instruction to one-liner print message
virtual function string convert2string();
return convert2asm();
endfunction
virtual function void do_print (uvm_printer printer);
`uvm_info(get_type_name(), convert2string(), UVM_LOW)
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);
if (is_floating_point) begin
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
end else if((category != SYSTEM) && !(group inside {RV32A, RV64A})) 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 == C_NOP)
asm_str = "c.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
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
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:
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 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
// 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 else 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
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
// Get opcode for compressed instruction
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
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;
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;
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;
if (!is_compressed) begin
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
end else begin
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
end
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 == 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 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
// Copy the rand fields of the base instruction
virtual function void copy_base_instr(riscv_instr_base obj);
this.group = obj.group;
this.format = obj.format;
this.category = obj.category;
this.instr_name = obj.instr_name;
this.rs2 = obj.rs2;
this.rs1 = obj.rs1;
this.rd = obj.rd;
this.imm = obj.imm;
this.imm_type = obj.imm_type;
this.imm_len = obj.imm_len;
this.imm_mask = obj.imm_mask;
this.imm_str = obj.imm_str;
this.is_pseudo_instr = obj.is_pseudo_instr;
this.aq = obj.aq;
this.rl = obj.rl;
this.is_compressed = obj.is_compressed;
this.has_imm = obj.has_imm;
this.has_rs1 = obj.has_rs1;
this.has_rs2 = obj.has_rs2;
this.has_rd = obj.has_rd;
this.fs3 = obj.fs3;
this.fs2 = obj.fs2;
this.fs1 = obj.fs1;
this.fd = obj.fd;
this.has_fs1 = obj.has_fs1;
this.has_fs2 = obj.has_fs2;
this.has_fs3 = obj.has_fs3;
this.has_fd = obj.has_fd;
this.is_floating_point = obj.is_floating_point;
endfunction
endclass
// Psuedo instructions are used to simplify assembly program writing
class riscv_pseudo_instr extends riscv_instr_base;
rand riscv_pseudo_instr_name_t pseudo_instr_name;
constraint default_c {
is_pseudo_instr == 1'b1;
}
`add_pseudo_instr(LI, I_FORMAT, LOAD, RV32I)
`add_pseudo_instr(LA, I_FORMAT, LOAD, RV32I)
`uvm_object_utils(riscv_pseudo_instr)
function new(string name = "");
super.new(name);
process_load_store = 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);
// instr rd,imm
asm_str = $sformatf("%0s%0s, %0s", asm_str, rd.name(), get_imm());
if(comment != "")
asm_str = {asm_str, " #",comment};
return asm_str.tolower();
endfunction
virtual function string get_instr_name();
return pseudo_instr_name.name();
endfunction
endclass