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

Subversion Repositories ternary_adder

[/] [ternary_adder/] [trunk/] [vhdl/] [ternary_adder_xilinx.vhd] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 plutonium
---------------------------------------------------------------------------------------------
2
-- Author:          Jens Willkomm, Martin Kumm
3
-- Contact:         jens.willkomm@student.uni-kassel.de, kumm@uni-kassel.de
4
-- License:         LGPL
5
-- Date:            15.03.2013
6
-- Compatibility:   Xilinx FPGAs of Virtex 5-7, Spartan 6 and Series 7 architectures
7
--
8
-- Description:
9
-- Low level implementation of a ternary adder according to U.S. Patent No 7274211 
10
-- from Xilinx, which uses the same no of slices than a two input adder.
11
-- The output coresponds to sum_o = x_i + y_i + z_i, where the inputs have a word size of 
12
-- 'input_word_size' while the output has a word size of input_word_size+2.
13
--
14
-- Flipflops at the outputs can be activated by setting 'use_output_ff' to true.
15
-- Signed operation is activated by using the 'is_signed' generic.
16
-- The inputs y_i and z_i can be negated by setting 'subtract_y' or 'subtract_z'
17
-- to realize sum_o = x_i +/- y_i +/- z_i. The negation requires no extra resources.
18
---------------------------------------------------------------------------------------------
19
 
20
library ieee;
21
use ieee.std_logic_1164.all;
22
 
23
entity ternary_add_sub_prim is
24
  generic(
25
    input_word_size  : integer := 10;
26
    subtract_y       : boolean := false;
27
    subtract_z       : boolean := false;
28
    use_output_ff    : boolean := true;
29
    is_signed        : boolean := true
30
  );
31
  port(
32
    clk_i   : in  std_logic;
33
    rst_i   : in  std_logic;
34
    x_i   : in  std_logic_vector((input_word_size - 1) downto 0);
35
    y_i   : in  std_logic_vector((input_word_size - 1) downto 0);
36
    z_i   : in  std_logic_vector((input_word_size - 1) downto 0);
37
    sum_o : out std_logic_vector((input_word_size + 1) downto 0)
38
  );
39
end entity;
40
 
41
architecture behavior of ternary_add_sub_prim is
42
  -- this function calculates the initial carry bit for the bbus
43
  function bbus_init
44
    return std_logic is
45
    variable result : std_logic;
46
  begin
47
    result  := '0';
48
 
49
    if subtract_y or subtract_z then
50
      result  := '1';
51
    end if;
52
 
53
    return result;
54
  end function;
55
 
56
  -- this function calculates the initial carry bit for the carry chain
57
  function cc_init
58
    return std_logic is
59
    variable result : std_logic;
60
  begin
61
    result  := '0';
62
 
63
    if subtract_y and subtract_z then
64
      result  := '1';
65
    end if;
66
 
67
    return result;
68
  end function;
69
 
70
  component slice_setup
71
        generic(
72
                input_word_size                         : integer       := 4;
73
                use_output_ff           : boolean       := false;
74
                is_initial_slice        : boolean       := true;
75
                subtract_y      : boolean       := false;
76
                subtract_z      : boolean       := false
77
        );
78
        port(
79
                -- signals for a synchronous circuit
80
                clock                           : in std_logic;
81
                clock_enable    : in std_logic;
82
                clear                           : in std_logic;
83
                -- the three addends
84
                x_in                            : in    std_logic_vector((input_word_size - 1) downto 0);
85
                y_in                            : in    std_logic_vector((input_word_size - 1) downto 0);
86
                z_in                            : in    std_logic_vector((input_word_size - 1) downto 0);
87
                -- the upper entity is mapping the bbus correctly
88
                -- in initial slice bbus(0) ^= sub / ~add
89
                bbus_in                 : in    std_logic_vector((input_word_size - 1) downto 0);
90
                bbus_out                        : out   std_logic_vector((input_word_size - 1) downto 0);
91
                -- both carrys are for and from the carry chain
92
                -- in the initial slice use carry_in <= '0' always
93
                -- sub/add is done by the bbus(0) from the initial slice
94
                carry_in                        : in    std_logic;
95
                carry_out               : out   std_logic;
96
                -- the sum of the three addends (x_in + y_in + z_in)
97
                sum_out                 : out   std_logic_vector((input_word_size - 1) downto 0)
98
        );
99
  end component;
100
 
101
  -- calculate the needed number of slices
102
  constant num_slices : integer := ((input_word_size + 1) / 4) + 1;
103
 
104
  -- defines the initial carry values
105
  -- in the pure addition mode both constants are '0'
106
  -- if one of the input signal is subtracted the carry_bbus is '1'
107
  -- if two input signal are subtracted both constants are '1'
108
  constant carry_bbus : std_logic := bbus_init;
109
  constant carry_cc   : std_logic := cc_init;
110
 
111
  -- the input addends with sign extention
112
  signal x      : std_logic_vector((input_word_size + 1) downto 0);
113
  signal y      : std_logic_vector((input_word_size + 1) downto 0);
114
  signal z      : std_logic_vector((input_word_size + 1) downto 0);
115
 
116
  -- the bbus that is routed around the slice
117
  -- this bbus differs from the one in the xilinx paper,
118
  -- per position the input is bbus(n) and the output is bbus(n + 1)
119
  -- this is because of the sub/~add, which is bbus(0) and all the other
120
  -- bbus signals are scrolled one position up
121
  signal bbus   : std_logic_vector(input_word_size + 2 downto 0);
122
  -- the carry from every slice to the next one
123
  -- the last slice gives the carry output for the adder
124
  -- carry(n) is the carry of the carry chain of slice n
125
  signal carry  : std_logic_vector((num_slices - 1) downto 0);
126
begin
127
  -- checking the parameter input_word_size
128
  assert (input_word_size > 0) report "an adder with a bit width of "
129
    & integer'image(input_word_size) & " is not possible." severity failure;
130
 
131
  -- adding two bit sign extention to the input addends
132
  extention_signed: if is_signed = true generate
133
    x <= x_i(input_word_size - 1) & x_i(input_word_size - 1) & x_i;
134
    y <= y_i(input_word_size - 1) & y_i(input_word_size - 1) & y_i;
135
    z <= z_i(input_word_size - 1) & z_i(input_word_size - 1) & z_i;
136
  end generate;
137
 
138
  extention_unsigned: if is_signed = false generate
139
    x <= '0' & '0' & x_i;
140
    y <= '0' & '0' & y_i;
141
    z <= '0' & '0' & z_i;
142
  end generate;
143
 
144
  -- the initial bbus carry signal
145
  bbus(0) <= carry_bbus;
146
 
147
  -- generating the slice setups
148
  -- getting all signals into one slice
149
  single_slice: if num_slices = 1 generate
150
    slice_i: slice_setup
151
        generic map(
152
          input_word_size        => input_word_size + 2,
153
          use_output_ff    => use_output_ff,
154
          is_initial_slice  => true,
155
          subtract_y  => subtract_y,
156
          subtract_z  => subtract_z
157
        )
158
        port map(
159
          clock       => clk_i,
160
          clock_enable  => '1',
161
          clear       => rst_i,
162
          x_in        => x,
163
          y_in        => y,
164
          z_in        => z,
165
          bbus_in     => bbus(input_word_size + 1 downto 0),
166
          -- scrolling bbus_out one position up
167
          bbus_out      => bbus(input_word_size + 2 downto 1),
168
          carry_in      => carry_cc,
169
          carry_out   => carry(0),
170
          sum_out     => sum_o(input_word_size + 1 downto 0)
171
        );
172
  end generate;
173
 
174
  -- make more slices to calculate all signals
175
  multiple_slices: if num_slices > 1 generate
176
    slices: for i in 0 to (num_slices - 1) generate
177
      -- generate the first slice
178
      first_slice: if i = 0 generate
179
        slice_i: slice_setup
180
          generic map(
181
            input_word_size        => 4,
182
            use_output_ff    => use_output_ff,
183
            is_initial_slice  => true,
184
            subtract_y  => subtract_y,
185
            subtract_z  => subtract_z
186
          )
187
          port map(
188
            clock       => clk_i,
189
            clock_enable  => '1',
190
            clear       => rst_i,
191
            x_in        => x(3 downto 0),
192
            y_in        => y(3 downto 0),
193
            z_in        => z(3 downto 0),
194
            bbus_in     => bbus(3 downto 0),
195
            -- scrolling bbus_out one position upwards
196
            bbus_out      => bbus(4 downto 1),
197
            carry_in      => carry_cc,
198
            carry_out   => carry(0),
199
            sum_out     => sum_o(3 downto 0)
200
          );
201
      end generate;
202
 
203
      -- generate all full slices
204
      full_slice: if i > 0 and i < (num_slices - 1) generate
205
        slice_i: slice_setup
206
          generic map(
207
            input_word_size        => 4,
208
            use_output_ff    => use_output_ff,
209
            is_initial_slice  => false,
210
            subtract_y  => subtract_y,
211
            subtract_z  => subtract_z
212
          )
213
          port map(
214
            clock       => clk_i,
215
            clock_enable  => '1',
216
            clear       => rst_i,
217
            x_in        => x((4 * i) + 3 downto 4 * i),
218
            y_in        => y((4 * i) + 3 downto 4 * i),
219
            z_in        => z((4 * i) + 3 downto 4 * i),
220
            bbus_in     => bbus((4 * i) + 3 downto 4 * i),
221
            -- scrolling bbus_out one position upwards
222
            bbus_out      => bbus((4 * i) + 4 downto (4 * i) + 1),
223
            carry_in      => carry(i - 1),
224
            carry_out   => carry(i),
225
            sum_out     => sum_o((4 * i) + 3 downto 4 * i)
226
          );
227
      end generate;
228
 
229
      -- generate the last slice
230
      last_slice: if i = (num_slices - 1) generate
231
        slice_i: slice_setup
232
          generic map(
233
            input_word_size        => (input_word_size + 2) - (i * 4),
234
            use_output_ff    => use_output_ff,
235
            is_initial_slice  => false,
236
            subtract_y  => subtract_y,
237
            subtract_z  => subtract_z
238
          )
239
          port map(
240
            clock       => clk_i,
241
            clock_enable  => '1',
242
            clear       => rst_i,
243
            x_in        => x(input_word_size + 1 downto 4 * i),
244
            y_in        => y(input_word_size + 1 downto 4 * i),
245
            z_in        => z(input_word_size + 1 downto 4 * i),
246
            bbus_in     => bbus(input_word_size + 1 downto 4 * i),
247
            -- scrolling bbus_out one position up
248
            bbus_out      => bbus(input_word_size + 2 downto (4 * i) + 1),
249
            carry_in      => carry(i - 1),
250
            carry_out   => carry(i),
251
            sum_out     => sum_o(input_word_size + 1 downto 4 * i)
252
          );
253
      end generate;
254
    end generate;
255
  end generate;
256
end architecture;
257
 
258
--- Definition of the slice_setup component which configures a single slice ---
259
 
260
library unisim;
261
use unisim.vcomponents.all;                             -- loading xilinx primitives
262
 
263
library ieee;
264
use ieee.std_logic_1164.all;                            -- loading std_logic & std_logic_vector
265
 
266
entity slice_setup is
267
        generic(
268
                input_word_size                         : integer       := 4;
269
                use_output_ff           : boolean       := false;
270
                is_initial_slice        : boolean       := true;
271
                subtract_y      : boolean       := false;
272
                subtract_z      : boolean       := false
273
        );
274
        port(
275
                -- signals for a synchronous circuit
276
                clock                           : in std_logic;
277
                clock_enable    : in std_logic;
278
                clear                           : in std_logic;
279
                -- the three addends
280
                x_in                            : in    std_logic_vector((input_word_size - 1) downto 0);
281
                y_in                            : in    std_logic_vector((input_word_size - 1) downto 0);
282
                z_in                            : in    std_logic_vector((input_word_size - 1) downto 0);
283
                -- the upper entity is mapping the bbus correctly
284
                -- in initial slice bbus(0) ^= sub / ~add
285
                bbus_in                 : in    std_logic_vector((input_word_size - 1) downto 0);
286
                bbus_out                        : out   std_logic_vector((input_word_size - 1) downto 0);
287
                -- both carrys are for and from the carry chain
288
                -- in the initial slice use carry_in <= '0' always
289
                -- sub/add is done by the bbus(0) from the initial slice
290
                carry_in                        : in    std_logic;
291
                carry_out               : out   std_logic;
292
                -- the sum of the three addends (x_in + y_in + z_in)
293
                sum_out                 : out   std_logic_vector((input_word_size - 1) downto 0)
294
        );
