OpenCores
URL https://opencores.org/ocsvn/m32632/m32632/trunk

Subversion Repositories m32632

[/] [m32632/] [trunk/] [rtl/] [SP_FPU.v] - Blame information for rev 37

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 29 ns32kum
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 9 ns32kum
//
3
// This file is part of the M32632 project
4
// http://opencores.org/project,m32632
5
//
6 23 ns32kum
//      Filename:       SP_FPU.v
7 29 ns32kum
//      Version:        3.0
8 23 ns32kum
//      History:        1.0 first release of 30 Mai 2015
9 29 ns32kum
//      Date:           2 December 2018
10 9 ns32kum
//
11 29 ns32kum
// Copyright (C) 2018 Udo Moeller
12 9 ns32kum
// 
13
// This source file may be used and distributed without 
14
// restriction provided that this copyright statement is not 
15
// removed from the file and that any derivative work contains 
16
// the original copyright notice and the associated disclaimer.
17
// 
18
// This source file is free software; you can redistribute it 
19
// and/or modify it under the terms of the GNU Lesser General 
20
// Public License as published by the Free Software Foundation;
21
// either version 2.1 of the License, or (at your option) any 
22
// later version. 
23
// 
24
// This source is distributed in the hope that it will be 
25
// useful, but WITHOUT ANY WARRANTY; without even the implied 
26
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
27
// PURPOSE. See the GNU Lesser General Public License for more 
28
// details. 
29
// 
30
// You should have received a copy of the GNU Lesser General 
31
// Public License along with this source; if not, download it 
32
// from http://www.opencores.org/lgpl.shtml 
33
// 
34 29 ns32kum
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
35 9 ns32kum
//
36 23 ns32kum
//      Testversion mit Pipeline Register in SFPU_ADDSUB **************
37
//
38 9 ns32kum
//      Modules contained in this file:
39
//      1. ADDSUB               Adder and Subtractor for 36 bit
40
//      2. SFPU_ADDSUB  Single Precision Floating Point Adder/Subtractor and Converter
41
//      3. SFPU_MUL             Single Precision Floating Point Multiplier
42
//      4. SP_FPU               Top Level of Single Precision Floating Point Unit
43
//
44 11 ns32kum
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
45 9 ns32kum
 
46 11 ns32kum
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
47 9 ns32kum
//
48
//      1. ADDSUB               Adder and Subtractor for 36 bit
49
//
50 11 ns32kum
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
51 9 ns32kum
module ADDSUB (dataa, datab, add_sub, result);
52
 
53
        input   [35:0]   dataa,datab;
54
        input                   add_sub;        // 1 = Addition , 0 = Subtraction
55
        output  [35:0]   result;
56
 
