cvw/wally-pipelined/src/fpu/fctrl.sv
2021-05-01 02:18:01 +00:00

214 lines
5.9 KiB
Systemverilog
Executable File

module fctrl (
input logic [6:0] Funct7D,
input logic [6:0] OpD,
input logic [4:0] Rs2D,
input logic [2:0] Funct3D,
input logic [2:0] FRM_REGW,
output logic IllegalFPUInstrD,
output logic FRegWriteD,
output logic DivSqrtStartD,
//output logic [2:0] regSelD,
output logic [2:0] FResultSelD,
output logic [3:0] OpCtrlD,
output logic FmtD,
output logic [2:0] FrmD,
output logic WriteIntD);
//precision is taken directly from instruction
assign FmtD = Funct7D[0];
// *** fix rounding for dynamic rounding
assign FrmD = &Funct3D ? FRM_REGW : Funct3D;
//all subsequent logic is based on the table present
//in Section 5 of Wally Architecture Specification
//write is enabled for all fp instruciton op codes
//sans fp load
logic isFP, isFPLD;
always_comb begin
//case statement is easier to modify
//in case of errors
case(OpD)
//fp instructions sans load
7'b1010011 : isFP = 1'b1;
7'b1000011 : isFP = 1'b1;
7'b1000111 : isFP = 1'b1;
7'b1001011 : isFP = 1'b1;
7'b1001111 : isFP = 1'b1;
7'b0100111 : isFP = 1'b1;
7'b0000111 : isFP = 1'b1;// KEP change 7'b1010011 to 7'b0000111
default : isFP = 1'b0;
endcase
end
//useful intermediary signals
//
//(mult only not supported in current datapath)
//set third FMA operand to zero in this case
//(or equivalent)
always_comb begin
//checks all but FMA/store/load
if(OpD == 7'b1010011) begin
casez(Funct7D)
//compare
7'b10100?? : FResultSelD = 3'b001;
//div/sqrt
7'b0?011?? : FResultSelD = 3'b000;
//add/sub
7'b0000??? : FResultSelD = 3'b100;
//mult
7'b00010?? : FResultSelD = 3'b010;
//convert (not precision)
7'b110?0?? : FResultSelD = 3'b100;
//convert (precision)
7'b010000? : FResultSelD = 3'b100;
//Min/Max
7'b00101?? : FResultSelD = 3'b001;
//sign injection
7'b00100?? : FResultSelD = 3'b011;
//classify //only if funct3 = 001
7'b11100?? : if(Funct3D == 3'b001) FResultSelD = 3'b101;
//output ReadData1
else if (Funct7D[1] == 0) FResultSelD = 3'b111;
//output SrcW
7'b111100? : FResultSelD = 3'b110;
default : FResultSelD = 3'bxxx;
endcase
end
//FMA/store/load
else begin
case(OpD)
//4 FMA instructions
7'b1000011 : FResultSelD = 3'b010;
7'b1000111 : FResultSelD = 3'b010;
7'b1001011 : FResultSelD = 3'b010;
7'b1001111 : FResultSelD = 3'b010;
//store
7'b0100111 : FResultSelD = 3'b111;
//load
7'b0000111 : FResultSelD = 3'b111;
default : FResultSelD = 3'bxxx;
endcase
end
end
//register is chosen based on operation performed
//----
//write selection is chosen in the same way as
//register selection
//
// reg/write sel logic and assignment
//
// 3'b000 = div/sqrt
// 3'b001 = cmp
// 3'b010 = fma/mult
// 3'b011 = sgn inj
// 3'b100 = add/sub/cnvt
// 3'b101 = classify
// 3'b110 = output SrcAW
// 3'b111 = output ReadData1
//
//reg select
//this value is used enough to be shorthand
//if op is div/sqrt - start div/sqrt
assign DivSqrtStartD = ~|FResultSelD; // is FResultSelD == 000
//operation control for each fp operation
//has to be expanded over standard to account for
//integrated fpadd/cvt
//
//will integrate FMA opcodes into design later
//
//conversion instructions will
//also need to be added later as I find the opcode
//version I used for this repo
//let's do separate SOP for each type of operation
// assign OpCtrlD[3] = 1'b0;
//
//
always_comb begin
IllegalFPUInstrD = 0;
case (FResultSelD)
// div/sqrt
// fdiv = ???0
// fsqrt = ???1
3'b000 : OpCtrlD = {3'b0, Funct7D[5]};
// cmp
// fmin = ?100
// fmax = ?101
// feq = ?010
// flt = ?001
// fle = ?011
// {?, is min or max, is eq or le, is lt or le}
3'b001 : OpCtrlD = {1'b0, Funct7D[2], ~Funct3D[0], ~(|Funct3D[2:1])};
//fma/mult
// fmadd = ?000
// fmsub = ?001
// fnmadd = ?010
// fnmsub = ?011
// fmul = ?100
// {?, is mul, is negitive, is sub}
3'b010 : OpCtrlD = {1'b0, OpD[4:2]};
// sgn inj
// fsgnj = ??00
// fsgnjn = ??01
// fsgnjx = ??10
3'b011 : OpCtrlD = {2'b0, Funct3D[1:0]};
// add/sub/cnvt
// fadd = 0000
// fsub = 0001
// fcvt.w.s = 0100
// fcvt.wu.s = 0101
// fcvt.s.w = 0110
// fcvt.s.wu = 0111
// fcvt.s.d = 0010
// fcvt.w.d = 1100
// fcvt.wu.d = 1101
// fcvt.d.w = 1110
// fcvt.d.wu = 1111
// fcvt.d.s = 1000
// { is double and not add/sub, is to/from int, is to int or float to double, is unsigned or sub
3'b100 : OpCtrlD = {Funct7D[0]&Funct7D[5], Funct7D[6], Funct7D[3] | (~Funct7D[6]&Funct7D[5]&~Funct7D[0]), Rs2D[0]|(Funct7D[2]&~Funct7D[5])};
// classify {?, ?, ?, ?}
3'b101 : OpCtrlD = 4'b0;
// output SrcAW
// fmv.w.x = ???0
// fmv.w.d = ???1
3'b110 : OpCtrlD = {3'b0, Funct7D[0]};
// output ReadData1
// flw = ?000
// fld = ?001
// fsw = ?010
// fsd = ?011
// fmv.x.w = ?100
// fmv.d.w = ?101
// {?, is mv, is store, is double or fcvt.d.w}
3'b111 : OpCtrlD = {1'b0, OpD[6:5], Funct3D[0] | (OpD[6]&Funct7D[0])};
default : begin OpCtrlD = 4'bxxxx; IllegalFPUInstrD = isFP; end
endcase
end
//write to integer source if conv to int occurs
//AND of Funct7 for int results
// is add/cvt and is to int or is classify or is cmp and not max/min or is output ReadData1 and is mv
assign WriteIntD = ((FResultSelD == 3'b100)&Funct7D[3]) | (FResultSelD == 3'b101) | ((FResultSelD == 3'b001)&~Funct7D[2]) | ((FResultSelD == 3'b001)&OpD[6]);
// if not writting to int reg and not a store function and not move
assign FRegWriteD = ~WriteIntD & ~OpD[5] & ~((FResultSelD == 3'b111)&OpD[6]);
endmodule