295
end entity;
296
 
297
architecture behavior of slice_setup is
298
        -- this function returns the lut initialization
299
        function get_lut_init
300
                return bit_vector is
301
                -- defines several lut configurations
302
                -- for init calculation see "initializing_primitives.ods"
303
                constant lut_init_no_sub        : bit_vector(63 downto 0)        := x"3cc3c33cfcc0fcc0";
304
                constant lut_init_sub_y         : bit_vector(63 downto 0)        := x"c33c3cc3cf0ccf0c";
305
                constant lut_init_sub_z         : bit_vector(63 downto 0)        := x"c33c3cc3f330f330";
306
                constant lut_init_sub_yz        : bit_vector(63 downto 0)        := x"3cc3c33c3f033f03";
307
                variable curr_lut                                 : bit_vector(63 downto 0)      := lut_init_no_sub;
308
        begin
309
                curr_lut        := lut_init_no_sub;
310
 
311
                if subtract_y then
312
                        curr_lut        := lut_init_sub_y;
313
                end if;
314
 
315
                if subtract_z then
316
                        curr_lut        := lut_init_sub_z;
317
                end if;
318
 
319
                if subtract_y and subtract_z then
320
                        curr_lut        := lut_init_sub_yz;
321
                end if;
322
 
323
                return curr_lut;
324
        end function;
325
 
326
        -- calculate how many bits to fill up with zeros for the carry chain
327
        constant fillup_width   : integer := 4 - input_word_size;
328
 
329
        -- holds the lut configuration used in this slice
330
        constant current_lut_init       : bit_vector := get_lut_init;
331
 
332
        -- output o6 of the luts
333
        signal lut_o6   : std_logic_vector((input_word_size - 1) downto 0);
334
        -- the signals for and from the carry chain have to be wrapped into signals
335
        -- with a width of four, to fill them up with zeros and prevent synthesis
336
        -- warnings when doing this in the port map of the carry chain
337
        -- input di of the carry chain (have to be four bits width)
338
        signal cc_di    : std_logic_vector(3 downto 0);
339
        -- input s of the carry chain (have to be four bits width)
340
        signal cc_s             : std_logic_vector(3 downto 0);
341
        -- output o of the carry chain (have to be four bits width)
342
        signal cc_o             : std_logic_vector(3 downto 0);
343
        -- output co of the carry chain (have to be four bits width)
344
        signal cc_co    : std_logic_vector(3 downto 0);
345
begin
346
        -- check the generic parameter
347
        assert (input_word_size > 0 and input_word_size < 5) report "a slice with a bit width of "
348
                & integer'image(input_word_size) & " is not possible." severity failure;
349
 
350
        -- prepairing singals for the carry chain
351
        full_slice_assignment: if input_word_size = 4 generate
352
                cc_di   <= bbus_in;
353
                cc_s    <= lut_o6;
354
        end generate;
355
 
356
        last_slice_assignment: if input_word_size < 4 generate
357
                cc_di   <= (fillup_width downto 1 => '0') & bbus_in;
358
                cc_s    <= (fillup_width downto 1 => '0') & lut_o6;
359
        end generate;
360
 
361
        -- creating the lookup tables
362
        luts: for i in 0 to (input_word_size - 1) generate
363
                -- lut6_2 primitive is described in virtex 6 user guide on page 215:
364
                -- http://www.xilinx.com/support/documentation/sw_manuals/xilinx12_3/virtex6_hdl.pdf
365
                lut_bit_i: lut6_2
366
                        generic map(
367
                                init    => current_lut_init
368
                        )
369
                        -------------------------------------------------------------------
370
                        -- table of names and connections
371
                        -- user guide                           us 7,274,211                            usage in adder
372
                        -- ----------                           ------------                            --------------