57
        assign result = dataa + (add_sub ? datab : ~datab) + {35'd0,~add_sub};
58
 
59
endmodule
60
 
61 11 ns32kum
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
62 9 ns32kum
//
63
//      2. SFPU_ADDSUB  Single Precision Floating Point Adder/Subtractor and Converter
64
//
65 11 ns32kum
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
66 23 ns32kum
module SFPU_ADDSUB ( BCLK, SRC1, SRC2, NZEXP, BWD, SELECT, OUT, IOUT, CMPRES );
67 9 ns32kum
 
68 23 ns32kum
        input                   BCLK;
69 9 ns32kum
        input   [31:0]   SRC1,SRC2;      // Input data
70
        input    [2:1]  NZEXP;
71
        input    [1:0]   BWD;            // size of integer
72
        input    [3:0]   SELECT;
73
 
74 23 ns32kum
        output          [36:0]   OUT;    // the result
75
        output  reg [31:0]       IOUT;   // result of ROUNDFi/TRUNCFi/FLOORFi
76
        output  reg  [1:0]       CMPRES;
77 9 ns32kum
 
78
        // ++++++++++++++++++++++++++++++++++
79
        // MOViF : 1. step
80
 
81 23 ns32kum
        reg  [31:0]      movdat;
82 9 ns32kum
        wire [31:0]      movif;
83
 
84
        always @(BWD or SRC1)
85 23 ns32kum
                casex(BWD)
86
                  2'b00 : movdat = {{24{SRC1[7]}}, SRC1[7:0]};   // Byte
87
                  2'b01 : movdat = {{16{SRC1[15]}},SRC1[15:0]};  // Word
88
                default : movdat =              SRC1[31:0];                              // Double
89 9 ns32kum
                endcase
90
 
91 23 ns32kum
        assign movif = ({32{movdat[31]}} ^ movdat) + {31'h0,movdat[31]};
92 9 ns32kum
                                                                // -2^31 is kept
93
 
94
        // ROUNDFi/TRUNCFi/FLOORFi : 1. step
95
 
96
        reg                     ovflag,ovflag2;
97
        wire [8:0]       rexdiff,rexo;
98 23 ns32kum
        reg                     rovfl;
99
        wire            minint;
100 9 ns32kum
        wire            ganzklein;      // Flag for 0
101
 
102
        assign rexdiff = 9'h09D - {1'b0,SRC1[30:23]};   // 4..0 is the right shift value
103 23 ns32kum
        always @(posedge BCLK) rovfl <= (ovflag | ovflag2) & (SELECT[1:0] == 2'b11) & ~minint;
104 9 ns32kum
        assign ganzklein = (~rexdiff[8] & (rexdiff[7:5] != 3'b000));    // 0 is implicit via SRC1[30:23]=0
105
 
106
        // Detection of Overflow
107
        assign rexo = ({1'b0,SRC1[30:23]} - {8'h3F,~BWD[1]});   // subtract B/W = 7F , D = 7E
108
 
109
        always @(BWD or rexo)
110
                casex (BWD)
111
                  2'b00 : ovflag = (~rexo[8] & (rexo[7:3] != 5'h0));    // Exponent 0..7 because of -128.4 => -128
112
                  2'b01 : ovflag = (~rexo[8] & (rexo[7:4] != 4'h0));    // Exponent 0..15 because of -128.4 => -128
