🚧 Add FP extensions to decoder

This commit is contained in:
Stefan Mach 2018-03-29 15:35:09 +02:00
parent d2460f3048
commit 8cb26a39e2
2 changed files with 247 additions and 18 deletions

View file

@ -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;

View file

@ -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;