Initial Commit (steal code from https://github.com/jop-devel/jop)
[ipdf/vfpu.git] / src / fpu.vhd
1 -------------------------------------------------------------------------------
2 --
3 -- Project:     <Floating Point Unit Core>
4 --      
5 -- Description: top entity
6 -------------------------------------------------------------------------------
7 --
8 --                              100101011010011100100
9 --                              110000111011100100000
10 --                              100000111011000101101
11 --                              100010111100101111001
12 --                              110000111011101101001
13 --                              010000001011101001010
14 --                              110100111001001100001
15 --                              110111010000001100111
16 --                              110110111110001011101
17 --                              101110110010111101000
18 --                              100000010111000000000
19 --
20 --      Author:          Jidan Al-eryani 
21 --      E-mail:          [email protected]
22 --
23 --  Copyright (C) 2006
24 --
25 --      This source file may be used and distributed without        
26 --      restriction provided that this copyright statement is not   
27 --      removed from the file and that any derivative work contains 
28 --      the original copyright notice and the associated disclaimer.
29 --                                                           
30 --              THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY     
31 --      EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   
32 --      TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS   
33 --      FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR      
34 --      OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,         
35 --      INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    
36 --      (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE   
37 --      GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR        
38 --      BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF  
39 --      LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT  
40 --      (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  
41 --      OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE         
42 --      POSSIBILITY OF SUCH DAMAGE. 
43 --
44
45
46 library ieee;
47 use ieee.std_logic_1164.all;
48 use ieee.numeric_std.all;
49 use ieee.std_logic_misc.all;
50
51 library work;
52 use work.comppack.all;
53 use work.fpupack.all;
54
55
56 entity fpu is
57     port (
58         clk_i                   : in std_logic;
59
60         -- Input Operands A & B
61         opa_i           : in std_logic_vector(FP_WIDTH-1 downto 0);  -- Default: FP_WIDTH=32 
62         opb_i           : in std_logic_vector(FP_WIDTH-1 downto 0);
63         
64         -- fpu operations (fpu_op_i):
65                 -- ========================
66                 -- 000 = add, 
67                 -- 001 = substract, 
68                 -- 010 = multiply, 
69                 -- 011 = divide,
70                 -- 100 = square root
71                 -- 101 = unused
72                 -- 110 = unused
73                 -- 111 = unused
74         fpu_op_i                : in std_logic_vector(2 downto 0);
75         
76         -- Rounding Mode: 
77         -- ==============
78         -- 00 = round to nearest even(default), 
79         -- 01 = round to zero, 
80         -- 10 = round up, 
81         -- 11 = round down
82         rmode_i                 : in std_logic_vector(1 downto 0);
83         
84         -- Output port   
85         output_o        : out std_logic_vector(FP_WIDTH-1 downto 0);
86         
87         -- Control signals
88         start_i                 : in std_logic; -- is also restart signal
89         ready_o                 : out std_logic;
90         
91         -- Exceptions
92         ine_o                   : out std_logic; -- inexact
93         overflow_o      : out std_logic; -- overflow
94         underflow_o     : out std_logic; -- underflow
95         div_zero_o      : out std_logic; -- divide by zero
96         inf_o                   : out std_logic; -- infinity
97         zero_o                  : out std_logic; -- zero
98         qnan_o                  : out std_logic; -- queit Not-a-Number
99         snan_o                  : out std_logic -- signaling Not-a-Number
100         );   
101 end fpu;
102
103 architecture rtl of fpu is
104     
105
106         constant MUL_SERIAL: integer range 0 to 1 := 1; -- 0 for parallel multiplier, 1 for serial
107         constant MUL_COUNT: integer:= 34; --11 for parallel multiplier, 34 for serial
108                 
109         -- Input/output registers
110         signal s_opa_i, s_opb_i : std_logic_vector(FP_WIDTH-1 downto 0);
111         signal s_fpu_op_i               : std_logic_vector(2 downto 0);
112         signal s_rmode_i : std_logic_vector(1 downto 0);
113         signal s_output_o : std_logic_vector(FP_WIDTH-1 downto 0);
114     signal s_ine_o, s_overflow_o, s_underflow_o, s_div_zero_o, s_inf_o, s_zero_o, s_qnan_o, s_snan_o : std_logic;
115         
116         type   t_state is (waiting,busy);
117         signal s_state : t_state;
118         signal s_start_i : std_logic;
119         signal s_count : integer;
120         signal s_output1 : std_logic_vector(FP_WIDTH-1 downto 0);       
121         signal s_infa, s_infb : std_logic;
122         
123         --      ***Add/Substract units signals***
124
125         signal prenorm_addsub_fracta_28_o, prenorm_addsub_fractb_28_o : std_logic_vector(27 downto 0);
126         signal prenorm_addsub_exp_o : std_logic_vector(7 downto 0); 
127         
128         signal addsub_fract_o : std_logic_vector(27 downto 0); 
129         signal addsub_sign_o : std_logic;
130         
131         signal postnorm_addsub_output_o : std_logic_vector(31 downto 0); 
132         signal postnorm_addsub_ine_o : std_logic;
133         
134         --      ***Multiply units signals***
135         
136         signal pre_norm_mul_exp_10 : std_logic_vector(9 downto 0);
137         signal pre_norm_mul_fracta_24   : std_logic_vector(23 downto 0);
138         signal pre_norm_mul_fractb_24   : std_logic_vector(23 downto 0);
139                 
140         signal mul_24_fract_48 : std_logic_vector(47 downto 0);
141         signal mul_24_sign      : std_logic;
142         signal serial_mul_fract_48 : std_logic_vector(47 downto 0);
143         signal serial_mul_sign  : std_logic;
144         
145         signal mul_fract_48: std_logic_vector(47 downto 0);
146         signal mul_sign: std_logic;
147         
148         signal post_norm_mul_output     : std_logic_vector(31 downto 0);
149         signal post_norm_mul_ine        : std_logic;
150         
151         --      ***Division units signals***
152         
153         signal pre_norm_div_dvdnd : std_logic_vector(49 downto 0);
154         signal pre_norm_div_dvsor : std_logic_vector(26 downto 0);
155         signal pre_norm_div_exp : std_logic_vector(EXP_WIDTH+1 downto 0);
156         
157         signal serial_div_qutnt : std_logic_vector(26 downto 0);
158         signal serial_div_rmndr : std_logic_vector(26 downto 0);
159         signal serial_div_sign : std_logic;
160         signal serial_div_div_zero : std_logic;
161         
162         signal post_norm_div_output : std_logic_vector(31 downto 0);
163         signal post_norm_div_ine : std_logic;
164         
165         --      ***Square units***
166         
167         signal pre_norm_sqrt_fracta_o           : std_logic_vector(51 downto 0);
168         signal pre_norm_sqrt_exp_o                              : std_logic_vector(7 downto 0);
169                          
170         signal sqrt_sqr_o                       : std_logic_vector(25 downto 0);
171         signal sqrt_ine_o                       : std_logic;
172
173         signal post_norm_sqrt_output    : std_logic_vector(31 downto 0);
174         signal post_norm_sqrt_ine_o             : std_logic;
175         
176         
177 begin
178         --***Add/Substract units***
179         
180         i_prenorm_addsub: pre_norm_addsub
181         port map (
182           clk_i => clk_i,
183                                 opa_i => s_opa_i,
184                                 opb_i => s_opb_i,
185                                 fracta_28_o => prenorm_addsub_fracta_28_o,
186                                 fractb_28_o => prenorm_addsub_fractb_28_o,
187                                 exp_o=> prenorm_addsub_exp_o);
188                                 
189         i_addsub: addsub_28
190                 port map(
191                          clk_i => clk_i,                        
192                          fpu_op_i => s_fpu_op_i(0),              
193                          fracta_i       => prenorm_addsub_fracta_28_o,  
194                          fractb_i       => prenorm_addsub_fractb_28_o,          
195                          signa_i =>  s_opa_i(31),                       
196                          signb_i =>  s_opb_i(31),                               
197                          fract_o => addsub_fract_o,                     
198                          sign_o => addsub_sign_o);      
199                          
200         i_postnorm_addsub: post_norm_addsub
201         port map(
202                 clk_i => clk_i,         
203                 opa_i => s_opa_i,
204                 opb_i => s_opb_i,       
205                 fract_28_i => addsub_fract_o,
206                 exp_i => prenorm_addsub_exp_o,
207                 sign_i => addsub_sign_o,
208                 fpu_op_i => s_fpu_op_i(0), 
209                 rmode_i => s_rmode_i,
210                 output_o => postnorm_addsub_output_o,
211                 ine_o => postnorm_addsub_ine_o
212                 );
213         
214         --***Multiply units***
215         
216         i_pre_norm_mul: pre_norm_mul
217         port map(
218                 clk_i => clk_i,         
219                 opa_i => s_opa_i,
220                 opb_i => s_opb_i,
221                 exp_10_o => pre_norm_mul_exp_10,
222                 fracta_24_o     => pre_norm_mul_fracta_24,
223                 fractb_24_o     => pre_norm_mul_fractb_24);
224                                 
225         i_mul_24 : mul_24
226         port map(
227                          clk_i => clk_i,
228                          fracta_i => pre_norm_mul_fracta_24,
229                          fractb_i => pre_norm_mul_fractb_24,
230                          signa_i => s_opa_i(31),
231                          signb_i => s_opb_i(31),
232                          start_i => start_i,
233                          fract_o => mul_24_fract_48, 
234                          sign_o =>      mul_24_sign,
235                          ready_o => open);      
236                          
237         i_serial_mul : serial_mul
238         port map(
239                          clk_i => clk_i,
240                          fracta_i => pre_norm_mul_fracta_24,
241                          fractb_i => pre_norm_mul_fractb_24,
242                          signa_i => s_opa_i(31),
243                          signb_i => s_opb_i(31),
244                          start_i => s_start_i,
245                          fract_o => serial_mul_fract_48, 
246                          sign_o =>      serial_mul_sign,
247                          ready_o => open);      
248         
249         -- serial or parallel multiplier will be choosed depending on constant MUL_SERIAL
250         mul_fract_48 <= mul_24_fract_48 when MUL_SERIAL=0 else serial_mul_fract_48;
251         mul_sign <= mul_24_sign when MUL_SERIAL=0 else serial_mul_sign;
252         
253         i_post_norm_mul : post_norm_mul
254         port map(
255                          clk_i => clk_i,
256                          opa_i => s_opa_i,
257                          opb_i => s_opb_i,
258                          exp_10_i => pre_norm_mul_exp_10,
259                          fract_48_i     => mul_fract_48,
260                          sign_i => mul_sign,
261                          rmode_i => s_rmode_i,
262                          output_o => post_norm_mul_output,
263                          ine_o => post_norm_mul_ine
264                         );
265                 
266         --***Division units***
267         
268         i_pre_norm_div : pre_norm_div
269         port map(
270                          clk_i => clk_i,
271                          opa_i => s_opa_i,
272                          opb_i => s_opb_i,
273                          exp_10_o => pre_norm_div_exp,
274                          dvdnd_50_o     => pre_norm_div_dvdnd,
275                          dvsor_27_o     => pre_norm_div_dvsor);
276                          
277         i_serial_div : serial_div
278         port map(
279                          clk_i=> clk_i,
280                          dvdnd_i => pre_norm_div_dvdnd,
281                          dvsor_i => pre_norm_div_dvsor,
282                          sign_dvd_i => s_opa_i(31),
283                          sign_div_i => s_opb_i(31),
284                          start_i => s_start_i,
285                          ready_o => open,
286                          qutnt_o => serial_div_qutnt,
287                          rmndr_o => serial_div_rmndr,
288                          sign_o => serial_div_sign,
289                          div_zero_o     => serial_div_div_zero);
290         
291         i_post_norm_div : post_norm_div
292         port map(
293                          clk_i => clk_i,
294                          opa_i => s_opa_i,
295                          opb_i => s_opb_i,
296                          qutnt_i =>     serial_div_qutnt,
297                          rmndr_i => serial_div_rmndr,
298                          exp_10_i => pre_norm_div_exp,
299                          sign_i => serial_div_sign,
300                          rmode_i =>     s_rmode_i,
301                          output_o => post_norm_div_output,
302                          ine_o => post_norm_div_ine);
303                          
304         
305         --***Square units***
306
307         i_pre_norm_sqrt : pre_norm_sqrt
308         port map(
309                          clk_i => clk_i,
310                          opa_i => s_opa_i,
311                          fracta_52_o => pre_norm_sqrt_fracta_o,
312                          exp_o => pre_norm_sqrt_exp_o);
313                 
314         i_sqrt: sqrt 
315         generic map(RD_WIDTH=>52, SQ_WIDTH=>26) 
316         port map(
317                          clk_i => clk_i,
318                          rad_i => pre_norm_sqrt_fracta_o, 
319                          start_i => s_start_i, 
320                          ready_o => open, 
321                          sqr_o => sqrt_sqr_o,
322                          ine_o => sqrt_ine_o);
323
324         i_post_norm_sqrt : post_norm_sqrt
325         port map(
326                         clk_i => clk_i,
327                         opa_i => s_opa_i,
328                         fract_26_i => sqrt_sqr_o,
329                         exp_i => pre_norm_sqrt_exp_o,
330                         ine_i => sqrt_ine_o,
331                         rmode_i => s_rmode_i,
332                         output_o => post_norm_sqrt_output,
333                         ine_o => post_norm_sqrt_ine_o);
334                         
335                         
336                         
337 -----------------------------------------------------------------                       
338
339         -- Input Register
340         process(clk_i)
341         begin
342                 if rising_edge(clk_i) then      
343                         s_opa_i <= opa_i;
344                         s_opb_i <= opb_i;
345                         s_fpu_op_i <= fpu_op_i;
346                         s_rmode_i <= rmode_i;
347                         s_start_i <= start_i;
348                 end if;
349         end process;
350           
351         -- Output Register
352         process(clk_i)
353         begin
354                 if rising_edge(clk_i) then      
355                         output_o <= s_output_o;
356                         ine_o <= s_ine_o;
357                         overflow_o <= s_overflow_o;
358                         underflow_o <= s_underflow_o;
359                         div_zero_o <= s_div_zero_o;
360                         inf_o <= s_inf_o;
361                         zero_o <= s_zero_o;
362                         qnan_o <= s_qnan_o;
363                         snan_o <= s_snan_o;
364                 end if;
365         end process;    
366
367     
368         -- FSM
369         process(clk_i)
370         begin
371                 if rising_edge(clk_i) then
372                         if s_start_i ='1' then
373                                 s_state <= busy;
374                                 s_count <= 0;
375                         elsif s_count=6 and ((fpu_op_i="000") or (fpu_op_i="001")) then
376                                 s_state <= waiting;
377                                 ready_o <= '1';
378                                 s_count <=0;
379                         elsif s_count=MUL_COUNT and fpu_op_i="010" then
380                                 s_state <= waiting;
381                                 ready_o <= '1';
382                                 s_count <=0;
383                         elsif s_count=33 and fpu_op_i="011" then
384                                 s_state <= waiting;
385                                 ready_o <= '1';
386                                 s_count <=0;
387                         elsif s_count=33 and fpu_op_i="100" then
388                                 s_state <= waiting;
389                                 ready_o <= '1';
390                                 s_count <=0;                    
391                         elsif s_state=busy then
392                                 s_count <= s_count + 1;
393                         else
394                                 s_state <= waiting;
395                                 ready_o <= '0';
396                         end if;
397         end if; 
398         end process;
399                 
400         -- Output Multiplexer
401         process(clk_i)
402         begin
403                 if rising_edge(clk_i) then
404                         if fpu_op_i="000" or fpu_op_i="001" then        
405                                 s_output1               <= postnorm_addsub_output_o;
406                                 s_ine_o                 <= postnorm_addsub_ine_o;
407                         elsif fpu_op_i="010" then
408                                 s_output1       <= post_norm_mul_output;
409                                 s_ine_o                 <= post_norm_mul_ine;
410                         elsif fpu_op_i="011" then
411                                 s_output1       <= post_norm_div_output;
412                                 s_ine_o                 <= post_norm_div_ine;           
413 --                      elsif fpu_op_i="100" then
414 --                              s_output1       <= post_norm_sqrt_output;
415 --                              s_ine_o         <= post_norm_sqrt_ine_o;                        
416                         else
417                                 s_output1       <= (others => '0');
418                                 s_ine_o                 <= '0';
419                         end if;
420                 end if;
421         end process;    
422
423         
424         s_infa <= '1' when s_opa_i(30 downto 23)="11111111"  else '0';
425         s_infb <= '1' when s_opb_i(30 downto 23)="11111111"  else '0';
426         
427
428         --In round down: the subtraction of two equal numbers other than zero are always -0!!!
429         process(s_output1, s_rmode_i, s_div_zero_o, s_infa, s_infb, s_qnan_o, s_snan_o, s_zero_o, s_fpu_op_i, s_opa_i, s_opb_i )
430         begin
431                         if s_rmode_i="00" or (s_div_zero_o or (s_infa or s_infb) or s_qnan_o or s_snan_o)='1' then --round-to-nearest-even
432                                 s_output_o <= s_output1;
433                         elsif s_rmode_i="01" and s_output1(30 downto 23)="11111111" then
434                                 --In round-to-zero: the sum of two non-infinity operands is never infinity,even if an overflow occures
435                                 s_output_o <= s_output1(31) & "1111111011111111111111111111111";
436                         elsif s_rmode_i="10" and s_output1(31 downto 23)="111111111" then
437                                 --In round-up: the sum of two non-infinity operands is never negative infinity,even if an overflow occures
438                                 s_output_o <= "11111111011111111111111111111111";
439                         elsif s_rmode_i="11" then
440                                 --In round-down: a-a= -0
441                                 if (s_fpu_op_i="000" or s_fpu_op_i="001") and s_zero_o='1' and (s_opa_i(31) or (s_fpu_op_i(0) xor s_opb_i(31)))='1' then
442                                         s_output_o <= "1" & s_output1(30 downto 0);     
443                                 --In round-down: the sum of two non-infinity operands is never postive infinity,even if an overflow occures
444                                 elsif s_output1(31 downto 23)="011111111" then
445                                         s_output_o <= "01111111011111111111111111111111";
446                                 else
447                                         s_output_o <= s_output1;
448                                 end if;                 
449                         else
450                                 s_output_o <= s_output1;
451                         end if;
452         end process;
453                 
454
455         -- Generate Exceptions 
456         s_underflow_o <= '1' when s_output1(30 downto 23)="00000000" and s_ine_o='1' else '0'; 
457         s_overflow_o <= '1' when s_output1(30 downto 23)="11111111" and s_ine_o='1' else '0';
458         s_div_zero_o <= serial_div_div_zero when fpu_op_i="011" else '0';
459         s_inf_o <= '1' when s_output1(30 downto 23)="11111111" and (s_qnan_o or s_snan_o)='0' else '0';
460         s_zero_o <= '1' when or_reduce(s_output1(30 downto 0))='0' else '0';
461         s_qnan_o <= '1' when s_output1(30 downto 0)=QNAN else '0';
462     s_snan_o <= '1' when s_opa_i(30 downto 0)=SNAN or s_opb_i(30 downto 0)=SNAN else '0';
463
464
465 end rtl;

UCC git Repository :: git.ucc.asn.au