mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-24 22:27:10 -04:00
🚧 Add FP extensions to decoder
This commit is contained in:
parent
d2460f3048
commit
8cb26a39e2
2 changed files with 247 additions and 18 deletions
|
@ -35,14 +35,21 @@ package ariane_pkg;
|
|||
localparam BITS_SATURATION_COUNTER = 2;
|
||||
localparam NR_COMMIT_PORTS = 2;
|
||||
|
||||
localparam logic [63:0] ISA_CODE = (1 << 2) // C - Compressed extension
|
||||
| (1 << 8) // I - RV32I/64I/128I base ISA
|
||||
| (1 << 12) // M - Integer Multiply/Divide extension
|
||||
| (0 << 13) // N - User level interrupts supported
|
||||
| (1 << 18) // S - Supervisor mode implemented
|
||||
| (1 << 20) // U - User mode implemented
|
||||
| (0 << 23) // X - Non-standard extensions present
|
||||
| (1 << 63); // RV64
|
||||
// Floating-point extensions configuration
|
||||
localparam bit RVF = 1'b1; // Is F extension enabled
|
||||
localparam bit RVD = 1'b1; // Is D extension enabled
|
||||
|
||||
localparam logic [63:0] ISA_CODE = (0 << 0) // A - Atomic Instructions extension
|
||||
| (1 << 2) // C - Compressed extension
|
||||
| (RVD << 3) // D - Double precsision floating-point extension
|
||||
| (RVF << 5) // F - Single precsision floating-point extension
|
||||
| (1 << 8) // I - RV32I/64I/128I base ISA
|
||||
| (1 << 12) // M - Integer Multiply/Divide extension
|
||||
| (0 << 13) // N - User level interrupts supported
|
||||
| (1 << 18) // S - Supervisor mode implemented
|
||||
| (1 << 20) // U - User mode implemented
|
||||
| (0 << 23) // X - Non-standard extensions present
|
||||
| (1 << 63); // RV64
|
||||
|
||||
// 32 registers + 1 bit for re-naming = 6
|
||||
localparam REG_ADDR_SIZE = 6;
|
||||
|
@ -152,7 +159,17 @@ package ariane_pkg;
|
|||
// Multiplications
|
||||
MUL, MULH, MULHU, MULHSU, MULW,
|
||||
// Divisions
|
||||
DIV, DIVU, DIVW, DIVUW, REM, REMU, REMW, REMUW
|
||||
DIV, DIVU, DIVW, DIVUW, REM, REMU, REMW, REMUW,
|
||||
// Floating-Point Load and Store Instructions
|
||||
FLD, FLW, FSD, FSW,
|
||||
// Floating-Point Computational Instructions
|
||||
FADD, FSUB, FMUL, FDIV, FMIN_MAX, FSQRT, FMADD, FMSUB, FNMADD, FNMSUB,
|
||||
// Floating-Point Conversion and Move Instructions
|
||||
FCVT_F2I, FCVT_I2F, FCVT_F2F, FSGNJ, FMV_F2X, FMV_X2F,
|
||||
// Floating-Point Compare Instructions
|
||||
FCMP,
|
||||
// Floating-Point Classify Instruction
|
||||
FCLASS
|
||||
} fu_op;
|
||||
|
||||
// ----------------------
|
||||
|
@ -161,11 +178,11 @@ package ariane_pkg;
|
|||
// TODO: Add atomics
|
||||
function automatic logic [1:0] extract_transfer_size (fu_op op);
|
||||
case (op)
|
||||
LD, SD: return 2'b11;
|
||||
LW, LWU, SW: return 2'b10;
|
||||
LH, LHU, SH: return 2'b01;
|
||||
LB, SB, LBU: return 2'b00;
|
||||
default: return 2'b11;
|
||||
LD, SD, FLD, FSD : return 2'b11;
|
||||
LW, LWU, SW, FLW, FSW : return 2'b10;
|
||||
LH, LHU, SH : return 2'b01;
|
||||
LB, LBU, SB : return 2'b00;
|
||||
default : return 2'b11;
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
|
@ -202,7 +219,10 @@ package ariane_pkg;
|
|||
logic [REG_ADDR_SIZE-1:0] rs1; // register source address 1
|
||||
logic [REG_ADDR_SIZE-1:0] rs2; // register source address 2
|
||||
logic [REG_ADDR_SIZE-1:0] rd; // register destination address
|
||||
logic [63:0] result; // for unfinished instructions this field also holds the immediate
|
||||
logic [63:0] result; // for unfinished instructions this field also holds the immediate,
|
||||
// for unfinished floating-point that are partly encoded in rs2, this field also holds rs2
|
||||
// for unfinished floating-point fused operations (FMADD, FMSUB, FNMADD, FNMSUB)
|
||||
// this field holds the address of the third operand from the floating-point register file
|
||||
logic valid; // is the result valid
|
||||
logic use_imm; // should we use the immediate as operand b?
|
||||
logic use_zimm; // use zimm as operand a
|
||||
|
@ -225,6 +245,26 @@ package ariane_pkg;
|
|||
logic [6:0] opcode;
|
||||
} rtype_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [31:27] rs3;
|
||||
logic [1:0] funct2;
|
||||
logic [24:20] rs2;
|
||||
logic [19:15] rs1;
|
||||
logic [14:12] funct3;
|
||||
logic [11:7] rd;
|
||||
logic [6:0] opcode;
|
||||
} r4type_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [31:27] funct5;
|
||||
logic [26:25] fmt;
|
||||
logic [24:20] rs2;
|
||||
logic [19:15] rs1;
|
||||
logic [14:12] rm;
|
||||
logic [11:7] rd;
|
||||
logic [6:0] opcode;
|
||||
} rftype_t; // floating-point
|
||||
|
||||
typedef struct packed {
|
||||
logic [31:20] imm;
|
||||
logic [19:15] rs1;
|
||||
|
@ -251,6 +291,8 @@ package ariane_pkg;
|
|||
typedef union packed {
|
||||
logic [31:0] instr;
|
||||
rtype_t rtype;
|
||||
r4type_t r4type;
|
||||
rftype_t rftype;
|
||||
itype_t itype;
|
||||
stype_t stype;
|
||||
utype_t utype;
|
||||
|
|
193
src/decoder.sv
193
src/decoder.sv
|
@ -29,6 +29,7 @@ module decoder (
|
|||
input exception_t ex_i, // if an exception occured in if
|
||||
// From CSR
|
||||
input priv_lvl_t priv_lvl_i, // current privilege level
|
||||
input logic [2:0] frm_i, // floating-point dynamic rounding mode
|
||||
input logic tvm_i, // trap virtual memory
|
||||
input logic tw_i, // timeout wait
|
||||
input logic tsr_i, // trap sret
|
||||
|
@ -40,13 +41,15 @@ module decoder (
|
|||
logic ecall;
|
||||
// this instruction is a software break-point
|
||||
logic ebreak;
|
||||
// this instruction needs floating-point rounding-mode verification
|
||||
logic check_fprm;
|
||||
instruction_t instr;
|
||||
assign instr = instruction_t'(instruction_i);
|
||||
// --------------------
|
||||
// Immediate select
|
||||
// --------------------
|
||||
enum logic[3:0] {
|
||||
NOIMM, PCIMM, IIMM, SIMM, SBIMM, BIMM, UIMM, JIMM
|
||||
NOIMM, PCIMM, IIMM, SIMM, SBIMM, BIMM, UIMM, JIMM, RS3
|
||||
} imm_select;
|
||||
|
||||
logic [63:0] imm_i_type;
|
||||
|
@ -63,18 +66,19 @@ module decoder (
|
|||
is_control_flow_instr_o = 1'b0;
|
||||
illegal_instr = 1'b0;
|
||||
instruction_o.pc = pc_i;
|
||||
instruction_o.trans_id = 5'b0;
|
||||
instruction_o.fu = NONE;
|
||||
instruction_o.op = ADD;
|
||||
instruction_o.rs1 = 5'b0;
|
||||
instruction_o.rs2 = 5'b0;
|
||||
instruction_o.rd = 5'b0;
|
||||
instruction_o.use_pc = 1'b0;
|
||||
instruction_o.trans_id = 5'b0;
|
||||
instruction_o.is_compressed = is_compressed_i;
|
||||
instruction_o.use_zimm = 1'b0;
|
||||
instruction_o.bp = branch_predict_i;
|
||||
ecall = 1'b0;
|
||||
ebreak = 1'b0;
|
||||
check_fprm = 1'b0;
|
||||
|
||||
if (~ex_i.valid) begin
|
||||
case (instr.rtype.opcode)
|
||||
|
@ -384,6 +388,183 @@ module decoder (
|
|||
endcase
|
||||
end
|
||||
|
||||
// --------------------------------
|
||||
// Floating-Point Load/store
|
||||
// --------------------------------
|
||||
OPCODE_STORE_FP: begin
|
||||
if (RVF || RVD) begin // only generate decoder if FP extensions are enabled
|
||||
instruction_o.fu = STORE;
|
||||
imm_select = SIMM;
|
||||
instruction_o.rs1 = instr.stype.rs1;
|
||||
instruction_o.rs2 = instr.stype.rs2;
|
||||
// determine store size
|
||||
unique case (instr.stype.funct3)
|
||||
// Only process instruction if corresponding extension is active (static)
|
||||
3'b010: if (RVF) instruction_o.op = FSW;
|
||||
else illegal_instr = 1'b1;
|
||||
3'b011: if (RVD) instruction_o.op = FSD;
|
||||
else illegal_instr = 1'b1;
|
||||
default: illegal_instr = 1'b1;
|
||||
endcase
|
||||
end else
|
||||
illegal_instr = 1'b1;
|
||||
end
|
||||
|
||||
OPCODE_LOAD_FP: begin
|
||||
if (RVF || RVD) begin // only generate decoder if FP extensions are enabled
|
||||
instruction_o.fu = LOAD;
|
||||
imm_select = IIMM;
|
||||
instruction_o.rs1 = instr.itype.rs1;
|
||||
instruction_o.rd = instr.itype.rd;
|
||||
// determine load size
|
||||
unique case (instr.itype.funct3)
|
||||
// Only process instruction if corresponding extension is active (static)
|
||||
3'b010: if (RVF) instruction_o.op = FLW;
|
||||
else illegal_instr = 1'b1;
|
||||
3'b011: if (RVD) instruction_o.op = FLD;
|
||||
else illegal_instr = 1'b1;
|
||||
default: illegal_instr = 1'b1;
|
||||
endcase
|
||||
end else
|
||||
illegal_instr = 1'b1;
|
||||
end
|
||||
|
||||
// ----------------------------------
|
||||
// Floating-Point Reg-Reg Operations
|
||||
// ----------------------------------
|
||||
OPCODE_MADD,
|
||||
OPCODE_MSUB,
|
||||
OPCODE_NMSUB,
|
||||
OPCODE_NMADD: begin
|
||||
if (RVF || RVD) begin // only generate decoder if FP extensions are enabled
|
||||
instruction_o.fu = FPU;
|
||||
instruction_o.rs1 = instr.r4type.rs1;
|
||||
instruction_o.rs2 = instr.r4type.rs2;
|
||||
instruction_o.rd = instr.r4type.rd;
|
||||
imm_select = RS3; // rs3 into result field
|
||||
check_fprm = 1'b1;
|
||||
// select the correct fused operation
|
||||
unique case (instr.r4type.opcode)
|
||||
default: instruction_o.op = FMADD; // fmadd.fmt - Fused multiply-add
|
||||
OPCODE_MSUB: instruction_o.op = FMSUB; // fmsub.fmt - Fused multiply-subtract
|
||||
OPCODE_NMSUB: instruction_o.op = FNMSUB; // fnmsub.fmt - Negated fused multiply-subtract
|
||||
OPCODE_NMADD: instruction_o.op = FNMADD; // fnmadd.fmt - Negated fused multiply-add
|
||||
endcase
|
||||
|
||||
// determine fp format
|
||||
unique case (instr.r4type.funct2)
|
||||
// Only process instruction if corresponding extension is active (static)
|
||||
2'b00: if (!RVF) illegal_instr = 1'b1;
|
||||
2'b01: if (!RVD) illegal_instr = 1'b1;
|
||||
default: illegal_instr = 1'b1;
|
||||
endcase
|
||||
end else
|
||||
illegal_instr = 1'b1;
|
||||
end
|
||||
|
||||
OPCODE_FP: begin
|
||||
if (RVF || RVD) begin // only generate decoder if FP extensions are enabled
|
||||
instruction_o.fu = FPU;
|
||||
instruction_o.rs1 = instr.rftype.rs1;
|
||||
instruction_o.rs2 = instr.rftype.rs2;
|
||||
instruction_o.rd = instr.rftype.rd;
|
||||
check_fprm = 1'b1;
|
||||
// decode FP instruction
|
||||
unique case (instr.rftype.funct5)
|
||||
5'b00000: instruction_o.op = FADD; // fadd.fmt - FP Addition
|
||||
5'b00001: instruction_o.op = FSUB; // fsub.fmt - FP Subtraction
|
||||
5'b00010: instruction_o.op = FMUL; // fmul.fmt - FP Multiplication
|
||||
5'b00011: instruction_o.op = FDIV; // fdiv.fmt - FP Division
|
||||
5'b01011: begin
|
||||
instruction_o.op = FSQRT; // fsqrt.fmt - FP Square Root
|
||||
// rs2 must be zero
|
||||
if (instr.rftype.rs2 != 5'b00000) illegal_instr = 1'b1;
|
||||
end
|
||||
5'b00100: begin
|
||||
instruction_o.op = FSGNJ; // fsgn{j[n]/jx}.fmt - FP Sign Injection
|
||||
check_fprm = 1'b0; // instruction encoded in rm, do the check here
|
||||
if (instr.rftype.rm > 3'b010) illegal_instr = 1'b1;
|
||||
end
|
||||
5'b00101: begin
|
||||
instruction_o.op = FMIN_MAX; // fmin/fmax.fmt - FP Minimum / Maximum
|
||||
check_fprm = 1'b0; // instruction encoded in rm, do the check here
|
||||
if (instr.rftype.rm > 3'b001) illegal_instr = 1'b1;
|
||||
end
|
||||
5'b01000: begin
|
||||
instruction_o.op = FCVT_F2F; // fcvt.fmt.fmt - FP to FP Conversion
|
||||
imm_select = IIMM; // rs2 holds part of the intruction
|
||||
if (instr.rftype.rs2[24:22]) illegal_instr = 1'b1; // bits [21:20] used, other bits must be 0
|
||||
// check source format
|
||||
unique case (instr.rftype.rs2[21:20])
|
||||
// Only process instruction if corresponding extension is active (static)
|
||||
2'b00: if (!RVF) illegal_instr = 1'b1;
|
||||
2'b01: if (!RVD) illegal_instr = 1'b1;
|
||||
default: illegal_instr = 1'b1;
|
||||
endcase
|
||||
end
|
||||
5'b11000: begin
|
||||
instruction_o.op = FCVT_F2I; // fcvt.ifmt.fmt - FP to Int Conversion
|
||||
imm_select = IIMM; // rs2 holds part of the instruction
|
||||
if (instr.rftype.rs2[24:22]) illegal_instr = 1'b1; // bits [21:20] used, other bits must be 0
|
||||
end
|
||||
5'b11100: begin
|
||||
instruction_o.rs2 = instr.rftype.rs1; // set rs2 = rs1 so we can map FMV to SGNJ in the unit
|
||||
check_fprm = 1'b0; // instruction encoded in rm, do the check here
|
||||
if (instr.rftype.rm == 3'b000) instruction_o.op = FMV_F2X; // fmv.ifmt.fmt - FPR to GPR Move
|
||||
else if (instr.rftype.rm == 3'b001) instruction_o.op = FCLASS; // fclass.fmt - FP Classify
|
||||
else illegal_instr = 1'b1;
|
||||
// rs2 must be zero
|
||||
if (instr.rftype.rs2 != 5'b00000) illegal_instr = 1'b1;
|
||||
end
|
||||
5'b10100: begin
|
||||
instruction_o.op = FCMP; // feq/flt/fle.fmt - FP Comparisons
|
||||
check_fprm = 1'b0; // instruction encoded in rm, do the check here
|
||||
if (instr.rftype.rm > 3'b010) illegal_instr = 1'b1;
|
||||
end
|
||||
5'b11010: begin
|
||||
instruction_o.op = FCVT_I2F; // fcvt.fmt.ifmt - Int to FP Conversion
|
||||
imm_select = IIMM; // rs2 holds part of the instruction
|
||||
if (instr.rftype.rs2[24:22]) illegal_instr = 1'b1; // bits [21:20] used, other bits must be 0
|
||||
end
|
||||
5'b11110: begin
|
||||
instruction_o.op = FMV_X2F; // fmv.fmt.ifmt - GPR to FPR Move
|
||||
instruction_o.rs2 = instr.rftype.rs1; // set rs2 = rs1 so we can map FMV to SGNJ in the unit
|
||||
check_fprm = 1'b0; // instruction encoded in rm, do the check here
|
||||
if (instr.rftype.rm != 3'b000) illegal_instr = 1'b1;
|
||||
// rs2 must be zero
|
||||
if (instr.rftype.rs2 != 5'b00000) illegal_instr = 1'b1;
|
||||
end
|
||||
default : illegal_instr = 1'b1;
|
||||
endcase
|
||||
|
||||
// check format
|
||||
unique case (instr.rftype.fmt)
|
||||
// Only process instruction if corresponding extension is active (static)
|
||||
2'b00: if (!RVF) illegal_instr = 1'b1;
|
||||
2'b01: if (!RVD) illegal_instr = 1'b1;
|
||||
default: illegal_instr = 1'b1;
|
||||
endcase
|
||||
|
||||
// check rounding mode
|
||||
if (check_fprm) begin
|
||||
unique case (instr.rftype.rm)
|
||||
[3'b000:3'b100]: ; //legal rounding modes
|
||||
3'b111: begin
|
||||
unique case (frm_i)
|
||||
[3'b000:3'b100]: ; //legal rounding modes
|
||||
default : illegal_instr = 1'b1;
|
||||
endcase
|
||||
end
|
||||
default : illegal_instr = 1'b1;
|
||||
endcase
|
||||
end
|
||||
end else
|
||||
illegal_instr = 1'b1;
|
||||
end
|
||||
|
||||
// ----------------------------------
|
||||
// Atomic Operations
|
||||
// ----------------------------------
|
||||
`ifdef ENABLE_ATOMICS
|
||||
OPCODE_AMO: begin
|
||||
// we are going to use the load unit for AMOs
|
||||
|
@ -489,6 +670,7 @@ module decoder (
|
|||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// --------------------------------
|
||||
// Sign extend immediate
|
||||
// --------------------------------
|
||||
|
@ -501,7 +683,7 @@ module decoder (
|
|||
imm_uj_type = uj_imm(instruction_i);
|
||||
imm_bi_type = { {59{instruction_i[24]}}, instruction_i[24:20] };
|
||||
|
||||
// NOIMM, PCIMM, IIMM, SIMM, BIMM, BIMM, UIMM, JIMM
|
||||
// NOIMM, PCIMM, IIMM, SIMM, BIMM, BIMM, UIMM, JIMM, RS3
|
||||
// select immediate
|
||||
case (imm_select)
|
||||
PCIMM: begin
|
||||
|
@ -532,6 +714,11 @@ module decoder (
|
|||
instruction_o.result = imm_uj_type;
|
||||
instruction_o.use_imm = 1'b1;
|
||||
end
|
||||
RS3: begin
|
||||
// result holds address of fp operand rs3
|
||||
instruction_o.result = {59'b0, instr.r4type.rs3};
|
||||
instruction_o.use_imm = 1'b0;
|
||||
end
|
||||
default: begin
|
||||
instruction_o.result = 64'b0;
|
||||
instruction_o.use_imm = 1'b0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue