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

Subversion Repositories openfpu64

[/] [openfpu64/] [trunk/] [fpu_add.vhd] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 bro
-------------------------------------------------------------------------------
2
-- Project    : openFPU64 Add/Sub Component
3
-------------------------------------------------------------------------------
4
-- File       : fpu_add.vhd
5
-- Author     : Peter Huewe  <peterhuewe@gmx.de>
6
-- Created    : 2010-04-19
7
-- Last update: 2010-04-19
8
-- Standard   : VHDL'87
9
-------------------------------------------------------------------------------
10
-- Description: double precision floating point adder/subtractor component
11
--                     for openFPU64, includes rounding and normalization
12
-- 
13
-------------------------------------------------------------------------------
14
-- Copyright (c) 2010 
15
-------------------------------------------------------------------------------
16
-- License: gplv3, see licence.txt
17
-------------------------------------------------------------------------------
18
library IEEE;
19
use IEEE.std_logic_1164.all;
20
use IEEE.numeric_std.all;
21
use work.fpu_package.all;
22
 
23
entity fpu_add is
24
  port (
25
    clk, reset_n           : in  std_logic;  -- reset = standard active low
26
    mode                   : in  std_logic;  --  mode: 0 = add , 1= sub
27
    cs                     : in  std_logic;  -- chip select active high
28
    -- in operands
29
    sign_a, sign_b         : in  std_logic;  -- sign bits
30
    exponent_a, exponent_b : in  std_logic_vector (11 downto 0);  -- exponents of the operands
31
    mantissa_a, mantissa_b : in  std_logic_vector (57 downto 0);  -- mantissa of operands
32
-- out result
33
    sign_res               : out std_logic;
34
    exponent_res           : out std_logic_vector(11 downto 0);
35
    mantissa_res           : out std_logic_vector (57 downto 0);
36
 
37
    rounding_needed : out std_logic;  -- FUTURE wether rounding is needed or not
38
    valid           : out std_logic
39
    );
40
end fpu_add;
41
architecture rtl of fpu_add is
42
  -- controller part
43
 
44
 
45
 
46
  type t_state is (
47
    s_reset,
48
    s_load_wait,
49
    s_a_is_nan,
50
    s_b_is_nan,
51
    s_swap_a_and_b,
52
    s_invalid_operation_inf_minus_inf,
53
    s_get_result,
54
    s_fix_sub_borrow,
55
    s_normalize_right,
56
    s_result_is_inf,
57
    s_normalize_left,
58
    s_prepare_round_ceiling,
59
    s_post_normalization,
60
    s_finished,
61
    s_zero,
62
    s_correction_and_round,
63
    s_prepare_operation,
64
    s_check_result,
65
    s_wait_on_normalize_right,
66
    s_align_b_to_a
67
    );
68
  signal state : t_state;
69
 
70
  signal a_s, b_s                       : std_logic             := '0';
71
  signal a_e, b_e                       : unsigned(11 downto 0) := (others => '0');
72
  signal a_m, b_m                       : unsigned(57 downto 0) := (others => '0');
73
  signal alu_result, alu_op_a, alu_op_b : unsigned(57 downto 0) := (others => '0');
74
  -- Switches adder between Addition and Subtraction, helps to infer 1 big addsub by synthesis tools
75
  signal alu_mode                       : std_logic             := '0';
76
 
77
  -- status bits generated automatically
78
  signal a_is_a_denormalized_number, a_is_lesser_than_b, a_is_inf_or_nan, a_is_inf : std_logic := '0';
79
  signal b_is_unaligned, addition_mode, rounding_case_is_to_ceiling                : std_logic := '0';
80
  signal b_is_inf, b_is_inf_or_nan, or_signal                                      : std_logic := '0';
81
 
82
 
83
 
84
  alias result_is_inf   : std_logic is a_is_inf_or_nan;  -- result is stored in a
85
  alias signs_are_equal : std_logic is addition_mode;
86
  alias a_e_all_ones    : std_logic is a_is_inf_or_nan;  -- if exponent 111...111 then a is either INF or NAN
87
  alias b_e_all_ones    : std_logic is b_is_inf_or_nan;  -- if exponent 111...111 then b is either INF or NAN
88
  alias a_e_all_zeros   : std_logic is a_is_a_denormalized_number;  -- if exponent of a, a is either zero or a denormalized number
