>----------------
Status and outlook:
For RV64GC, out of 229 standard ISA tests, 202 PASS, 27 FAIL.
Below is a list of current failures, current diagnoses, and outlook.
'C' instructions:
rv64uc-v-rvc
Diagnosis: error in saved regs during instruction page fault
when a 32-bit instruction straddles a page boundary and
the second 16-bits encounters a page fault.
Note: the corresponding rv64uc-p-rvc passes, containing
the same set of tests except for the virtual-memory
aspect, so we expect this test to pass once this issue is
fixed.
Outlook: Target date for fix: 2019-Apr-09 (today)
System instructions:
rv64mi-p-access
rv64mi-p-csr
rv64si-p-dirty
rv64mi-p-illegal
Diagnosis: we do not have accurate diagnoses yet, although
some symptoms look similar to what we saw with earlier
processors (these test various corner-cases of system
instructions).
Outlook: Target date for fix: 2019-Apr-15
'F' and 'D' instructions
rv64uf-p-fadd rv64uf-v-fadd
rv64uf-p-fcmp rv64uf-v-fcmp
rv64uf-p-fdiv rv64uf-v-fdiv
rv64uf-p-fmin rv64uf-v-fmin
rv64ud-p-fadd rv64ud-v-fadd
rv64ud-p-fcmp rv64ud-v-fcmp
rv64ud-p-fdiv rv64ud-v-fdiv
rv64ud-p-fmadd rv64ud-v-fmadd
rv64ud-p-fmin rv64ud-v-fmin
rv64ud-p-ldst rv64ud-v-ldst
rv64ud-p-move rv64ud-v-move
Diagnosis: These seem to be simulation-only errors. Simulation
uses some quick-and-dirty floating-point "model" modules
written by the MIT authors, which are not accurate. All
the errors seem to be regarding incomplete treatment of
NaNs in the models. These errors should not happen in
FPGA since those use Xilinx IP modules instead. MIT has
been booting Linux with the Xilinx IP modules, lending
more confidence in the FPGA version.
The actual number of root-cause failures is likely to be
smaller than the list. For example, the 'fadd' test has
four variants: {uf/ud} x {-p-/-v-}; they all likely need a
comon fix.
Outlook: Target date: 2019-Apr-30
[Lower priority, since FPGA versions should be ok even now.]
>----------------
Detailed comments on file changes
New files:
Doc/micro2018.pdf
MIT's paper on RISCY-OOO at IEEE Micro
src_Core/CPU/CPU_Decode_C.bsv
Function to expand 'C' instrs to 32-bit counterparts, taken from Piccolo/Flute
Modified files:
src_Core/CPU/Core.bsv
Added rob_getOrig_Inst method
src_Core/RISCY_OOO/procs/RV64G_OOO/AluExePipeline.bsv
Added 'orig_inst' stuff, $displays
src_Core/RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv
Mostly verbosity stuff, including printing out brief instruction trace similar to Piccolo/Flute.
src_Core/RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv
Major changes for 'C', including call to Decode_C function from Piccolo/Flute
Pass orig_inst to downpipe.
src_Core/RISCY_OOO/procs/RV64G_OOO/RenameStage.bsv
Added 'orig_inst', input from FetchStage and passed on to ROB
Tweaked PC+4 check to accommodate 'C' instructions.
src_Core/RISCY_OOO/procs/lib/BrPred.bsv
Fixed 'decodeBrPred' to accommodate 'C' instructions
src_Core/RISCY_OOO/procs/lib/Exec.bsv
Fixed 'brAddrCalc', 'getControlFlow', 'basicExec' to acommodate 'C' instructions
src_Core/RISCY_OOO/procs/lib/MemLoader.bsv
Switched off 'verbose' by default
src_Core/RISCY_OOO/procs/lib/ProcTypes.bsv
Added 'C' to MISA, 'getExtensionBits'
src_Core/RISCY_OOO/procs/lib/ReorderBuffer.bsv
Added 'orig_inst' register to basic cell, and methods to set/access.
src_Core/RISCY_OOO/procs/lib/Types.bsv
Added typedefs for 'C' instructions
>----------------
1131 lines
38 KiB
Plaintext
1131 lines
38 KiB
Plaintext
// Copyright (c) 2016-2019 Bluespec, Inc. All Rights Reserved
|
|
|
|
package CPU_Decode_C;
|
|
|
|
// ================================================================
|
|
// fv_decode_C() is a function that decodes and expands a 16-bit
|
|
// "compressed" RISC-V instruction ('C' extension) into its full
|
|
// 32-bit equivalent.
|
|
|
|
// ================================================================
|
|
// Exports
|
|
|
|
export fv_decode_C;
|
|
|
|
// ================================================================
|
|
// BSV library imports
|
|
|
|
// None
|
|
|
|
// ----------------
|
|
// BSV additional libs
|
|
|
|
// None
|
|
|
|
// ================================================================
|
|
// Project imports
|
|
|
|
import ISA_Decls :: *;
|
|
|
|
// ================================================================
|
|
|
|
function Instr fv_decode_C (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
// ----------------
|
|
// Try each possible C instruction
|
|
match { .valid_C_LWSP, .i_C_LWSP } = fv_decode_C_LWSP (misa, xl, instr_C);
|
|
match { .valid_C_SWSP, .i_C_SWSP } = fv_decode_C_SWSP (misa, xl, instr_C);
|
|
match { .valid_C_LW, .i_C_LW } = fv_decode_C_LW (misa, xl, instr_C);
|
|
match { .valid_C_SW, .i_C_SW } = fv_decode_C_SW (misa, xl, instr_C);
|
|
|
|
match { .valid_C_J, .i_C_J } = fv_decode_C_J (misa, xl, instr_C);
|
|
match { .valid_C_JAL, .i_C_JAL } = fv_decode_C_JAL (misa, xl, instr_C);
|
|
match { .valid_C_JR, .i_C_JR } = fv_decode_C_JR (misa, xl, instr_C);
|
|
match { .valid_C_JALR, .i_C_JALR } = fv_decode_C_JALR (misa, xl, instr_C);
|
|
match { .valid_C_BEQZ, .i_C_BEQZ } = fv_decode_C_BEQZ (misa, xl, instr_C);
|
|
match { .valid_C_BNEZ, .i_C_BNEZ } = fv_decode_C_BNEZ (misa, xl, instr_C);
|
|
match { .valid_C_LI, .i_C_LI } = fv_decode_C_LI (misa, xl, instr_C);
|
|
match { .valid_C_LUI, .i_C_LUI } = fv_decode_C_LUI (misa, xl, instr_C);
|
|
match { .valid_C_ADDI, .i_C_ADDI } = fv_decode_C_ADDI (misa, xl, instr_C);
|
|
match { .valid_C_NOP, .i_C_NOP } = fv_decode_C_NOP (misa, xl, instr_C);
|
|
match { .valid_C_ADDIW, .i_C_ADDIW } = fv_decode_C_ADDIW (misa, xl, instr_C);
|
|
match { .valid_C_ADDI16SP, .i_C_ADDI16SP } = fv_decode_C_ADDI16SP (misa, xl, instr_C);
|
|
match { .valid_C_ADDI4SPN, .i_C_ADDI4SPN } = fv_decode_C_ADDI4SPN (misa, xl, instr_C);
|
|
match { .valid_C_SLLI, .i_C_SLLI } = fv_decode_C_SLLI (misa, xl, instr_C);
|
|
match { .valid_C_SRLI, .i_C_SRLI } = fv_decode_C_SRLI (misa, xl, instr_C);
|
|
match { .valid_C_SRAI, .i_C_SRAI } = fv_decode_C_SRAI (misa, xl, instr_C);
|
|
match { .valid_C_ANDI, .i_C_ANDI } = fv_decode_C_ANDI (misa, xl, instr_C);
|
|
match { .valid_C_MV, .i_C_MV } = fv_decode_C_MV (misa, xl, instr_C);
|
|
match { .valid_C_ADD, .i_C_ADD } = fv_decode_C_ADD (misa, xl, instr_C);
|
|
match { .valid_C_AND, .i_C_AND } = fv_decode_C_AND (misa, xl, instr_C);
|
|
match { .valid_C_OR, .i_C_OR } = fv_decode_C_OR (misa, xl, instr_C);
|
|
match { .valid_C_XOR, .i_C_XOR } = fv_decode_C_XOR (misa, xl, instr_C);
|
|
match { .valid_C_SUB, .i_C_SUB } = fv_decode_C_SUB (misa, xl, instr_C);
|
|
match { .valid_C_ADDW, .i_C_ADDW } = fv_decode_C_ADDW (misa, xl, instr_C);
|
|
match { .valid_C_SUBW, .i_C_SUBW } = fv_decode_C_SUBW (misa, xl, instr_C);
|
|
match { .valid_C_EBREAK, .i_C_EBREAK } = fv_decode_C_EBREAK (misa, xl, instr_C);
|
|
|
|
`ifdef RV64
|
|
match { .valid_C_LDSP, .i_C_LDSP } = fv_decode_C_LDSP (misa, xl, instr_C);
|
|
match { .valid_C_SDSP, .i_C_SDSP } = fv_decode_C_SDSP (misa, xl, instr_C);
|
|
match { .valid_C_LD, .i_C_LD } = fv_decode_C_LD (misa, xl, instr_C);
|
|
match { .valid_C_SD, .i_C_SD } = fv_decode_C_SD (misa, xl, instr_C);
|
|
`endif
|
|
|
|
`ifdef RV128
|
|
match { .valid_C_LQSP, .i_C_LQSP } = fv_decode_C_LQSP (misa, xl, instr_C);
|
|
match { .valid_C_SQSP, .i_C_SQSP } = fv_decode_C_SQSP (misa, xl, instr_C);
|
|
match { .valid_C_LQ, .i_C_LQ } = fv_decode_C_LQ (misa, xl, instr_C);
|
|
match { .valid_C_SQ, .i_C_SQ } = fv_decode_C_SQ (misa, xl, instr_C);
|
|
`endif
|
|
|
|
`ifdef ISA_F
|
|
match { .valid_C_FLWSP, .i_C_FLWSP } = fv_decode_C_FLWSP (misa, xl, instr_C);
|
|
match { .valid_C_FSWSP, .i_C_FSWSP } = fv_decode_C_FSWSP (misa, xl, instr_C);
|
|
match { .valid_C_FLW, .i_C_FLW } = fv_decode_C_FLW (misa, xl, instr_C);
|
|
match { .valid_C_FSW, .i_C_FSW } = fv_decode_C_FSW (misa, xl, instr_C);
|
|
`endif
|
|
|
|
`ifdef ISA_D
|
|
match { .valid_C_FLDSP, .i_C_FLDSP } = fv_decode_C_FLDSP (misa, xl, instr_C);
|
|
match { .valid_C_FSDSP, .i_C_FSDSP } = fv_decode_C_FSDSP (misa, xl, instr_C);
|
|
match { .valid_C_FLD, .i_C_FLD } = fv_decode_C_FLD (misa, xl, instr_C);
|
|
match { .valid_C_FSD, .i_C_FSD } = fv_decode_C_FSD (misa, xl, instr_C);
|
|
`endif
|
|
|
|
// ----------------
|
|
// Pick the one (if any) that decodes
|
|
|
|
Instr instr = ?;
|
|
|
|
if (valid_C_LWSP) instr = i_C_LWSP;
|
|
else if (valid_C_SWSP) instr = i_C_SWSP;
|
|
else if (valid_C_LW) instr = i_C_LW;
|
|
else if (valid_C_SW) instr = i_C_SW;
|
|
|
|
else if (valid_C_J) instr = i_C_J;
|
|
else if (valid_C_JAL) instr = i_C_JAL;
|
|
else if (valid_C_JR) instr = i_C_JR;
|
|
else if (valid_C_JALR) instr = i_C_JALR;
|
|
else if (valid_C_BEQZ) instr = i_C_BEQZ;
|
|
else if (valid_C_BNEZ) instr = i_C_BNEZ;
|
|
else if (valid_C_LI) instr = i_C_LI;
|
|
else if (valid_C_LUI) instr = i_C_LUI;
|
|
else if (valid_C_ADDI) instr = i_C_ADDI;
|
|
else if (valid_C_NOP) instr = i_C_NOP;
|
|
else if (valid_C_ADDIW) instr = i_C_ADDIW;
|
|
else if (valid_C_ADDI16SP) instr = i_C_ADDI16SP;
|
|
else if (valid_C_ADDI4SPN) instr = i_C_ADDI4SPN;
|
|
else if (valid_C_SLLI) instr = i_C_SLLI;
|
|
else if (valid_C_SRLI) instr = i_C_SRLI;
|
|
else if (valid_C_SRAI) instr = i_C_SRAI;
|
|
else if (valid_C_ANDI) instr = i_C_ANDI;
|
|
else if (valid_C_MV) instr = i_C_MV;
|
|
else if (valid_C_ADD) instr = i_C_ADD;
|
|
else if (valid_C_AND) instr = i_C_AND;
|
|
else if (valid_C_OR) instr = i_C_OR;
|
|
else if (valid_C_XOR) instr = i_C_XOR;
|
|
else if (valid_C_SUB) instr = i_C_SUB;
|
|
else if (valid_C_ADDW) instr = i_C_ADDW;
|
|
else if (valid_C_SUBW) instr = i_C_SUBW;
|
|
else if (valid_C_EBREAK) instr = i_C_EBREAK;
|
|
|
|
`ifdef RV64
|
|
else if (valid_C_LDSP) instr = i_C_LDSP;
|
|
else if (valid_C_SDSP) instr = i_C_SDSP;
|
|
else if (valid_C_LD) instr = i_C_LD;
|
|
else if (valid_C_SD) instr = i_C_SD;
|
|
`endif
|
|
|
|
`ifdef RV128
|
|
else if (valid_C_LQSP) instr = i_C_LQSP;
|
|
else if (valid_C_SQSP) instr = i_C_SQSP;
|
|
else if (valid_C_LQ) instr = i_C_LQ;
|
|
else if (valid_C_SQ) instr = i_C_SQ;
|
|
`endif
|
|
|
|
`ifdef ISA_F
|
|
else if (valid_C_FLWSP) instr = i_C_FLWSP;
|
|
else if (valid_C_FSWSP) instr = i_C_FSWSP;
|
|
else if (valid_C_FLW) instr = i_C_FLW;
|
|
else if (valid_C_FSW) instr = i_C_FSW;
|
|
`endif
|
|
|
|
`ifdef ISA_D
|
|
else if (valid_C_FLDSP) instr = i_C_FLDSP;
|
|
else if (valid_C_FSDSP) instr = i_C_FSDSP;
|
|
else if (valid_C_FLD) instr = i_C_FLD;
|
|
else if (valid_C_FSD) instr = i_C_FSD;
|
|
`endif
|
|
|
|
else
|
|
instr = illegal_instr;
|
|
|
|
return instr;
|
|
endfunction
|
|
|
|
// ================================================================
|
|
// 'C' Extension Stack-Pointer-Based Loads
|
|
|
|
// LWSP: expands into LW
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_LWSP (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: I-type
|
|
match { .funct3, .imm_at_12, .rd, .imm_at_6_2, .op } = fv_ifields_CI_type (instr_C);
|
|
Bit #(8) offset = { imm_at_6_2 [1:0], imm_at_12, imm_at_6_2 [4:2], 2'b0};
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C2)
|
|
&& (rd != 0)
|
|
&& (funct3 == funct3_C_LWSP));
|
|
|
|
RegName rs1 = reg_sp;
|
|
let instr = mkInstr_I_type (zeroExtend (offset), rs1, f3_LW, rd, op_LOAD);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
`ifdef RV64
|
|
// LDSP: expands into LD
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_LDSP (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: I-type
|
|
match { .funct3, .imm_at_12, .rd, .imm_at_6_2, .op } = fv_ifields_CI_type (instr_C);
|
|
Bit #(9) offset = { imm_at_6_2 [2:0], imm_at_12, imm_at_6_2 [4:3], 3'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C2)
|
|
&& (rd != 0)
|
|
&& (funct3 == funct3_C_LDSP)
|
|
&& ( (xl == misa_mxl_64)
|
|
|| (xl == misa_mxl_128)));
|
|
|
|
RegName rs1 = reg_sp;
|
|
let instr = mkInstr_I_type (zeroExtend (offset), rs1, f3_LD, rd, op_LOAD);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
`endif
|
|
|
|
`ifdef RV128
|
|
// LQSP: expands into LQ
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_LQSP (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: I-type
|
|
match { .funct3, .imm_at_12, .rd, .imm_at_6_2, .op } = fv_ifields_CI_type (instr_C);
|
|
Bit #(10) offset = { imm_at_6_2 [3:0], imm_at_12, imm_at_6_2 [4], 4'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C2)
|
|
&& (rd != 0)
|
|
&& (funct3 == funct3_C_LQSP)
|
|
&& (xl == misa_mxl_128));
|
|
|
|
RegName rs1 = reg_sp;
|
|
let instr = mkInstr_I_type (zeroExtend (offset), rs1, f3_LQ, rd, op_LOAD);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
`endif
|
|
|
|
`ifdef ISA_F
|
|
// FLWSP: expands into FLW
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_FLWSP (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: I-type
|
|
match { .funct3, .imm_at_12, .rd, .imm_at_6_2, .op } = fv_ifields_CI_type (instr_C);
|
|
Bit #(8) offset = { imm_at_6_2 [1:0], imm_at_12, imm_at_6_2 [4:2], 2'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C2)
|
|
&& (rd != 0)
|
|
&& (funct3 == funct3_C_FLWSP)
|
|
&& (misa.f == 1'b1));
|
|
|
|
RegName rs1 = reg_sp;
|
|
let instr = mkInstr_I_type (zeroExtend (offset), rs1, f3_FLW, rd, op_LOAD_FP);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
`endif
|
|
|
|
`ifdef ISA_D
|
|
// FLDSP: expands into FLD
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_FLDSP (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: I-type
|
|
match { .funct3, .imm_at_12, .rd, .imm_at_6_2, .op } = fv_ifields_CI_type (instr_C);
|
|
Bit #(9) offset = { imm_at_6_2 [2:0], imm_at_12, imm_at_6_2 [4:3], 3'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C2)
|
|
&& (rd != 0)
|
|
&& (funct3 == funct3_C_FLDSP)
|
|
&& (misa.d == 1'b1)
|
|
&& ( (xl == misa_mxl_64)
|
|
|| (xl == misa_mxl_128)));
|
|
|
|
RegName rs1 = reg_sp;
|
|
let instr = mkInstr_I_type (zeroExtend (offset), rs1, f3_FLD, rd, op_LOAD_FP);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
`endif
|
|
|
|
// ================================================================
|
|
// 'C' Extension Stack-Pointer-Based Stores
|
|
|
|
// SWSP: expands to SW
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_SWSP (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CSS-type
|
|
match { .funct3, .imm_at_12_7, .rs2, .op } = fv_ifields_CSS_type (instr_C);
|
|
Bit #(8) offset = { imm_at_12_7 [1:0], imm_at_12_7 [5:2], 2'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C2)
|
|
&& (funct3 == funct3_C_SWSP));
|
|
|
|
RegName rs1 = reg_sp;
|
|
let instr = mkInstr_S_type (zeroExtend (offset), rs2, rs1, f3_SW, op_STORE);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
`ifdef RV64
|
|
// SDSP: expands to SD
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_SDSP (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CSS-type
|
|
match { .funct3, .imm_at_12_7, .rs2, .op } = fv_ifields_CSS_type (instr_C);
|
|
Bit #(9) offset = { imm_at_12_7 [2:0], imm_at_12_7 [5:3], 3'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C2)
|
|
&& (funct3 == funct3_C_SDSP)
|
|
&& ( (xl == misa_mxl_64)
|
|
|| (xl == misa_mxl_128)));
|
|
|
|
RegName rs1 = reg_sp;
|
|
let instr = mkInstr_S_type (zeroExtend (offset), rs2, rs1, f3_SD, op_STORE);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
`endif
|
|
|
|
`ifdef RV128
|
|
// SQSP: expands to SQ
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_SQSP (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CSS-type
|
|
match { .funct3, .imm_at_12_7, .rs2, .op } = fv_ifields_CSS_type (instr_C);
|
|
Bit #(10) offset = { imm_at_12_7 [3:0], imm_at_12_7 [5:4], 4'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C2)
|
|
&& (funct3 == funct3_C_SQSP)
|
|
&& (xl == misa_mxl_128));
|
|
|
|
RegName rs1 = reg_sp;
|
|
let instr = mkInstr_S_type (zeroExtend (offset), rs2, rs1, f3_SQ, op_STORE);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
`endif
|
|
|
|
`ifdef ISA_F
|
|
// FSWSP: expands to FSW
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_FSWSP (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CSS-type
|
|
match { .funct3, .imm_at_12_7, .rs2, .op } = fv_ifields_CSS_type (instr_C);
|
|
Bit #(8) offset = { imm_at_12_7 [1:0], imm_at_12_7 [5:2], 2'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C2)
|
|
&& (funct3 == funct3_C_FSWSP));
|
|
|
|
RegName rs1 = reg_sp;
|
|
let instr = mkInstr_S_type (zeroExtend (offset), rs2, rs1, f3_FSW, op_STORE_FP);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
`endif
|
|
|
|
`ifdef ISA_D
|
|
// FSDSP: expands to FSD
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_FSDSP (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CSS-type
|
|
match { .funct3, .imm_at_12_7, .rs2, .op } = fv_ifields_CSS_type (instr_C);
|
|
Bit #(9) offset = { imm_at_12_7 [2:0], imm_at_12_7 [5:3], 3'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C2)
|
|
&& (funct3 == funct3_C_FSDSP)
|
|
&& ( (xl == misa_mxl_64)
|
|
|| (xl == misa_mxl_128)));
|
|
|
|
RegName rs1 = reg_sp;
|
|
let instr = mkInstr_S_type (zeroExtend (offset), rs2, rs1, f3_FSD, op_STORE_FP);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
`endif
|
|
|
|
// ================================================================
|
|
// 'C' Extension Register-Based Loads
|
|
|
|
// C_LW: expands to LW
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_LW (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CL-type
|
|
match { .funct3, .imm_at_12_10, .rs1, .imm_at_6_5, .rd, .op } = fv_ifields_CL_type (instr_C);
|
|
Bit #(7) offset = { imm_at_6_5 [0], imm_at_12_10, imm_at_6_5 [1], 2'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C0)
|
|
&& (funct3 == funct3_C_LW));
|
|
|
|
let instr = mkInstr_I_type (zeroExtend (offset), rs1, f3_LW, rd, op_LOAD);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
`ifdef RV64
|
|
// C_LD: expands to LD
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_LD (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CL-type
|
|
match { .funct3, .imm_at_12_10, .rs1, .imm_at_6_5, .rd, .op } = fv_ifields_CL_type (instr_C);
|
|
Bit #(8) offset = { imm_at_6_5, imm_at_12_10, 3'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C0)
|
|
&& (funct3 == funct3_C_LD)
|
|
&& ( (xl == misa_mxl_64)
|
|
|| (xl == misa_mxl_128)));
|
|
|
|
let instr = mkInstr_I_type (zeroExtend (offset), rs1, f3_LD, rd, op_LOAD);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
`endif
|
|
|
|
`ifdef RV128
|
|
// C_LQ: expands to LQ
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_LQ (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CL-type
|
|
match { .funct3, .imm_at_12_10, .rs1, .imm_at_6_5, .rd, .op } = fv_ifields_CL_type (instr_C);
|
|
Bit #(9) offset = { imm_at_12_10 [0], imm_at_6_5, imm_at_12_10 [2], imm_at_12_10 [1], 4'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C0)
|
|
&& (funct3 == funct3_C_LQ)
|
|
&& (xl == misa_mxl_128));
|
|
|
|
let instr = mkInstr_I_type (zeroExtend (offset), rs1, f3_LQ, rd, op_LOAD);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
`endif
|
|
|
|
`ifdef ISA_F
|
|
// C_FLW: expands to FLW
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_FLW (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CL-type
|
|
match { .funct3, .imm_at_12_10, .rs1, .imm_at_6_5, .rd, .op } = fv_ifields_CL_type (instr_C);
|
|
Bit #(7) offset = { imm_at_6_5 [0], imm_at_12_10, imm_at_6_5 [1], 2'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C0)
|
|
&& (funct3 == funct3_C_FLW));
|
|
|
|
let instr = mkInstr_I_type (zeroExtend (offset), rs1, f3_FLW, rd, op_LOAD_FP);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
`endif
|
|
|
|
`ifdef ISA_D
|
|
// C_FLD: expands to FLD
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_FLD (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CL-type
|
|
match { .funct3, .imm_at_12_10, .rs1, .imm_at_6_5, .rd, .op } = fv_ifields_CL_type (instr_C);
|
|
Bit #(8) offset = { imm_at_6_5, imm_at_12_10, 3'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C0)
|
|
&& (funct3 == funct3_C_FLD)
|
|
&& ( (xl == misa_mxl_64)
|
|
|| (xl == misa_mxl_128)));
|
|
|
|
let instr = mkInstr_I_type (zeroExtend (offset), rs1, f3_FLD, rd, op_LOAD_FP);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
`endif
|
|
|
|
// ================================================================
|
|
// 'C' Extension Register-Based Stores
|
|
|
|
// C_SW: expands to SW
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_SW (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CS-type
|
|
match { .funct3, .imm_at_12_10, .rs1, .imm_at_6_5, .rs2, .op } = fv_ifields_CS_type (instr_C);
|
|
Bit #(7) offset = { imm_at_6_5 [0], imm_at_12_10, imm_at_6_5 [1], 2'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C0)
|
|
&& (funct3 == funct3_C_SW));
|
|
|
|
let instr = mkInstr_S_type (zeroExtend (offset), rs2, rs1, f3_SW, op_STORE);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
`ifdef RV64
|
|
// C_SD: expands to SD
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_SD (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CS-type
|
|
match { .funct3, .imm_at_12_10, .rs1, .imm_at_6_5, .rs2, .op } = fv_ifields_CS_type (instr_C);
|
|
Bit #(8) offset = { imm_at_6_5, imm_at_12_10, 3'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C0)
|
|
&& (funct3 == funct3_C_SD));
|
|
|
|
let instr = mkInstr_S_type (zeroExtend (offset), rs2, rs1, f3_SD, op_STORE);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
`endif
|
|
|
|
`ifdef RV128
|
|
// C_SQ: expands to SQ
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_SQ (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CS-type
|
|
match { .funct3, .imm_at_12_10, .rs1, .imm_at_6_5, .rs2, .op } = fv_ifields_CS_type (instr_C);
|
|
Bit #(9) offset = { imm_at_12_10 [0], imm_at_6_5, imm_at_12_10 [2], imm_at_12_10 [1], 4'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C0)
|
|
&& (funct3 == funct3_C_SQ));
|
|
|
|
let instr = mkInstr_S_type (zeroExtend (offset), rs2, rs1, f3_SQ, op_STORE);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
`endif
|
|
|
|
`ifdef ISA_F
|
|
// C_FSW: expands to FSW
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_FSW (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CS-type
|
|
match { .funct3, .imm_at_12_10, .rs1, .imm_at_6_5, .rs2, .op } = fv_ifields_CS_type (instr_C);
|
|
Bit #(7) offset = { imm_at_6_5 [0], imm_at_12_10, imm_at_6_5 [1], 2'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C0)
|
|
&& (funct3 == funct3_C_FSW));
|
|
|
|
let instr = mkInstr_S_type (zeroExtend (offset), rs2, rs1, f3_FSW, op_STORE_FP);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
`endif
|
|
|
|
`ifdef ISA_D
|
|
// C_FSD: expands to FSD
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_FSD (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CS-type
|
|
match { .funct3, .imm_at_12_10, .rs1, .imm_at_6_5, .rs2, .op } = fv_ifields_CS_type (instr_C);
|
|
Bit #(8) offset = { imm_at_6_5, imm_at_12_10, 3'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C0)
|
|
&& (funct3 == funct3_C_FSD));
|
|
|
|
let instr = mkInstr_S_type (zeroExtend (offset), rs2, rs1, f3_FSD, op_STORE_FP);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
`endif
|
|
|
|
// ================================================================
|
|
// 'C' Extension Control Transfer
|
|
// C.J, C.JAL, C.JR, C.JALR, C.BEQZ, C.BNEZ
|
|
|
|
// C.J: expands to JAL
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_J (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CJ-type
|
|
match { .funct3, .imm_at_12_2, .op } = fv_ifields_CJ_type (instr_C);
|
|
Bit #(12) offset = {imm_at_12_2 [10],
|
|
imm_at_12_2 [6],
|
|
imm_at_12_2 [8:7],
|
|
imm_at_12_2 [4],
|
|
imm_at_12_2 [5],
|
|
imm_at_12_2 [0],
|
|
imm_at_12_2 [9],
|
|
imm_at_12_2 [3:1],
|
|
1'b0};
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C1)
|
|
&& (funct3 == funct3_C_J));
|
|
|
|
RegName rd = reg_zero;
|
|
Bit #(21) imm21 = signExtend (offset);
|
|
let instr = mkInstr_J_type (imm21, rd, op_JAL);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// C.JAL: expands to JAL
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_JAL (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CJ-type
|
|
match { .funct3, .imm_at_12_2, .op } = fv_ifields_CJ_type (instr_C);
|
|
Bit #(12) offset = {imm_at_12_2 [10],
|
|
imm_at_12_2 [6],
|
|
imm_at_12_2 [8:7],
|
|
imm_at_12_2 [4],
|
|
imm_at_12_2 [5],
|
|
imm_at_12_2 [0],
|
|
imm_at_12_2 [9],
|
|
imm_at_12_2 [3:1],
|
|
1'b0};
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C1)
|
|
&& (funct3 == funct3_C_JAL)
|
|
&& (xl == misa_mxl_32));
|
|
|
|
RegName rd = reg_ra;
|
|
Bit #(21) imm21 = signExtend (offset);
|
|
let instr = mkInstr_J_type (imm21, rd, op_JAL);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// C.JR: expands to JALR
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_JR (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CR-type
|
|
match { .funct4, .rs1, .rs2, .op } = fv_ifields_CR_type (instr_C);
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C2)
|
|
&& (funct4 == funct4_C_JR)
|
|
&& (rs1 != 0)
|
|
&& (rs2 == 0));
|
|
|
|
RegName rd = reg_zero;
|
|
Bit #(12) imm12 = 0;
|
|
let instr = mkInstr_I_type (imm12, rs1, funct3_JALR, rd, op_JALR);
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// C.JALR: expands to JALR
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_JALR (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CR-type
|
|
match { .funct4, .rs1, .rs2, .op } = fv_ifields_CR_type (instr_C);
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C2)
|
|
&& (funct4 == funct4_C_JALR)
|
|
&& (rs1 != 0)
|
|
&& (rs2 == 0));
|
|
|
|
RegName rd = reg_ra;
|
|
Bit #(12) imm12 = 0;
|
|
let instr = mkInstr_I_type (imm12, rs1, funct3_JALR, rd, op_JALR);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// C.BEQZ: expands to BEQ
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_BEQZ (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CB-type
|
|
match { .funct3, .imm_at_12_10, .rs1, .imm_at_6_2, .op } = fv_ifields_CB_type (instr_C);
|
|
Bit #(9) offset = { imm_at_12_10 [2], imm_at_6_2 [4:3], imm_at_6_2 [0], imm_at_12_10 [1:0], imm_at_6_2 [2:1], 1'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C1)
|
|
&& (funct3 == funct3_C_BEQZ));
|
|
|
|
RegName rs2 = reg_zero;
|
|
Bit #(13) imm13 = signExtend (offset);
|
|
let instr = mkInstr_B_type (imm13, rs2, rs1, f3_BEQ, op_BRANCH);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// C.BNEZ: expands to BNE
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_BNEZ (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CB-type
|
|
match { .funct3, .imm_at_12_10, .rs1, .imm_at_6_2, .op } = fv_ifields_CB_type (instr_C);
|
|
Bit #(9) offset = { imm_at_12_10 [2], imm_at_6_2 [4:3], imm_at_6_2 [0], imm_at_12_10 [1:0], imm_at_6_2 [2:1], 1'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C1)
|
|
&& (funct3 == funct3_C_BNEZ));
|
|
|
|
RegName rs2 = reg_zero;
|
|
Bit #(13) imm13 = signExtend (offset);
|
|
let instr = mkInstr_B_type (imm13, rs2, rs1, f3_BNE, op_BRANCH);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// ================================================================
|
|
// 'C' Extension Integer Constant-Generation
|
|
|
|
// C.LI: expands to ADDI
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_LI (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CI-type
|
|
match { .funct3, .imm_at_12, .rd, .imm_at_6_2, .op } = fv_ifields_CI_type (instr_C);
|
|
Bit #(6) imm6 = { imm_at_12, imm_at_6_2 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C1)
|
|
&& (funct3 == funct3_C_LI)
|
|
&& (rd != 0));
|
|
|
|
RegName rs1 = reg_zero;
|
|
Bit #(12) imm12 = signExtend (imm6);
|
|
let instr = mkInstr_I_type (imm12, rs1, f3_ADDI, rd, op_OP_IMM);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// C.LUI: expands to LUI
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_LUI (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CI-type
|
|
match { .funct3, .imm_at_12, .rd, .imm_at_6_2, .op } = fv_ifields_CI_type (instr_C);
|
|
Bit #(6) nzimm6 = { imm_at_12, imm_at_6_2 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C1)
|
|
&& (funct3 == funct3_C_LUI)
|
|
&& (rd != 0)
|
|
&& (rd != 2)
|
|
&& (nzimm6 != 0));
|
|
|
|
Bit #(20) imm20 = signExtend (nzimm6);
|
|
let instr = mkInstr_U_type (imm20, rd, op_LUI);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// ================================================================
|
|
// 'C' Extension Integer Register-Immediate Operations
|
|
|
|
// C.ADDI: expands to ADDI
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_ADDI (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CI-type
|
|
match { .funct3, .imm_at_12, .rd_rs1, .imm_at_6_2, .op } = fv_ifields_CI_type (instr_C);
|
|
Bit #(6) nzimm6 = { imm_at_12, imm_at_6_2 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C1)
|
|
&& (funct3 == funct3_C_ADDI)
|
|
&& (rd_rs1 != 0)
|
|
&& (nzimm6 != 0));
|
|
|
|
Bit #(12) imm12 = signExtend (nzimm6);
|
|
let instr = mkInstr_I_type (imm12, rd_rs1, f3_ADDI, rd_rs1, op_OP_IMM);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// C.NOP: expands to ADDI
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_NOP (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CI-type
|
|
match { .funct3, .imm_at_12, .rd_rs1, .imm_at_6_2, .op } = fv_ifields_CI_type (instr_C);
|
|
Bit #(6) nzimm6 = { imm_at_12, imm_at_6_2 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C1)
|
|
&& (funct3 == funct3_C_NOP)
|
|
&& (rd_rs1 == 0)
|
|
&& (nzimm6 == 0));
|
|
|
|
Bit #(12) imm12 = signExtend (nzimm6);
|
|
let instr = mkInstr_I_type (imm12, rd_rs1, f3_ADDI, rd_rs1, op_OP_IMM);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// C.ADDIW: expands to ADDIW
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_ADDIW (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CI-type
|
|
match { .funct3, .imm_at_12, .rd_rs1, .imm_at_6_2, .op } = fv_ifields_CI_type (instr_C);
|
|
Bit #(6) imm6 = { imm_at_12, imm_at_6_2 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C1)
|
|
&& (funct3 == funct3_C_ADDIW)
|
|
&& (rd_rs1 != 0)
|
|
&& ( (xl == misa_mxl_64)
|
|
|| (xl == misa_mxl_128)));
|
|
|
|
Bit #(12) imm12 = signExtend (imm6);
|
|
let instr = mkInstr_I_type (imm12, rd_rs1, f3_ADDIW, rd_rs1, op_OP_IMM_32);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// C.ADDI16SP: expands to ADDI
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_ADDI16SP (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CI-type
|
|
match { .funct3, .imm_at_12, .rd_rs1, .imm_at_6_2, .op } = fv_ifields_CI_type (instr_C);
|
|
Bit #(10) nzimm10 = { imm_at_12, imm_at_6_2 [2:1], imm_at_6_2 [3], imm_at_6_2 [0], imm_at_6_2 [4], 4'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C1)
|
|
&& (funct3 == funct3_C_ADDI16SP)
|
|
&& (rd_rs1 == reg_sp)
|
|
&& (nzimm10 != 0));
|
|
|
|
Bit #(12) imm12 = signExtend (nzimm10);
|
|
let instr = mkInstr_I_type (imm12, rd_rs1, f3_ADDI, rd_rs1, op_OP_IMM);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// C.ADDI4SPN: expands to ADDI
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_ADDI4SPN (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CIW-type
|
|
match { .funct3, .imm_at_12_5, .rd, .op } = fv_ifields_CIW_type (instr_C);
|
|
Bit #(10) nzimm10 = { imm_at_12_5 [5:2], imm_at_12_5 [7:6], imm_at_12_5 [0], imm_at_12_5 [1], 2'b0 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C0)
|
|
&& (funct3 == funct3_C_ADDI4SPN)
|
|
&& (nzimm10 != 0));
|
|
|
|
RegName rs1 = reg_sp;
|
|
Bit #(12) imm12 = zeroExtend (nzimm10);
|
|
let instr = mkInstr_I_type (imm12, rs1, f3_ADDI, rd, op_OP_IMM);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// C.SLLI: expands to SLLI
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_SLLI (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CI-type
|
|
match { .funct3, .imm_at_12, .rd_rs1, .imm_at_6_2, .op } = fv_ifields_CI_type (instr_C);
|
|
Bit #(6) shamt6 = { imm_at_12, imm_at_6_2 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C2)
|
|
&& (funct3 == funct3_C_SLLI)
|
|
&& (rd_rs1 != 0)
|
|
&& (shamt6 != 0)
|
|
&& ((xl == misa_mxl_32) ? (imm_at_12 == 0) : True));
|
|
|
|
Bit #(12) imm12 = ( (xl == misa_mxl_32)
|
|
? { msbs7_SLLI, imm_at_6_2 }
|
|
: { msbs6_SLLI, shamt6 } );
|
|
let instr = mkInstr_I_type (imm12, rd_rs1, f3_SLLI, rd_rs1, op_OP_IMM);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// C.SRLI: expands to SRLI
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_SRLI (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CB-type
|
|
match { .funct3, .imm_at_12_10, .rd_rs1, .imm_at_6_2, .op } = fv_ifields_CB_type (instr_C);
|
|
Bit #(1) shamt6_5 = imm_at_12_10 [2];
|
|
Bit #(2) funct2 = imm_at_12_10 [1:0];
|
|
Bit #(6) shamt6 = { shamt6_5, imm_at_6_2 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C1)
|
|
&& (funct3 == funct3_C_SRLI)
|
|
&& (funct2 == funct2_C_SRLI)
|
|
&& (rd_rs1 != 0)
|
|
&& (shamt6 != 0)
|
|
&& ((xl == misa_mxl_32) ? (shamt6_5 == 0) : True));
|
|
|
|
Bit #(12) imm12 = ( (xl == misa_mxl_32)
|
|
? { msbs7_SRLI, imm_at_6_2 }
|
|
: { msbs6_SRLI, shamt6 } );
|
|
let instr = mkInstr_I_type (imm12, rd_rs1, f3_SRLI, rd_rs1, op_OP_IMM);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// C.SRAI: expands to SRAI
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_SRAI (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CB-type
|
|
match { .funct3, .imm_at_12_10, .rd_rs1, .imm_at_6_2, .op } = fv_ifields_CB_type (instr_C);
|
|
Bit #(1) shamt6_5 = imm_at_12_10 [2];
|
|
Bit #(2) funct2 = imm_at_12_10 [1:0];
|
|
Bit #(6) shamt6 = { shamt6_5, imm_at_6_2 };
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C1)
|
|
&& (funct3 == funct3_C_SRAI)
|
|
&& (funct2 == funct2_C_SRAI)
|
|
&& (rd_rs1 != 0)
|
|
&& (shamt6 != 0)
|
|
&& ((xl == misa_mxl_32) ? (shamt6_5 == 0) : True));
|
|
|
|
Bit #(12) imm12 = ( (xl == misa_mxl_32)
|
|
? { msbs7_SRAI, imm_at_6_2 }
|
|
: { msbs6_SRAI, shamt6 } );
|
|
let instr = mkInstr_I_type (imm12, rd_rs1, f3_SRAI, rd_rs1, op_OP_IMM);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// C.ANDI: expands to ANDI
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_ANDI (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CB-type
|
|
match { .funct3, .imm_at_12_10, .rd_rs1, .imm_at_6_2, .op } = fv_ifields_CB_type (instr_C);
|
|
Bit #(1) imm6_5 = imm_at_12_10 [2];
|
|
Bit #(6) imm6 = { imm6_5, imm_at_6_2 };
|
|
Bit #(2) funct2 = imm_at_12_10 [1:0];
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C1)
|
|
&& (funct3 == funct3_C_ANDI)
|
|
&& (funct2 == funct2_C_ANDI));
|
|
|
|
Bit #(12) imm12 = signExtend (imm6);
|
|
let instr = mkInstr_I_type (imm12, rd_rs1, f3_ANDI, rd_rs1, op_OP_IMM);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// ================================================================
|
|
// 'C' Extension Integer Register-Register Operations
|
|
|
|
// C.MV: expands to ADD
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_MV (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
match { .funct4, .rd_rs1, .rs2, .op } = fv_ifields_CR_type (instr_C);
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C2)
|
|
&& (funct4 == funct4_C_MV)
|
|
&& (rd_rs1 != 0)
|
|
&& (rs2 != 0));
|
|
|
|
RegName rs1 = reg_zero;
|
|
let instr = mkInstr_R_type (funct7_ADD, rs2, rs1, funct3_ADD, rd_rs1, op_OP);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// C.ADD: expands to ADD
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_ADD (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
match { .funct4, .rd_rs1, .rs2, .op } = fv_ifields_CR_type (instr_C);
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C2)
|
|
&& (funct4 == funct4_C_ADD)
|
|
&& (rd_rs1 != 0)
|
|
&& (rs2 != 0));
|
|
|
|
let instr = mkInstr_R_type (funct7_ADD, rs2, rd_rs1, funct3_ADD, rd_rs1, op_OP);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// C.AND: expands to AND
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_AND (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CA-type
|
|
match { .funct6, .rd_rs1, .funct2, .rs2, .op } = fv_ifields_CA_type (instr_C);
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C1)
|
|
&& (funct6 == funct6_C_AND)
|
|
&& (funct2 == funct2_C_AND));
|
|
|
|
let instr = mkInstr_R_type (funct7_AND, rs2, rd_rs1, funct3_AND, rd_rs1, op_OP);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// C.OR: expands to OR
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_OR (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CA-type
|
|
match { .funct6, .rd_rs1, .funct2, .rs2, .op } = fv_ifields_CA_type (instr_C);
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C1)
|
|
&& (funct6 == funct6_C_OR)
|
|
&& (funct2 == funct2_C_OR));
|
|
|
|
let instr = mkInstr_R_type (funct7_OR, rs2, rd_rs1, funct3_OR, rd_rs1, op_OP);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// C.XOR: expands to XOR
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_XOR (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CA-type
|
|
match { .funct6, .rd_rs1, .funct2, .rs2, .op } = fv_ifields_CA_type (instr_C);
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C1)
|
|
&& (funct6 == funct6_C_XOR)
|
|
&& (funct2 == funct2_C_XOR));
|
|
|
|
let instr = mkInstr_R_type (funct7_XOR, rs2, rd_rs1, funct3_XOR, rd_rs1, op_OP);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// C.SUB: expands to SUB
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_SUB (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CA-type
|
|
match { .funct6, .rd_rs1, .funct2, .rs2, .op } = fv_ifields_CA_type (instr_C);
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C1)
|
|
&& (funct6 == funct6_C_SUB)
|
|
&& (funct2 == funct2_C_SUB));
|
|
|
|
let instr = mkInstr_R_type (funct7_SUB, rs2, rd_rs1, funct3_SUB, rd_rs1, op_OP);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// C.ADDW: expands to ADDW
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_ADDW (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CA-type
|
|
match { .funct6, .rd_rs1, .funct2, .rs2, .op } = fv_ifields_CA_type (instr_C);
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C1)
|
|
&& (funct6 == funct6_C_ADDW)
|
|
&& (funct2 == funct2_C_ADDW)
|
|
&& ( (xl == misa_mxl_64)
|
|
|| (xl == misa_mxl_128)));
|
|
|
|
let instr = mkInstr_R_type (funct7_ADDW, rs2, rd_rs1, funct3_ADDW, rd_rs1, op_OP_32);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// C.SUBW: expands to SUBW
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_SUBW (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CA-type
|
|
match { .funct6, .rd_rs1, .funct2, .rs2, .op } = fv_ifields_CA_type (instr_C);
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C1)
|
|
&& (funct6 == funct6_C_SUBW)
|
|
&& (funct2 == funct2_C_SUBW)
|
|
&& ( (xl == misa_mxl_64)
|
|
|| (xl == misa_mxl_128)));
|
|
|
|
let instr = mkInstr_R_type (funct7_SUBW, rs2, rd_rs1, funct3_SUBW, rd_rs1, op_OP_32);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// ================================================================
|
|
// 'C' Extension EBREAK
|
|
|
|
// C.EBREAK: expands to EBREAK
|
|
function Tuple2 #(Bool, Instr) fv_decode_C_EBREAK (MISA misa, Bit #(2) xl, Instr_C instr_C);
|
|
begin
|
|
// Instr fields: CR-type
|
|
match { .funct4, .rd_rs1, .rs2, .op } = fv_ifields_CR_type (instr_C);
|
|
|
|
Bool is_legal = ((misa.c == 1'b1)
|
|
&& (op == opcode_C2)
|
|
&& (funct4 == funct4_C_EBREAK)
|
|
&& (rd_rs1 == 0)
|
|
&& (rs2 == 0));
|
|
|
|
Bit #(12) imm12 = f12_EBREAK;
|
|
let instr = mkInstr_I_type (imm12, rd_rs1, f3_PRIV, rd_rs1, op_SYSTEM);
|
|
|
|
return tuple2 (is_legal, instr);
|
|
end
|
|
endfunction
|
|
|
|
// ================================================================
|
|
|
|
endpackage
|