113
                default : ovflag = (~rexo[8] & (rexo[7:5] != 3'h0));    // Exponent only 0..30 
114
                endcase
115
 
116
        assign minint = (SRC1 == 32'hCF00_0000) & BWD[1];       // detection of -2^31
117
 
118
        // ++++++++++++++++++++++++++++++++++
119
        // ADD/SUB : 1. step : which operand ist bigger ? if required exchange
120
        // SUB/CMP : SRC2 - SRC1
121
 
122
        wire  [8:0]      exdiff;
123
        wire [23:0]      madiff;
124 23 ns32kum
        wire            switch,sign1,sign2;
125
        reg                     variante;
126 9 ns32kum
        wire            vorz,addflag;
127 23 ns32kum
        wire [35:0]      result,result_sw,result_nosw;
128 9 ns32kum
        wire [24:0] value1,value2;
129 23 ns32kum
        wire            cmp_res;
130 9 ns32kum
 
131
        assign exdiff = {1'b0,SRC2[30:23]} - {1'b0,SRC1[30:23]};        // Difference of Exponents
132
        assign madiff = {1'b0,SRC2[22:0]}  - {1'b0,SRC1[22:0]};           // Difference of Mantissas
133
 
134 23 ns32kum
        // if exdiff = 0 the shifter to the right is not needed ! MUX at the end, ROUND/TRUNC/MOViF uses case 1
135
        always @(posedge BCLK) variante <= (exdiff[8:1] == 8'h00) | (exdiff == 9'h1FF) | SELECT[1];
136 9 ns32kum
 
137
// ++++++++++++++++++++++++++  1. case works on MOViF  +++++++++++++++++++++++++++++++++++++++
138
 
139
        assign switch = exdiff[8] | ((exdiff[7:0] == 8'h0) & madiff[23]);        // exchange ?
140
 
141
        assign value1 = exdiff[0] ? {1'b0,NZEXP[1],SRC1[22:0]} : {NZEXP[1],SRC1[22:0],1'b0};
142
        assign value2 = exdiff[0] ? {1'b0,NZEXP[2],SRC2[22:0]} : {NZEXP[2],SRC2[22:0],1'b0};
143
 
144
        // The Subtraction needs 3 Guard-Bits after LSB for rounding ! 36 Bit wide
145
        //                                                                                              1
146
        ADDSUB  addsub_nosw     (.dataa({1'b0,SRC2[30:23],NZEXP[2],SRC2[22:0],3'b000}),
147
                                                 .datab({9'h0,value1,2'b0}), .add_sub(addflag),
148
                                                 .result(result_nosw) );
149
 
150
        ADDSUB  addsub_sw       (.dataa({1'b0,SRC1[30:23],NZEXP[1],SRC1[22:0],3'b000}),
151
                                                 .datab({9'h0,value2,2'b0}), .add_sub(addflag),
152
                                                 .result(result_sw) );
153
 
154
        assign result = switch ? result_sw : result_nosw;
155
 
156
        //      SRC2   SRC1     : switch = 0            SRC2   SRC1 : switch = 1
157
        //        5  +   3  : +(5 + 3) =  8               3  +   5  : +(5 + 3) =  8             SELECT[0] = 0
158
        //        5  + (-3) : +(5 - 3) =  2               3  + (-5) : -(5 - 3) = -2
159
        //      (-5) +   3  : -(5 - 3) = -2             (-3) +   5  : +(5 - 3) =  2
160
        //      (-5) + (-3) : -(5 + 3) = -8             (-3) + (-5) : -(5 + 3) = -8
161
        //        5  -   3  : +(5 - 3) =  2               3  -   5  : -(5 - 3) = -2             SELECT[0] = 1
162
        //        5  - (-3) : +(5 + 3) =  8               3  - (-5) : +(5 + 3) =  8
163
        //      (-5) -   3  : -(5 + 3) = -8             (-3) -   5  : -(5 + 3) = -8
164
        //      (-5) - (-3) : -(5 - 3) = -2             (-3) - (-5) : +(5 - 3) =  2
165
 
166
        assign sign1 = SRC1[31];
167
        assign sign2 = SRC2[31];
168
 
169
        assign vorz    = switch ? (SELECT[0] ^ sign1) : sign2;
170
        assign addflag = ~(SELECT[0] ^ (sign1 ^ sign2));
171
 
172
        // CMPF : 1. step : what happend if Invalid Operand occurs - no Flag update !
173
 
174 23 ns32kum
        assign cmp_res = (SRC1 == SRC2) | (~NZEXP[2] & ~NZEXP[1]);              // Z-Bit : SRC1=SRC2, +0.0 = -0.0
175
        always @(posedge BCLK) CMPRES <= {(~cmp_res & (switch ? ~sign1 : sign2)),cmp_res};      // see table above : N-Bit=1 if SRC1 > SRC2     
176
 
177 9 ns32kum
        // ++++++++++++++++++++++++++++++++++
178
        // ADD/SUB : 3. step : prepare of Barrelshifter Left
179
 
180
        wire [31:0] blshift;
181 23 ns32kum
        reg   [9:0]      shiftl;
182 9 ns32kum
        wire            shift_16;
183 23 ns32kum
        reg      [33:0] add_q;
184 9 ns32kum
        wire [31:0]      muxsrc2;
185
        wire  [1:0] inex;
186
 
187
        assign blshift = SELECT[1] ? movif : {result[26:0],5'h00};       // Feeding of MOViF
188
 
189 23 ns32kum
        always @(posedge BCLK) shiftl <= SELECT[1] ? 10'h09E : {1'b0,result[35:27]};     // MOViF
190 9 ns32kum
 
191
        assign shift_16 = (blshift[31:16] == 16'h0000);
192
 
193
        // In case of ADD the result bypasses the Barrelshifter left
194 23 ns32kum
        always @(posedge BCLK) add_q <= (muxsrc2[24] != result[27]) ? {result[35:3],(result[2:0] != 3'b000)}
195
                                                                                                                                : {result[35:27],result[25:2],(result[1:0] != 2'b00)} ;
196 9 ns32kum
 
197
        // ++++++++++++++++++++++++++++++++++
198
        // ADD/SUB : 4. step : Barrelshifter left for SUB and MOViF :
199
 
200 23 ns32kum
        wire            shift_8,shift_4,shift_2,shift_1;
201 9 ns32kum
        wire  [1:0] lsb_bl;
202 23 ns32kum
        wire [31:0]      blshifta,blshiftc,blshiftd,blshifte;
203
        reg      [31:0] blshiftb;
204 9 ns32kum
        wire  [9:0]      expol;
205
        wire [36:0] out_v1;
206 23 ns32kum
        reg       [1:0]  rinex;
207
        reg                     zero,sign,select_v1;
208
        reg       [4:3] pshift;
209 9 ns32kum
 
210 23 ns32kum
        assign blshifta = shift_16 ? {blshift[15:0],16'd0}       : blshift;
211 9 ns32kum
        assign shift_8 = (blshifta[31:24] == 8'h00);
212 23 ns32kum
        always @(posedge BCLK)
213
                   blshiftb <= shift_8 ? {blshifta[23:0],8'd0}   : blshifta;
214 9 ns32kum
        assign shift_4 = (blshiftb[31:28] == 4'h0);
215 23 ns32kum
        assign blshiftc = shift_4  ? {blshiftb[27:0],4'd0}       : blshiftb;
216 9 ns32kum
        assign shift_2 = (blshiftc[31:30] == 2'b00);
217 23 ns32kum
        assign blshiftd = shift_2  ? {blshiftc[29:0],2'd0}       : blshiftc;
218 9 ns32kum
        assign shift_1 = ~blshiftd[31];
219 23 ns32kum
        assign blshifte = shift_1  ? {blshiftd[30:0],1'b0}       : blshiftd;
220 9 ns32kum
 
221 23 ns32kum
        always @(posedge BCLK) pshift  <= {shift_16,shift_8};
222
 
223 9 ns32kum
        // Overflow at ROUNDFi/TRUNCFi/FLOORFi via overflow in exponent shown, SELECT[1] is then 1 !
224 23 ns32kum
        assign expol = (shiftl - {5'h00,pshift,shift_4,shift_2,shift_1}) | {1'b0,rovfl,8'd0};
225 9 ns32kum
 
226 23 ns32kum
        always @(posedge BCLK) rinex <= inex;
227 9 ns32kum
        // Inexact at ROUNDFi/TRUNCFi/FLOORFi : evaluation for all one level higher
228 23 ns32kum
        assign lsb_bl = (SELECT[1:0] == 2'b11) ? rinex : {blshifte[7],(blshifte[6:0] != 7'd0)};
229 9 ns32kum
 
230 23 ns32kum
        always @(posedge BCLK) zero <=  (~SELECT[1] & ~NZEXP[2] & ~NZEXP[1])
231
                                                                  | ((blshift == 32'h0) & ((~addflag & ~SELECT[1]) | (SELECT[1:0] == 2'b10)));
232 9 ns32kum
 
233 23 ns32kum
        always @(posedge BCLK) sign <= SELECT[1] ? movdat[31] : vorz;
234 9 ns32kum
 
235 23 ns32kum
        always @(posedge BCLK) select_v1 <= addflag & ~SELECT[1];
236 9 ns32kum
 
237 23 ns32kum
        assign out_v1 = select_v1 ? {zero,sign,1'b0,add_q}
238
                                                          : {zero,sign,expol,blshifte[30:8],lsb_bl};
239
 
240 9 ns32kum
// +++++++++++++++++++++++++  2. case works on ROUND/TRUNC/FLOOR  ++++++++++++++++++++++++++++++++++
241
 
242
        wire            vswitch;
243
        wire  [4:0]      shift1,shift2;
244
        wire  [8:0]      exdiff12;
245
        wire [23:0]      muxsrc1;
246
        wire [32:9]     pipe1;  // numbering special for Right Shifter
247
        wire  [4:0]      shift;
248
 
249 11 ns32kum
// the difference between SRC1 and SRC2 is bigger/equal 4:1 => no Barrelshifter after ADDSUB neccessary
250 9 ns32kum
 
251
        assign vswitch = exdiff[8];     // exchange ?
252
 
253
        assign shift1 = (exdiff[7:5] != 3'h0) ? 5'h1F : exdiff[4:0];
254
        assign exdiff12 = {1'b0,SRC1[30:23]} - {1'b0,SRC2[30:23]};      // caclulate already
255
        assign shift2 = (exdiff12[7:5] != 3'h0) ? 5'h1F : exdiff12[4:0];
256
 
257 11 ns32kum
        assign muxsrc2 = vswitch ? {SRC1[30:23],1'b1,SRC1[22:0]} : {SRC2[30:23],1'b1,SRC2[22:0]}; // Including exponent
258 9 ns32kum
        assign muxsrc1 = vswitch ? {NZEXP[2],SRC2[22:0]} : {NZEXP[1],SRC1[22:0]};
259
 
260 11 ns32kum
        assign pipe1 = SELECT[1] ? (ganzklein ? 24'h0 : {NZEXP[1],SRC1[22:0]}) : muxsrc1;        // Feeding in R.T.F.
261 9 ns32kum
 
262
        assign shift = SELECT[1] ? rexdiff[4:0] : (vswitch ? shift2 : shift1);
263
 
264
        // ++++++++++++++++++++++++++++++++++
265
        // ADD/SUB + ROUND/TRUNC/FLOOR : 2. step : Barrelshifter to right -->
266
 
267
        wire [32:0] brshifta,brshiftb,brshiftc,brshiftd;
268
        wire [32:0] brshifte;    // last stage
269
 
270
        // 33322222222221111111111
271
        // 2109876543210987654321098765432-10
272
        // 1VVVVVVVVVVVVVVVVVVVVVVV0000000-00   // last 2 Bit for rounding
273
 
274
        assign brshifta = shift[4] ? {16'h0,pipe1[32:17],  (pipe1[16:9]   != 8'h00)}  : {pipe1,9'h0};
275
        assign brshiftb = shift[3] ? { 8'h0,brshifta[32:9],(brshifta[8:0] != 9'h000)} : brshifta;
276
        assign brshiftc = shift[2] ? { 4'h0,brshiftb[32:5],(brshiftb[4:0] != 5'h00)}  : brshiftb;
277
        assign brshiftd = shift[1] ? { 2'h0,brshiftc[32:3],(brshiftc[2:0] != 3'h0)}   : brshiftc;
278
        assign brshifte = shift[0] ? { 1'b0,brshiftd[32:2],(brshiftd[1:0] != 2'h0)}   : brshiftd;
279
 
280
        // ++++++++++++++++++++++++++++++++++
281
        // ROUNDFi/TRUNCFi/FLOORFi : 3. step : round to integer
282
 
283
        reg                     car_ry;
284 23 ns32kum
        wire [32:0] iadder;
285 9 ns32kum
 
286
        assign inex = brshifte[1:0];             // Inexact-Flag-Data via multiplexer at the end
287
 
288
        always @(SELECT or sign1 or brshifte or inex or ganzklein)
289
                casex (SELECT[3:2])
290
                    2'b00 : car_ry = sign1 ^ ((brshifte[2:0] == 3'b110) | (inex == 2'b11));      // ROUNDLi
291 11 ns32kum
                    2'b1x : car_ry = sign1 ? (~ganzklein & (inex == 2'b00)) : 1'b0;     // +numbers like TRUNCLi, -numbers round to "-infinity"
292 9 ns32kum
                  default : car_ry = sign1;     // TRUNCLi , simple cut
293
                endcase
294
 
295 23 ns32kum
        assign iadder = (sign1 ? {2'b11,~brshifte[32:2]} : {2'b0,brshifte[32:2]}) + {32'h0,car_ry};
296 9 ns32kum
 
297 23 ns32kum
        always @(posedge BCLK) IOUT <= minint ? 32'h8000_0000 : iadder[31:0];
298 9 ns32kum
 
299
        always @(iadder or BWD or sign1)        // special overflow detection i.e. -129 bis -255 bei Byte
300
                casex (BWD)                                             // or 127.9 -> 128 = Fehler !
301
                  2'b00 : ovflag2 = (iadder[8]  != iadder[7]);  // Byte
302
                  2'b01 : ovflag2 = (iadder[16] != iadder[15]); // Word
303 23 ns32kum
                default : ovflag2 = (iadder[32] != iadder[31]); // Double
304 9 ns32kum
                endcase
305
 
306
        // ++++++++++++++++++++++++++++++++++
307
        // only ADD/SUB : 3. step : Add or Subtract
308
        // the modul ADDSUB integrates the carry from the mantissa : 35 Bit
309
 
310
        wire            lsb;
311
        wire [35:0]      vresult;
312
        wire  [7:0]      eminus1;
313
        wire [33:0] vadd_q,vsub_q;
314
        wire            vzero;
315 23 ns32kum
        reg      [36:0] out_v0;
316 9 ns32kum
 
317
        assign lsb = (brshifte[6:0] != 7'h00);
318
 
319
        // Adder-Definition : "0"(8 Bit Exponent)"1"(23 Bit Mantissa)"000"
320
 
321
        ADDSUB  addsub_v        (.dataa({1'b0,muxsrc2,3'b000}),
322
                                                 .datab({9'h0,brshifte[32:7],lsb}), .add_sub(addflag),
323
                                                 .result(vresult) );
324
 
325 11 ns32kum
        assign eminus1 = muxsrc2[31:24] - 8'h01;        // a greater Underflow can not exist, because minimal Exponent = 0..01
326 9 ns32kum
 
327
        // Case ADD : Bit 23 : LSB of exponent
328
        assign vadd_q = (muxsrc2[24] != vresult[27]) ? {vresult[35:3],(vresult[2:0] != 3'b000)}
329
                                                                                                 : {vresult[35:27],vresult[25:2],(vresult[1:0] != 2'b00)} ;
330
 
331
        // Case SUB : Bit 26 : "hidden" MSB of mantissa
332 11 ns32kum
        assign vsub_q = vresult[26] ? {vresult[35:27],     vresult[25:2],(vresult[1:0] != 2'b00)}        // like the vadd_q "0" case
333 9 ns32kum
                                                            : {vresult[35],eminus1,vresult[24:0]} ;
334
 
335
        // SELECT[1] has here no meaning
336 23 ns32kum
        assign vzero = (vresult[26:0] == 27'h0); // only if "-" can be the result 0
337 9 ns32kum
 
338 23 ns32kum
        always @(posedge BCLK) out_v0 <= addflag ? { 1'b0,vorz,1'b0,vadd_q}
339
                                                                                         : {vzero,vorz,1'b0,vsub_q} ;
340 9 ns32kum
 
341
        assign OUT = variante ? out_v1 : out_v0;        // Last multiplexer
342
 
343
endmodule
344
 
345 11 ns32kum
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
346 9 ns32kum
//
347
//      3. SFPU_MUL             Single Precision Floating Point Multiplier
348
//
349 11 ns32kum
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
350 29 ns32kum
module SFPU_MUL ( BCLK, SRC1, SRC2, NZEXP, OUT);
351 9 ns32kum
 
352 23 ns32kum
        input                   BCLK;
353 9 ns32kum
        input   [31:0]   SRC1,SRC2;      // only exponent of input data used
354
        input    [2:1]  NZEXP;          // Flags of input data
355
 
356 23 ns32kum
        output  reg     [36:0]   OUT;            // The result
357 9 ns32kum
 
358 29 ns32kum
        wire    [47:0]   mresult;
359
        wire     [9:0]   exponent,expoh,expol;
360
        wire     [1:0]   restlow,resthigh;
361
        wire                    zero,sign,orlow;
362 9 ns32kum
 
363 29 ns32kum
        assign mresult = {1'b1,SRC1[22:0]} * {1'b1,SRC2[22:0]};   // Unsigned Multiplier
364
 
365 9 ns32kum
        assign zero =   ~NZEXP[2] | ~NZEXP[1];  // one of both NULL -> NULL is the result
366
        assign sign =   (SRC1[31] ^ SRC2[31]) & ~zero;
367 29 ns32kum
        assign orlow =  (mresult[21:0] != 22'b0);
368 9 ns32kum
 
369 29 ns32kum
        assign restlow  = {mresult[22],orlow};
370
        assign resthigh = {mresult[23],(mresult[22] | orlow)};
371 9 ns32kum
 
372
        assign exponent = {2'b00,SRC1[30:23]} + {2'b00,SRC2[30:23]};
373
        assign expoh    = exponent - 10'h07E;
374 29 ns32kum
        assign expol    = exponent - 10'h07F;    // for MSB if mresult=0
375 9 ns32kum
 
376 29 ns32kum
        always @(posedge BCLK) OUT <= mresult[47] ? {zero,sign,expoh,mresult[46:24],resthigh}
377
                                                                                          : {zero,sign,expol,mresult[45:23],restlow};
378 9 ns32kum
 
379
endmodule
380
 
381 11 ns32kum
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
382 9 ns32kum
//
383
//      4. SP_FPU               Top Level of Single Precision Floating Point Unit
384
//
385 11 ns32kum
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
386 29 ns32kum
module SP_FPU (BCLK, START, OPCODE, SRC1, SRC2, FSR, BWD, FL, FP_OUT, I_OUT, TT_SP, SP_CMP, SP_MUX, LD_FSR, UP_SP);
387 9 ns32kum
 
388
        input                   BCLK;           // is not used !
389 23 ns32kum
        input                   START;
390 9 ns32kum
        input    [7:0]   OPCODE;
391
        input   [31:0]   SRC1,SRC2;      // Input data
392
        input    [8:3]  FSR;            // Floating Point Status Register
393
        input    [1:0]   BWD;            // Size of integer
394
        input                   FL;
395
 
396
        output  [31:0]   FP_OUT,I_OUT;   // The results
397
        output   [4:0]   TT_SP;          // Trap-Type
398
        output   [2:0]   SP_CMP;         // CMPF result
399 23 ns32kum
        output                  SP_MUX,LD_FSR;
400
        output  reg             UP_SP;
401 9 ns32kum
 
402
        reg              [2:0]   tt;
403
        reg              [3:0]   select;
404 23 ns32kum
        reg                             nan;
405 9 ns32kum
        reg                             car_ry;
406
 
407
        wire    [36:0]   mulout,addout,fpout;
408
        wire     [2:1]  nzexp;
409
        wire    [34:2]  rund;           // Indexnumbers like xxxout
410
        wire                    overflow,underflow,inexact;
411
        wire                    op_cmp;
412 23 ns32kum
        wire                    nan_1,nan_2;
413 9 ns32kum
 
414
        // Control of datapath 
415
 
416
        always @(OPCODE)
417
                casex (OPCODE)
418
                  8'b1011_0000 : select = 4'b1000;      // 0 0 0 :      ADDF    Shifter are reused
419
                  8'b1011_0100 : select = 4'b1001;      // 0 0 1 :      SUBF
420
                  8'b1001_000x : select = 4'b1010;      // 0 1 0 :      MOViF
421
                  8'b1001_100x : select = 4'b1011;      // 0 1 1 :      ROUNDFi
422
                  8'b1001_101x : select = 4'b1011;      // 0 1 1 :      TRUNCFi
423
                  8'b1001_111x : select = 4'b1011;      // 0 1 1 :      FLOORFi
424
                  8'b1011_0010 : select = 4'b1001;      // 0 0 1 :      CMPF
425
                  8'b1011_1100 : select = 4'b1100;      // 1 x x :      MULF
426
                  default      : select = 4'b0;
427
                endcase
428
 
429
        assign SP_MUX = select[3] & (select[1:0] != 2'b11) & FL; // Output multiplexer
430
 
431 11 ns32kum
        assign LD_FSR = (OPCODE[7:4] == 4'h9) & (OPCODE[3:1] == 3'b001);        // LFSR does only Double (according datasheet NS32016)
432 23 ns32kum
        always @(posedge BCLK) UP_SP = select[3] & FL & START;                          // All FPU opcodes of SP_FPU, all are using 2 Clock
433 9 ns32kum
        assign op_cmp = (OPCODE == 8'hB2) & FL;
434
 
435
        // SRCFLAGS
436
 
437
        assign nzexp[2] = (SRC2[30:23] != 8'd0);                // only exponent 0 ,denormalized Number => NAN !
438
        assign nzexp[1] = (SRC1[30:23] != 8'd0);                // only exponent 0 ,denormalized Number => NAN !
439
        assign nan_2    = (SRC2[30:23] == 8'hFF) | (~nzexp[2] & (SRC2[22:0] != 23'd0));  // NAN
440
        assign nan_1    = (SRC1[30:23] == 8'hFF) | (~nzexp[1] & (SRC1[22:0] != 23'd0));  // NAN
441
 
442 23 ns32kum
        always @(posedge BCLK) nan <= (select[1:0] == 2'b11) ? nan_1 : (~select[1] & (nan_2 | nan_1));
443 9 ns32kum
 
444
        // 001 : ADDF,... + 011 : CMPF
445 23 ns32kum
        SFPU_ADDSUB IADDSUB     ( .BCLK(BCLK), .SRC1(SRC1), .SRC2(SRC2), .NZEXP(nzexp), .BWD(BWD),
446 9 ns32kum
                                                  .SELECT({OPCODE[2:1],select[1:0]}), .OUT(addout), .IOUT(I_OUT), .CMPRES(SP_CMP[1:0]) );
447
 
448
        // 100 : MULF
449 29 ns32kum
        SFPU_MUL IMUL ( .BCLK(BCLK), .SRC1(SRC1), .SRC2(SRC2), .NZEXP(nzexp), .OUT(mulout) );
450 9 ns32kum
 
451
        // FP - Pfad : selection of result and rounding :
452
 
453
        assign fpout = (OPCODE[5] & OPCODE[3]) ? mulout : addout;
454
 
455
        always @(FSR or fpout)  // calculate Carry according rounding mode, fpout[35] = sign bit
456
                casex (FSR[8:7])
457
                  2'b00 : car_ry = ((fpout[1:0] == 2'b10) & fpout[2]) | (fpout[1:0] == 2'b11);    // round to nearest
458
                  2'b10 : car_ry = ~fpout[35] & (fpout[1:0] != 2'b00);   // round to positiv infinity
459
                  2'b11 : car_ry =  fpout[35] & (fpout[1:0] != 2'b00);   // round to negativ infinity
460
                default : car_ry = 1'b0;                                                                // round to zero
461
                endcase
462
 
463
        assign rund = {fpout[34:2]} + {32'h0,car_ry};
464
 
465
        // Detection of Overflow, Underflow and Inexact : epxonent is [34:25] = 10 Bits
466
        assign overflow  = ~rund[34] & (rund[33] | (rund[32:25] == 8'hFF));
467
        assign underflow = (rund[34] | (rund[33:25] == 9'h0)) & ~fpout[36];     // Zero-Flag
468
        assign inexact   = (fpout[1:0] != 2'b00);
469
 
470
        // CMPF can have no other error except NAN 
471
        always @(nan or op_cmp or overflow or underflow or inexact or FSR)
472
                casex ({nan,op_cmp,overflow,FSR[3],underflow,FSR[5],inexact})
473
                        7'b1xxxxxx : tt = 3'b101;       // Invalid operation
474
                        7'b001xxxx : tt = 3'b010;       // Overflow
475
                        7'b00011xx : tt = 3'b001;       // Underflow
476
                        7'b0000011 : tt = 3'b110;       // Inexact Result
477
                        default    : tt = 3'b000;       // no error
478
                endcase
479
 
480
        assign TT_SP = {(inexact & ~op_cmp),(underflow & ~op_cmp),tt};
481
        assign SP_CMP[2] = nan;
482
 
483
        // Underflow Special case and force ZERO 
484
        assign FP_OUT = (underflow | fpout[36]) ? 32'd0 : {fpout[35],rund[32:2]};
485
 
486
endmodule

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.