89
 
90
begin
91
  -- FUTURE
92
  rounding_needed <= '0';
93
 
94
 
95
  -- generate internal status signals
96
 
97
  a_is_a_denormalized_number <= '1' when a_e = ZEROS(10 downto 0)               else '0';
98
  a_is_inf_or_nan            <= '1' when a_e = ONES (10 downto 0)               else '0';
99
  b_is_inf_or_nan            <= '1' when b_e = ONES(10 downto 0)                else '0';
100
  b_is_inf                   <= '1' when b_m (54 downto 1) = ZEROS(54 downto 1) else '0';  -- if mantissa is zero and exponent  is 11..111 b is inf
101
  a_is_inf                   <= '1' when a_m (54 downto 1) = ZEROS(54 downto 1) else '0';  -- if mantissa is zero and exponent is 11..111 a is inf
102
  a_is_lesser_than_b         <= '1' when a_e(10 downto 0) < b_e(10 downto 0)    else '0';  --  a should be >= b
103
  b_is_unaligned             <= '1' when a_e /= b_e                             else '0';  -- exponents of a and b have to be the same before addition
104
  addition_mode              <= '1' when a_s = b_s                              else '0';
105
 
106
  -- this line has this meaning
107
  -- case a_m (3 downto 0) 
108
  --  when "1100" => add 1 to a_m(57 downto 3)
109
  --  when "1101" => add 1 to a_m(57 downto 3)
110
  --  when "1110" => add 1 to a_m(57 downto 3)
111
  --  when "1111" => add 1 to a_m(57 downto 3)
112
  rounding_case_is_to_ceiling <= '1' when a_m(3 downto 0) = "1100" or (a_m(2) = '1' and (a_m(1) = '1' or a_m(0) = '1')) else '0';
113
 
114
  -- Big ADD/SUB, has to be preloaded for each result
115
  alu_result <= alu_op_a+alu_op_b when alu_mode = '1' else alu_op_a-alu_op_b;
116
 
117
  state_trans : process (clk, reset_n)  -- clock, reset_n, chipselect
118
  begin
119
    if reset_n = '0' then
120
      a_m   <= (others => '0');
121
      a_e   <= (others => '0');
122
      a_s   <= '0';
123
      b_m   <= (others => '0');
124
      b_e   <= (others => '0');
125
      b_s   <= '0';
126
      valid <= '0';
127
 
128
      sign_res     <= '0';
129
      exponent_res <= (others => '0');
130
      mantissa_res <= (others => '0');
131
      alu_op_a     <= (others => '0');
132
      alu_op_b     <= (others => '0');
133
      alu_mode     <= '0';
134
      state        <= s_reset;          -- reset hat vorrang
135
    elsif rising_edge(clk) then
136
      if cs = '0' then
137
        a_m   <= (others => '0');
138
        a_e   <= (others => '0');
139
        a_s   <= '0';
140
        b_m   <= (others => '0');
141
        b_e   <= (others => '0');
142
        b_s   <= '0';
143
        valid <= '0';
144
 
145
        sign_res     <= '0';
146
        exponent_res <= (others => '0');
147
        mantissa_res <= (others => '0');
148
        alu_op_a     <= (others => '0');
149
        alu_op_b     <= (others => '0');
150
        alu_mode     <= '0';
151
        state        <= s_reset;        -- reset hat vorrang
152
      else
153
 
154
        -- keep values
155
        a_m          <= a_m;
156
        a_e          <= a_e;
157
        a_s          <= a_s;
158
        b_m          <= b_m;
159
        b_e          <= b_e;
160
        b_s          <= b_s;
161
        valid        <= '0';
162
        sign_res     <= a_s;
163
        exponent_res <= std_logic_vector(a_e);
164
        mantissa_res <= std_logic_vector(a_m);
165
        alu_op_a     <= alu_op_a;
166
        alu_op_b     <= alu_op_b;
167
        alu_mode     <= alu_mode;
168
        state        <= state;  -- keep state if nothing else specified.
169
 
170
 
171
        case state is
172
          -- reset state, if chipselect is 1 load operands
173
          when s_reset =>
174
            if cs = '1' then
175
              a_s <= sign_a;
176
              b_s <= sign_b xor mode;   -- "sorts operations" 
177
              a_m <= unsigned(mantissa_a);
178
              b_m <= unsigned(mantissa_b);
179
              a_e <= unsigned(exponent_a);
180
              b_e <= unsigned(exponent_b);
181
 
182
              state <= s_load_wait;
183
            end if;
184
 
185
          -- check operands if they are valid (!= nan), if operation is allowed
186
          -- or if operands need to be swapped
187
          when s_load_wait =>
188
            if a_is_inf_or_nan = '1' and a_is_inf = '0' then state                                     <= s_a_is_nan;
189
            elsif b_is_inf_or_nan = '1' and b_is_inf = '0' then state                                  <= s_b_is_nan;
190
            --if a and b are infinity and signs are not equal this is an invalid operation
191
            elsif a_is_inf_or_nan = '1' and b_is_inf_or_nan = '1' and signs_are_equal = '0' then state <= s_invalid_operation_inf_minus_inf;
192
            -- if only a is infinity then nothing is left to be done
193
            elsif a_is_inf_or_nan = '1' and a_is_inf = '1' then state                                  <= s_finished;
194
            elsif a_is_lesser_than_b = '1' then state                                                  <= s_swap_a_and_b;
195
            else state                                                                                 <= s_prepare_operation;
196
            end if;
197
 
198
          --operand a is NaN, set sign and finish
199
          when s_a_is_nan =>
200
            a_s <= b_s or mode;
201
 
202
            state <= s_finished;
203
 
204
          --operand b is NaN set result=b and finish
205
          when s_b_is_nan =>
206
            a_e <= b_e;
207
            a_m <= b_m;
208
            a_s <= b_s or mode;
209
 
210
            state <= s_finished;
211
 
212
          -- operands a and b have to be swapped
213
          when s_swap_a_and_b =>
214
            a_s <= b_s;
215
            b_s <= a_s;
216
            a_e <= b_e;
217
            b_e <= a_e;
218
            a_m <= b_m;
219
            b_m <= a_m;
220
 
221
            state <= s_prepare_operation;
222
 
223
          -- load adder for add/sub
224
          -- check if b has to be aligned
225
          when s_prepare_operation =>
226
            alu_mode <= addition_mode;  -- load alu for s_get_result
227
            alu_op_a <= a_m;
228
            alu_op_b <= b_m;
229
 
230
            if b_is_unaligned = '1' then state <= s_align_b_to_a;
231
            else state                         <= s_get_result;
232
            end if;
233
 
234
          -- INF - INF or similar is an invalid operation
235
          when s_invalid_operation_inf_minus_inf =>
236
            a_m(54) <= '1'; a_s <= '1';
237
 
238
            state <= s_finished;
239
 
240
          -- align b to a so that a_e=b_e
241
          when s_align_b_to_a =>
242
            alu_mode <= addition_mode;  -- load alu for s_get_result
243
            alu_op_a <= a_m;
244
            alu_op_b <= b_m;
245
 
246
            state <= s_get_result;  -- if a_e=b_e or b_m = 0...00x start calculation
247
            if b_is_unaligned = '1' then  -- otherwise align b to a
248
              b_m(56 downto 0) <= '0' & b_m (56 downto 2) & (b_m(1) or b_m(0));
249
              alu_op_b         <= '0'&'0' & b_m (56 downto 2) & (b_m(1) or b_m(0));
250
              b_e              <= b_e +1;
251
              if b_m(56 downto 1) /= 0 then
252
                -- still not alligned
253
                state <= s_align_b_to_a;
254
              end if;
255
            end if;
256
 
257
 
258
          -- assign calculation result
259
          when s_get_result =>
260
            b_e <= a_e;  -- in case some steps were skipped due to b_m = 0...00x
261
            a_m <= alu_result;
262
 
263
            state <= s_check_result;
264
 
265
-- check result:
266
-- sub borrow occured?
267
          -- normalization needed?
268
          -- result is zero?
269
          -- result is in?
270
          -- rounding needed?
271
          when s_check_result =>
272
            alu_mode <= '1';            -- load alu for s_fix_sub_borrow 
273
            alu_op_a <= not(a_m);
274
            alu_op_b <= (57 downto 1 => '0')&'1';
275
 
276
            if a_m(57) = '1' then state                       <= s_fix_sub_borrow;
277
            elsif a_m(56) = '1' then state                    <= s_normalize_right;  -- a_m(56)='1' -> normalization to the right is needed