373
                        -- i0                                                   in1                                                     gnd
374
                        -- i1                                                   in2                                                     z(n)
375
                        -- i2                                                   in3                                                     y(n)
376
                        -- i3                                                   in4                                                     x(n)
377
                        -- i4                                                   in5                                                     bbus(n-1)
378
                        -- i5                                                   in6                                                     vdd
379
                        -- o5                                                   o5
380
                        -- o6                                                   o6
381
                        -------------------------------------------------------------------
382
                        port map(
383
                                i0      => '0',
384
                                i1      => z_in(i),
385
                                i2      => y_in(i),
386
                                i3      => x_in(i),
387
                                i4      => bbus_in(i),
388
                                i5      => '1',
389
                                o5      => bbus_out(i),
390
                                o6 => lut_o6(i)
391
                        );
392
        end generate;
393
 
394
        -- creating the carry chain
395
        -- carry4 primitive is described in virtex 6 user guide on page 108:
396
        -- http://www.xilinx.com/support/documentation/sw_manuals/xilinx12_3/virtex6_hdl.pdf
397
        initial_slice: if is_initial_slice = true generate
398
                init_cc: carry4
399
                        -------------------------------------------------------------------
400
                        -- table of names and connections
401
                        -- user guide                           usage in adder
402
                        -- ----------                           --------------
403
                        -- co                                                   msb is carry out, rest is not connected
404
                        -- o                                                    sum
405
                        -- ci                                                   in the initial slice: not connected
406
                        -- cyinit                                       in the initial slice: add / ~sub
407
                        -- di                                                   bbus(n-1)
408
                        -- s                                                    lut_o6(n)
409
                        -------------------------------------------------------------------
410
                        port map(
411
                                co                      => cc_co,
412
                                o                       => cc_o,
413
                                cyinit  => '0',
414
                                ci      => carry_in,
415
                                di                      => cc_di,
416
                                s                       => cc_s
417
                        );
418
        end generate;
419
 
420
        further_slice: if is_initial_slice = false generate
421
                further_cc: carry4
422
                        -------------------------------------------------------------------
423
                        -- table of names and connections
424
                        -- user guide                           usage in adder
425
                        -- ----------                           --------------
426
                        -- co                                                   msb is carry out, rest is not connected
427
                        -- o                                                    sum
428
                        -- ci                                                   carry from previous slice
429
                        -- cyinit                                       in further slices: not connected
430
                        -- di                                                   bbus(n-1)
431
                        -- s                                                    lut_o6(n)
432
                        -------------------------------------------------------------------
433
                        port map(
434
                                co                      => cc_co,
435
                                o                       => cc_o,
436
                                cyinit  => '0',
437
                                ci      => carry_in,
438
                                di                      => cc_di,
439
                                s                       => cc_s
440
                        );
441
        end generate;
442
 
443
        -- connect the last used output of the carry chain to the slice output
444
        carry_out       <= cc_co(input_word_size - 1);
445
 
446
        -- creating the flip flops
447
        sum_register: if use_output_ff = true generate
448
                ffs: for i in 0 to (input_word_size - 1) generate
449
                        ff_i: fdce
450
                                generic map(
451
                                        -- initialize all flip flops with '0'
452
                                        init => '0'
453
                                )
454
                                -------------------------------------------------------------------
455
                                -- table of names and connections
456
                                -- user guide                           usage in adder
457
                                -- ----------                           --------------
458
                                -- clr                                          clear
459
                                -- ce                                                   clock_enable, always '1'
460
                                -- d                                                    cc_o
461
                                -- c                                                    clock
462
                                -- q                                                    sum(n)
463
                                -------------------------------------------------------------------
464
                                port map(
465
                                        clr     => clear,
466
                                        ce              => clock_enable,
467
                                        d               => cc_o(i),
468
                                        c               => clock,
469
                                        q               => sum_out(i)
470
                                );
471
                end generate;
472
        end generate;
473
 
474
        -- bypassing the flip flops in case of a asynchronous circuit
475
        bypass: if use_output_ff = false generate
476
                sum_out <= cc_o(input_word_size - 1 downto 0);
477
        end generate;
478
end architecture;

powered by: WebSVN 2.1.0

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