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
|