278
            elsif result_is_inf = '1' then state              <= s_result_is_inf;
279
            elsif a_m(55) = '0' and a_is_inf = '1' then state <= s_zero;
280
            else state                                        <= s_correction_and_round;
281
            end if;
282
 
283
          -- sub borrow occured, fix it by *-1 (adder loaded in previous state)
284
          when s_fix_sub_borrow =>
285
            a_s <= not a_s;
286
            a_m <= alu_result;
287
 
288
            if a_m(56) = '1' then state                       <= s_normalize_right;  -- a_m(56)='1' -> normalization to the right is needed
289
            elsif result_is_inf = '1' then state              <= s_result_is_inf;
290
            elsif a_m(55) = '0' and a_is_inf = '1' then state <= s_zero;
291
            else state                                        <= s_correction_and_round;
292
            end if;
293
 
294
          -- Normalize right 
295
          when s_normalize_right =>
296
            a_m(56 downto 0) <= '0' & a_m(56 downto 2)& (a_m(0) or a_m(1));
297
            a_e              <= a_e +1;
298
 
299
            state <= s_wait_on_normalize_right;
300
 
301
          -- check result of Normalization to the right
302
          when s_wait_on_normalize_right =>
303
            if a_is_inf_or_nan = '1' then state <= s_result_is_inf;
304
            else state                          <= s_correction_and_round;
305
            end if;
306
 
307
          -- result is infinity
308
          when s_result_is_inf =>
309
            a_m <= (others => '0');
310
 
311
            state <= s_finished;
312
 
313
          -- 
314
          when s_correction_and_round =>
315
            alu_mode                                            <= '1';  -- load alu for s_prepare_round_ceiling
316
            alu_op_a                                            <= a_m;
317
            alu_op_b                                            <= (57 downto 4 => '0')&"1000";
318
            if a_m(55) = '0' and a_e_all_zeros = '0' then state <= s_normalize_left;
319
            elsif rounding_case_is_to_ceiling = '1' then state  <= s_prepare_round_ceiling;
320
            elsif a_m(56) = '1' then state                      <= s_post_normalization;  -- a_m(56)='1' -> postnormalization is needed
321
 
322
            else state <= s_finished; end if;
323
 
324
          -- shift (possible) leading 1 to correct position
325
          when s_normalize_left=>
326
            a_m(55 downto 0) <= a_m(54 downto 0) & a_m(0);
327
            a_e              <= a_e -1;
328
            alu_mode         <= '1';    -- load alu for s_prepare_round_ceiling
329
            alu_op_a         <= a_m(57 downto 56) & a_m(54 downto 0) & a_m(0);
330
            alu_op_b         <= (57 downto 4 => '0')&"1000";
331
 
332
 
333
            if a_m(54) = '0' and a_e_all_zeros = '0' then state                         <= s_normalize_left;
334
            elsif a_m(2 downto 0) = "110" or (a_m(1) = '1' and a_m(0) = '1') then state <= s_prepare_round_ceiling;
335
            elsif a_m(56) = '1' then state                                              <= s_post_normalization;  -- a_m(56)='1' -> postnormalization is needed
336
            else state                                                                  <= s_finished; end if;
337
 
338
 
339
          when s_prepare_round_ceiling =>
340
            a_m                                <= alu_result;
341
            if alu_result(56) = '1' then state <= s_post_normalization;  -- a_m(56)='1' -> postnormalization is needed
342
            else state                         <= s_finished; end if;
343
 
344
          -- shift leading 1 to correct position
345
          when s_post_normalization =>
346
            a_m(56 downto 1) <= '0' & a_m(56 downto 2);
347
            a_e              <= a_e +1;
348
            state            <= s_finished;
349
 
350
          -- result is zero
351
          when s_zero =>
352
            a_s <= '0';  -- im add/sub fall bei allen rundungsmodi ausser round to -inf ist dies richtig!
353
            a_e <= (others => '0');
354
            a_m <= (others => '0');
355
 
356
            state <= s_finished;
357
          -- finished
358
          when s_finished =>
359
            valid <= '1';
360
            state <= s_finished;        -- done here.
361
 
362
        end case;
363
      end if;
364
    end if;
365
  end process;
366
end rtl;
367
 

powered by: WebSVN 2.1.0

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