2 Authors : Vinod.G, Arjun Menon, Aditya Govardhan
3 Email : g.vinod1993@gmail.com, c.arjunmenon@gmail.com
4 Last Update : 27th November 2017
5 See LICENSE for more details
11 package fpu_compare_min_max;
12 import defined_types::*;
13 `include "defined_parameters.bsv"
15 interface Ifc_fpu_compare_min_max#(numeric type fpinp, numeric type fpman, numeric type fpexp);
16 method ActionValue#(Floating_output#(fpinp)) _start(Bit#(fpinp) operand1,Bit#(fpinp) operand2, Bit#(3) which_cmp_instr,bit cmp_or_min_max,Tuple2#(Bit#(5),Bit#(5)) condFlags);
19 `ifdef fpu_hierarchical
20 interface Ifc_fpu_compare_min_max32;
21 method ActionValue#(Floating_output#(32)) _start(Bit#(32) operand1,Bit#(32) operand2, Bit#(3) which_cmp_instr,bit cmp_or_min_max,Tuple2#(Bit#(5),Bit#(5)) condFlags);
24 interface Ifc_fpu_compare_min_max64;
25 method ActionValue#(Floating_output#(64)) _start(Bit#(64) operand1,Bit#(64) operand2, Bit#(3) which_cmp_instr,bit cmp_or_min_max,Tuple2#(Bit#(5),Bit#(5)) condFlags);
31 function Bit#(2) fn_comparator(bit sign1, Bit#(fpexp) exponent1, Bit#(fpman) mantissa1, bit sign2, Bit#(fpexp) exponent2, Bit#(fpman) mantissa2);
33 Bit#(2) magnitude; //01 means inp2's magnitude is greater than inp1's magnitude
34 //10 means inp1's magnitude is greater than inp2's magnitude
35 //11 means inp2's magnitude is equal to inp1's magnitude
36 if(exponent1<exponent2)
38 else if(exponent1==exponent2)
40 if(mantissa1<mantissa2)
42 else if(mantissa1==mantissa2)
44 else magnitude = 2'b10;
57 return {magnitude[0],magnitude[1]};
63 module mkfpu_compare_min_max(Ifc_fpu_compare_min_max#(fpinp, fpman, fpexp))
65 Add#(TAdd#(fpexp,fpman),1,fpinp),
69 method ActionValue#(Floating_output#(fpinp)) _start(Bit#(fpinp) operand1,Bit#(fpinp) operand2, Bit#(3) which_cmp_instr,bit cmp_or_min_max,Tuple2#(Bit#(5),Bit#(5)) condFlags);
71 let fPMAN = valueOf(fpman);
72 let fPEXP = valueOf(fpexp);
73 let fPINP = valueOf(fpinp);
74 let flags1 = tpl_1(condFlags);
75 let flags2 = tpl_2(condFlags);
76 let sign1 = operand1[fPINP-1];
77 let sign2 = operand2[fPINP-1];
78 Bit#(fpexp) exponent1 = operand1[fPINP-2:fPMAN];
79 Bit#(fpexp) exponent2 = operand2[fPINP-2:fPMAN];
80 Bit#(fpman) mantissa1 = operand1[fPMAN-1:0];
81 Bit#(fpman) mantissa2 = operand2[fPMAN-1:0];
82 Bit#(5) lv_exception = 0;
84 Bit#(fpinp) lv_result = 0;
87 `ifdef verbose $display("operand1 : %h operand2: %h",operand1,operand2); `endif
89 bit lv_op1_is_qNan=flags1[2];
90 bit lv_op2_is_qNan=flags2[2];
91 bit lv_op1_is_sNan=flags1[0];
92 bit lv_op2_is_sNan=flags2[0];
93 bit lv_op1_Nan=lv_op1_is_qNan | lv_op1_is_sNan;
94 bit lv_op2_Nan=lv_op2_is_qNan | lv_op2_is_sNan;
95 bit or_sign = sign1 | sign2; //For accomodating spike's result ~ Spec is not clear!!!
96 bit and_sign = sign1 & sign2; //For accomodating spike's result ~ Spec is not clear!!!
98 if(lv_op1_is_qNan==1 || lv_op1_is_sNan==1 || lv_op2_is_qNan==1 || lv_op2_is_sNan==1)
101 if(flags1[3]==1 && flags2[3]==1)
104 Bit#(2) lv_compare_result = fn_comparator(sign1,exponent1,mantissa1,sign2,exponent2,mantissa2);
105 `ifdef verbose $display("lv_compare_result : %b sign1 %b exponent1 %b mantissa1 %b sign2 %b exponent2 %b mantissa2 %b",lv_compare_result,sign1,exponent1,mantissa1,sign2,exponent2,mantissa2); `endif
106 if(cmp_or_min_max=='b0) begin //checking if compare instruction
107 if(lv_invalid==1)begin
108 if(which_cmp_instr!=3'b010)
109 lv_exception[4] = 1; // Invalid
110 else if((flags1[0] | flags2[0])==1)
112 if((lv_op1_is_sNan | lv_op2_is_sNan)==1)
114 if(((lv_op1_is_qNan | lv_op2_is_qNan)==1) && which_cmp_instr!=3'b010)
117 else if(which_cmp_instr==3'b010) begin //FEQ.D, FEQ.S
118 `ifdef verbose $display("FEQ"); `endif
119 if(lv_compare_result==2'b11 || lv_zero==1) //checking if op1=op2
120 lv_result[0]=1; //writing result
122 else if(which_cmp_instr==3'b001) begin //FLT.D, FLT.S
123 `ifdef verbose $display("FLT lv_compare_result %b", lv_compare_result); `endif
124 if(lv_compare_result==2'b01 && lv_zero==0) //checking if op1<op2
125 //Also, if op1 is -0 and op2 is +0, lv_result[0] should be zero. lv_compare_is_zero takes care of that
126 lv_result[0]=1; //writing result
128 else if(which_cmp_instr==3'b000) begin //FLE.D, FLE.S
129 //`ifdef verbose $display("FLE"); `endif
130 if(lv_compare_result[0]==1'b1 || lv_zero==1) //checking if op1<=op2; since less than is 01 and equal to is 11, enough to check LSB
131 //Also, if op1 is +0 and op2 is -0, lv_result[0] should be zero. lv_compare_is_zero takes care of that
132 lv_result[0]=1; //writing result
136 /* According to IEEE 754-201x ratification Spec, they have introduced two operations called MinNum MaxNum, with a slightly different semantics with respect to NaN and (+0,-0) comparisons and the RISC-V spec chose to accomodate that, that change has been made here*/
137 Bit#(fpexp) exp_all_ones = '1;
138 Bit#(TSub#(fpman,1)) man_all_zeros = '0;
139 if(lv_op1_is_sNan==1 || lv_op2_is_sNan==1)
141 if((lv_op1_Nan&lv_op2_Nan)==1) begin
142 lv_result = {1'b0, exp_all_ones,1'b1, man_all_zeros};
144 else if(lv_op1_Nan==1) begin
146 //lv_exception[4] = 1;
148 else if(lv_op2_Nan==1) begin
150 //lv_exception[4] = 1;
152 else if((which_cmp_instr[0]==0 && lv_zero==1)) //FMIN.D, FMIN.S, and operands are 0
153 lv_result= {or_sign,truncate(operand2)};
154 else if((which_cmp_instr[0]==1 && lv_zero==1)) //FMAX.D, FMAX.S and operands are 0
155 lv_result= {and_sign,truncate(operand1)};
156 else if((which_cmp_instr[0]==0 && lv_compare_result==2'b01) || (which_cmp_instr[0]==1 && lv_compare_result==2'b10)) //FMIN.D, FMIN.S, FMAX.D, FMAX.S
158 else // in the alternate case of the above or if both the inputs are 0s (irrespective of +0 or -0 the output should be the first operand) or if both the inputs are the same magnitude.
161 return Floating_output{
162 final_result : lv_result,
163 fflags : lv_exception
170 `ifdef fpu_hierarchical
172 module mkfpu_compare_min_max32(Ifc_fpu_compare_min_max32);
173 Ifc_fpu_compare_min_max#(32,23,8) uut <- mkfpu_compare_min_max();
174 method ActionValue#(Floating_output#(32)) _start(Bit#(32) operand1,Bit#(32) operand2, Bit#(3) which_cmp_instr,bit cmp_or_min_max,Tuple2#(Bit#(5),Bit#(5)) condFlags);
175 let x <- uut._start(operand1,operand2,which_cmp_instr,cmp_or_min_max,condFlags);
181 module mkfpu_compare_min_max64(Ifc_fpu_compare_min_max64);
182 Ifc_fpu_compare_min_max#(64,52,11) uut <- mkfpu_compare_min_max();
183 method ActionValue#(Floating_output#(64)) _start(Bit#(64) operand1,Bit#(64) operand2, Bit#(3) which_cmp_instr,bit cmp_or_min_max,Tuple2#(Bit#(5),Bit#(5)) condFlags);
184 let x <- uut._start(operand1,operand2,which_cmp_instr,cmp_or_min_max,condFlags);
195 Reg#(Bit#(32)) rg_operand1 <- mkReg(32'h00000000);
196 Reg#(Bit#(32)) rg_operand2 <- mkReg(32'h0c4e2044);
197 Reg#(Bit#(32)) rg_clock <- mkReg(0);
198 Ifc_fpu_compare_min_max#(32,23,8) inst <- mkfpu_compare_min_max();
201 rg_clock <= rg_clock + 1;
204 rule rl_start_1(rg_clock=='d0);
205 `ifdef verbose $display("Giving Inputs to the compare module"); `endif
206 inst._start(rg_operand1, rg_operand2, 3'b000, 0);
209 rule rl_display_result;
210 let abc = inst.result_();
211 // inst._deque_buffer();
212 `ifdef verbose $display("Final Result = %h", abc.final_result); `endif
215 rule end_clock(rg_clock == 'd10);