replace defined_parameters with core_parameters
[shakti-core.git] / src / core / fpu / fpu_compare_min_max.bsv
1 /*
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
6 Description:
7 TODO
8 */
9
10
11 package fpu_compare_min_max;
12 import defined_types::*;
13 `include "core_parameters.bsv"
14
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);
17 endinterface
18
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);
22 endinterface
23
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);
26 endinterface
27 `endif
28
29
30 //(*noinline*)
31 function Bit#(2) fn_comparator(bit sign1, Bit#(fpexp) exponent1, Bit#(fpman) mantissa1, bit sign2, Bit#(fpexp) exponent2, Bit#(fpman) mantissa2);
32
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)
37 magnitude= 2'b01;
38 else if(exponent1==exponent2)
39 begin
40 if(mantissa1<mantissa2)
41 magnitude = 2'b01;
42 else if(mantissa1==mantissa2)
43 magnitude = 2'b11;
44 else magnitude = 2'b10;
45 end
46 else
47 magnitude = 2'b10;
48
49 if(sign1==0) begin
50 if(sign2==1)
51 return 2'b10;
52 else
53 return magnitude;
54 end
55 else begin
56 if(sign2==1)
57 return {magnitude[0],magnitude[1]};
58 else
59 return 2'b01;
60 end
61 endfunction
62
63 module mkfpu_compare_min_max(Ifc_fpu_compare_min_max#(fpinp, fpman, fpexp))
64 provisos(
65 Add#(TAdd#(fpexp,fpman),1,fpinp),
66 Add#(fpman,1,fpman1)
67 );
68
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);
70
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;
83
84 Bit#(fpinp) lv_result = 0;
85 bit lv_invalid = 0;
86 bit lv_zero = 0;
87 `ifdef verbose $display("operand1 : %h operand2: %h",operand1,operand2); `endif
88
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!!!
97
98 if(lv_op1_is_qNan==1 || lv_op1_is_sNan==1 || lv_op2_is_qNan==1 || lv_op2_is_sNan==1)
99 lv_invalid=1;
100
101 if(flags1[3]==1 && flags2[3]==1)
102 lv_zero = 1;
103
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)
111 lv_exception[4] = 1;
112 if((lv_op1_is_sNan | lv_op2_is_sNan)==1)
113 lv_result=0;
114 if(((lv_op1_is_qNan | lv_op2_is_qNan)==1) && which_cmp_instr!=3'b010)
115 lv_result=0;
116 end
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
121 end
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
127 end
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
133 end
134 end
135 else begin
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)
140 lv_exception[4] = 1;
141 if((lv_op1_Nan&lv_op2_Nan)==1) begin
142 lv_result = {1'b0, exp_all_ones,1'b1, man_all_zeros};
143 end
144 else if(lv_op1_Nan==1) begin
145 lv_result=operand2;
146 //lv_exception[4] = 1;
147 end
148 else if(lv_op2_Nan==1) begin
149 lv_result=operand1;
150 //lv_exception[4] = 1;
151 end
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
157 lv_result= operand1;
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.
159 lv_result= operand2;
160 end
161 return Floating_output{
162 final_result : lv_result,
163 fflags : lv_exception
164 };
165 endmethod
166
167 endmodule
168
169
170 `ifdef fpu_hierarchical
171 (*synthesize*)
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);
176 return x;
177 endmethod
178 endmodule
179
180 (*synthesize*)
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);
185 return x;
186 endmethod
187 endmodule
188 `endif
189
190
191
192
193 /*
194 module mkTb(Empty);
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();
199
200 rule rg_clock_cnt;
201 rg_clock <= rg_clock + 1;
202 endrule
203
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);
207 endrule
208
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
213 endrule
214
215 rule end_clock(rg_clock == 'd10);
216 $finish(0);
217 endrule
218 endmodule
219 */
220 endpackage