1
2-- Copyright (C) 1996 Morgan Kaufmann Publishers, Inc
3
4-- This file is part of VESTs (Vhdl tESTs).
5
6-- VESTs is free software; you can redistribute it and/or modify it
7-- under the terms of the GNU General Public License as published by the
8-- Free Software Foundation; either version 2 of the License, or (at
9-- your option) any later version.
10
11-- VESTs is distributed in the hope that it will be useful, but WITHOUT
12-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13-- FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14-- for more details.
15
16-- You should have received a copy of the GNU General Public License
17-- along with VESTs; if not, write to the Free Software Foundation,
18-- Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20-- ---------------------------------------------------------------------
21--
22-- $Id: bv_arithmetic_body.vhd,v 1.3 2001-10-26 16:29:33 paw Exp $
23-- $Revision: 1.3 $
24--
25-- ---------------------------------------------------------------------
26
27package body bv_arithmetic is
28
29  ----------------------------------------------------------------
30  --  Type conversions
31  ----------------------------------------------------------------
32
33  function bv_to_natural ( bv : in bit_vector ) return natural is
34
35    variable result : natural := 0;
36
37  begin
38    for index in bv'range loop
39      result := result * 2 + bit'pos( bv(index) );
40    end loop;
41    return result;
42  end function bv_to_natural;
43
44  function natural_to_bv ( nat : in natural;
45      	      	      	   length : in natural ) return bit_vector is
46
47    variable temp : natural := nat;
48    variable result : bit_vector(length - 1 downto 0) := (others => '0');
49
50  begin
51    for index in result'reverse_range loop
52      result(index) := bit'val( temp rem 2 );
53      temp := temp / 2;
54      exit when temp = 0;
55    end loop;
56    return result;
57  end function natural_to_bv;
58
59  function bv_to_integer ( bv : in bit_vector ) return integer is
60
61    variable temp : bit_vector(bv'range);
62    variable result : integer := 0;
63
64  begin
65    if bv(bv'left) = '1' then	  -- negative number
66      temp := not bv;
67    else
68      temp := bv;
69    end if;
70    for index in bv'range loop	  -- sign bit of temp = '0'
71      result := result * 2 + bit'pos( temp(index) );
72    end loop;
73    if bv(bv'left) = '1' then
74      result := (-result) - 1;
75    end if;
76    return result;
77  end function bv_to_integer;
78
79  function integer_to_bv ( int : in integer;
80      	      	      	   length : in natural ) return bit_vector is
81
82    variable temp : integer;
83    variable result : bit_vector(length - 1 downto 0) := (others => '0');
84
85  begin
86    if int < 0 then
87      temp := - (int + 1);
88    else
89      temp := int;
90    end if;
91    for index in result'reverse_range loop
92      result(index) := bit'val( temp rem 2 );
93      temp := temp / 2;
94      exit when temp = 0;
95    end loop;
96    if int < 0 then
97      result := not result;
98      result(result'left) := '1';
99    end if;
100    return result;
101  end function integer_to_bv;
102
103  ----------------------------------------------------------------
104  --  Arithmetic operations
105  ----------------------------------------------------------------
106
107  procedure bv_add ( bv1, bv2 : in bit_vector;
108      	       	     bv_result : out bit_vector;
109		     overflow : out boolean ) is
110
111    alias op1 : bit_vector(bv1'length - 1 downto 0) is bv1;
112    alias op2 : bit_vector(bv2'length - 1 downto 0) is bv2;
113    variable result : bit_vector(bv_result'length - 1 downto 0);
114    variable carry_in : bit;
115    variable carry_out : bit := '0';
116
117  begin
118    if bv1'length /= bv2'length or bv1'length /= bv_result'length then
119      report "bv_add: operands of different lengths"
120        severity failure;
121    else
122      for index in result'reverse_range loop
123        carry_in := carry_out;  -- of previous bit
124        result(index) := op1(index) xor op2(index) xor carry_in;
125        carry_out := (op1(index) and op2(index))
126                     or (carry_in and (op1(index) xor op2(index)));
127      end loop;
128      bv_result := result;
129      overflow := carry_out /= carry_in;
130    end if;
131  end procedure bv_add;
132
133  function "+" ( bv1, bv2 : in bit_vector ) return bit_vector is
134
135    alias op1 : bit_vector(bv1'length - 1 downto 0) is bv1;
136    alias op2 : bit_vector(bv2'length - 1 downto 0) is bv2;
137    variable result : bit_vector(bv1'length - 1 downto 0);
138    variable carry_in : bit;
139    variable carry_out : bit := '0';
140
141  begin
142    if bv1'length /= bv2'length then
143      report """+"": operands of different lengths"
144        severity failure;
145    else
146      for index in result'reverse_range loop
147        carry_in := carry_out;  -- of previous bit
148        result(index) := op1(index) xor op2(index) xor carry_in;
149        carry_out := (op1(index) and op2(index))
150                     or (carry_in and (op1(index) xor op2(index)));
151      end loop;
152    end if;
153    return result;
154  end function "+";
155
156  procedure bv_sub ( bv1, bv2 : in bit_vector;
157      	       	     bv_result : out bit_vector;
158		     overflow : out boolean ) is
159
160    -- subtraction implemented by adding ((not bv2) + 1), ie -bv2
161
162    alias op1 : bit_vector(bv1'length - 1 downto 0) is bv1;
163    alias op2 : bit_vector(bv2'length - 1 downto 0) is bv2;
164    variable result : bit_vector(bv_result'length - 1 downto 0);
165    variable carry_in : bit;
166    variable carry_out : bit := '1';
167
168  begin
169    if bv1'length /= bv2'length or bv1'length /= bv_result'length then
170      report "bv_sub: operands of different lengths"
171        severity failure;
172    else
173      for index in result'reverse_range loop
174        carry_in := carry_out;  -- of previous bit
175        result(index) := op1(index) xor (not op2(index)) xor carry_in;
176        carry_out := (op1(index) and (not op2(index)))
177                     or (carry_in and (op1(index) xor (not op2(index))));
178      end loop;
179      bv_result := result;
180      overflow := carry_out /= carry_in;
181    end if;
182  end procedure bv_sub;
183
184  function "-" ( bv1, bv2 : in bit_vector ) return bit_vector is
185
186    -- subtraction implemented by adding ((not bv2) + 1), ie -bv2
187
188    alias op1 : bit_vector(bv1'length - 1 downto 0) is bv1;
189    alias op2 : bit_vector(bv2'length - 1 downto 0) is bv2;
190    variable result : bit_vector(bv1'length - 1 downto 0);
191    variable carry_in : bit;
192    variable carry_out : bit := '1';
193
194  begin
195    if bv1'length /= bv2'length then
196      report """-"": operands of different lengths"
197        severity failure;
198    else
199      for index in result'reverse_range loop
200        carry_in := carry_out;  -- of previous bit
201        result(index) := op1(index) xor (not op2(index)) xor carry_in;
202        carry_out := (op1(index) and (not op2(index)))
203                     or (carry_in and (op1(index) xor (not op2(index))));
204      end loop;
205    end if;
206    return result;
207  end function "-";
208
209  procedure bv_addu ( bv1, bv2 : in bit_vector;
210      	       	      bv_result : out bit_vector;
211		      overflow : out boolean ) is
212
213    alias op1 : bit_vector(bv1'length - 1 downto 0) is bv1;
214    alias op2 : bit_vector(bv2'length - 1 downto 0) is bv2;
215    variable result : bit_vector(bv_result'length - 1 downto 0);
216    variable carry : bit := '0';
217
218  begin
219    if bv1'length /= bv2'length or bv1'length /= bv_result'length then
220      report "bv_addu: operands of different lengths"
221        severity failure;
222    else
223      for index in result'reverse_range loop
224        result(index) := op1(index) xor op2(index) xor carry;
225        carry := (op1(index) and op2(index))
226                 or (carry and (op1(index) xor op2(index)));
227      end loop;
228      bv_result := result;
229      overflow := carry = '1';
230    end if;
231  end procedure bv_addu;
232
233  function bv_addu ( bv1, bv2 : in bit_vector ) return bit_vector is
234
235    alias op1 : bit_vector(bv1'length - 1 downto 0) is bv1;
236    alias op2 : bit_vector(bv2'length - 1 downto 0) is bv2;
237    variable result : bit_vector(bv1'length - 1 downto 0);
238    variable carry : bit := '0';
239
240  begin
241    if bv1'length /= bv2'length then
242      report "bv_addu: operands of different lengths"
243        severity failure;
244    else
245      for index in result'reverse_range loop
246        result(index) := op1(index) xor op2(index) xor carry;
247        carry := (op1(index) and op2(index))
248                 or (carry and (op1(index) xor op2(index)));
249      end loop;
250    end if;
251    return result;
252  end function bv_addu;
253
254  procedure bv_subu ( bv1, bv2 : in bit_vector;
255      	       	      bv_result : out bit_vector;
256		      overflow : out boolean ) is
257
258    alias op1 : bit_vector(bv1'length - 1 downto 0) is bv1;
259    alias op2 : bit_vector(bv2'length - 1 downto 0) is bv2;
260    variable result : bit_vector(bv_result'length - 1 downto 0);
261    variable borrow : bit := '0';
262
263  begin
264    if bv1'length /= bv2'length or bv1'length /= bv_result'length then
265      report "bv_subu: operands of different lengths"
266        severity failure;
267    else
268      for index in result'reverse_range loop
269        result(index) := op1(index) xor op2(index) xor borrow;
270        borrow := (not op1(index) and op2(index))
271                  or (borrow and not (op1(index) xor op2(index)));
272      end loop;
273      bv_result := result;
274      overflow := borrow = '1';
275    end if;
276  end procedure bv_subu;
277
278  function bv_subu ( bv1, bv2 : in bit_vector ) return bit_vector is
279
280    alias op1 : bit_vector(bv1'length - 1 downto 0) is bv1;
281    alias op2 : bit_vector(bv2'length - 1 downto 0) is bv2;
282    variable result : bit_vector(bv1'length - 1 downto 0);
283    variable borrow : bit := '0';
284
285  begin
286    if bv1'length /= bv2'length then
287      report "bv_subu: operands of different lengths"
288        severity failure;
289    else
290      for index in result'reverse_range loop
291        result(index) := op1(index) xor op2(index) xor borrow;
292        borrow := (not op1(index) and op2(index))
293                  or (borrow and not (op1(index) xor op2(index)));
294      end loop;
295    end if;
296    return result;
297  end function bv_subu;
298
299  procedure bv_neg ( bv : in bit_vector;
300                     bv_result : out bit_vector;
301                     overflow : out boolean ) is
302
303    constant zero : bit_vector(bv'range) := (others => '0');
304
305  begin
306    bv_sub( zero, bv, bv_result, overflow );
307  end procedure bv_neg;
308
309
310  function "-" ( bv : in bit_vector ) return bit_vector is
311
312    constant zero : bit_vector(bv'range) := (others => '0');
313
314  begin
315    return zero - bv;
316  end function "-";
317
318  procedure bv_mult ( bv1, bv2 : in bit_vector;
319      	       	      bv_result : out bit_vector;
320		      overflow : out boolean ) is
321
322    variable negative_result : boolean;
323    variable op1 : bit_vector(bv1'range) := bv1;
324    variable op2 : bit_vector(bv2'range) := bv2;
325    variable multu_result : bit_vector(bv1'range);
326    variable multu_overflow : boolean;
327    variable abs_min_int : bit_vector(bv1'range) := (others => '0');
328
329  begin
330    if bv1'length /= bv2'length or bv1'length /= bv_result'length then
331      report "bv_mult: operands of different lengths"
332        severity failure;
333    else
334      abs_min_int(bv1'left) := '1';
335      negative_result := (op1(op1'left) = '1') xor (op2(op2'left) = '1');
336      if op1(op1'left) = '1' then
337        op1 := - bv1;
338      end if;
339      if op2(op2'left) = '1' then
340        op2 := - bv2;
341      end if;
342      bv_multu(op1, op2, multu_result, multu_overflow);
343      if negative_result then
344        overflow := multu_overflow or (multu_result > abs_min_int);
345        bv_result := - multu_result;
346      else
347        overflow := multu_overflow or (multu_result(multu_result'left) = '1');
348        bv_result := multu_result;
349      end if;
350    end if;
351  end procedure bv_mult;
352
353  function "*" ( bv1, bv2 : in bit_vector ) return bit_vector is
354
355    variable negative_result : boolean;
356    variable op1 : bit_vector(bv1'range) := bv1;
357    variable op2 : bit_vector(bv2'range) := bv2;
358    variable result : bit_vector(bv1'range);
359
360  begin
361    if bv1'length /= bv2'length then
362      report """*"": operands of different lengths"
363        severity failure;
364    else
365      negative_result := (op1(op1'left) = '1') xor (op2(op2'left) = '1');
366      if op1(op1'left) = '1' then
367        op1 := - bv1;
368      end if;
369      if op2(op2'left) = '1' then
370        op2 := - bv2;
371      end if;
372      result := bv_multu(op1, op2);
373      if negative_result then
374        result := - result;
375      end if;
376    end if;
377    return result;
378  end function "*";
379
380  procedure bv_multu ( bv1, bv2 : in bit_vector;
381      	       	       bv_result : out bit_vector;
382		       overflow : out boolean ) is
383
384    alias op1 : bit_vector(bv1'length - 1 downto 0) is bv1;
385    alias op2 : bit_vector(bv2'length - 1 downto 0) is bv2;
386    constant len : natural := bv1'length;
387    constant accum_len : natural := len * 2;
388    variable accum : bit_vector(accum_len - 1 downto 0) := (others => '0');
389    constant zero : bit_vector(accum_len - 1 downto len):= (others => '0');
390    variable addu_overflow : boolean;
391
392  begin
393    if bv1'length /= bv2'length or bv1'length /= bv_result'length then
394      report "bv_multu: operands of different lengths"
395        severity failure;
396    else
397      for count in 0 to len - 1 loop
398        if op2(count) = '1' then
399          bv_addu( accum(count + len - 1 downto count), op1,
400                   accum(count + len - 1 downto count), addu_overflow);
401          accum(count + len) := bit'val(boolean'pos(addu_overflow));
402        end if;
403      end loop;
404      bv_result := accum(len - 1 downto 0);
405      overflow := accum(accum_len-1 downto len) /= zero;
406    end if;
407  end procedure bv_multu;
408
409  function bv_multu ( bv1, bv2 : in bit_vector ) return bit_vector is
410
411    -- Use bv_multu with overflow detection, but ignore overflow flag
412
413    variable result : bit_vector(bv1'range);
414    variable tmp_overflow : boolean;
415
416  begin
417    bv_multu(bv1, bv2, result, tmp_overflow);
418    return result;
419  end function bv_multu;
420
421  procedure bv_div ( bv1, bv2 : in bit_vector;
422      	       	     bv_result : out bit_vector;
423		     div_by_zero : out boolean;
424                     overflow : out boolean ) is
425
426    --  Need overflow, in case divide b"10...0" (min_int) by -1
427    --  Don't use bv_to_int, in case size bigger than host machine!
428
429    variable negative_result : boolean;
430    variable op1 : bit_vector(bv1'range) := bv1;
431    variable op2 : bit_vector(bv2'range) := bv2;
432    variable divu_result : bit_vector(bv1'range);
433
434  begin
435    if bv1'length /= bv2'length or bv1'length /= bv_result'length then
436      report "bv_div: operands of different lengths"
437        severity failure;
438    else
439      negative_result := (op1(op1'left) = '1') xor (op2(op2'left) = '1');
440      if op1(op1'left) = '1' then
441        op1 := - bv1;
442      end if;
443      if op2(op2'left) = '1' then
444        op2 := - bv2;
445      end if;
446      bv_divu(op1, op2, divu_result, div_by_zero);
447      if negative_result then
448        overflow := false;
449        bv_result := - divu_result;
450      else
451        overflow := divu_result(divu_result'left) = '1';
452        bv_result := divu_result;
453      end if;
454    end if;
455  end procedure bv_div;
456
457  function "/" ( bv1, bv2 : in bit_vector ) return bit_vector is
458
459    variable negative_result : boolean;
460    variable op1 : bit_vector(bv1'range) := bv1;
461    variable op2 : bit_vector(bv2'range) := bv2;
462    variable result : bit_vector(bv1'range);
463
464  begin
465    if bv1'length /= bv2'length then
466      report """/"": operands of different lengths"
467        severity failure;
468    else
469      negative_result := (op1(op1'left) = '1') xor (op2(op2'left) = '1');
470      if op1(op1'left) = '1' then
471        op1 := - bv1;
472      end if;
473      if op2(op2'left) = '1' then
474        op2 := - bv2;
475      end if;
476      result := bv_divu(op1, op2);
477      if negative_result then
478        result := - result;
479      end if;
480    end if;
481    return result;
482  end function "/";
483
484  procedure bv_divu ( bv1, bv2 : in bit_vector;
485      	       	      bv_quotient : out bit_vector;
486		      bv_remainder : out bit_vector;
487		      div_by_zero : out boolean ) is
488
489    constant len : natural := bv1'length;
490    constant zero_divisor : bit_vector(len-1 downto 0) := (others => '0');
491    alias dividend : bit_vector(bv1'length-1 downto 0) is bv1;
492    variable divisor : bit_vector(bv2'length downto 0) := '0' & bv2;
493    variable quotient : bit_vector(len-1 downto 0);
494    variable remainder : bit_vector(len downto 0) := (others => '0');
495    variable ignore_overflow  : boolean;
496
497  begin
498    if bv1'length /= bv2'length
499      or bv1'length /= bv_quotient'length or bv1'length /= bv_remainder'length then
500      report "bv_divu: operands of different lengths"
501        severity failure;
502    else
503      --  check for zero divisor
504      if bv2 = zero_divisor then
505        div_by_zero := true;
506        return;
507      end if;
508      --  perform division
509      for iter in len-1 downto 0 loop
510        if remainder(len) = '0' then
511          remainder := remainder sll 1;
512          remainder(0) := dividend(iter);
513          bv_sub(remainder, divisor, remainder, ignore_overflow);
514        else
515          remainder := remainder sll 1;
516          remainder(0) := dividend(iter);
517          bv_add(remainder, divisor, remainder, ignore_overflow);
518        end if;
519        quotient(iter) := not remainder(len);
520      end loop;
521      if remainder(len) = '1' then
522        bv_add(remainder, divisor, remainder, ignore_overflow);
523      end if;
524      bv_quotient := quotient;
525      bv_remainder := remainder(len - 1 downto 0);
526      div_by_zero := false;
527    end if;
528  end procedure bv_divu;
529
530  procedure bv_divu ( bv1, bv2 : in bit_vector;
531      	       	      bv_quotient : out bit_vector;
532		      div_by_zero : out boolean ) is
533
534    variable ignore_remainder : bit_vector(bv_quotient'range);
535
536  begin
537    bv_divu(bv1, bv2, bv_quotient, ignore_remainder, div_by_zero);
538  end procedure bv_divu;
539
540  function bv_divu ( bv1, bv2 : in bit_vector ) return bit_vector is
541
542    variable result : bit_vector(bv1'range);
543    variable tmp_div_by_zero : boolean;
544
545  begin
546    bv_divu(bv1, bv2, result, tmp_div_by_zero);
547    return result;
548  end function bv_divu;
549
550  ----------------------------------------------------------------
551  --  Arithmetic comparison operators.
552  --  Perform comparisons on bit vector encoded signed integers.
553  --  (For unsigned integers, built in lexical comparison does
554  --  the required operation.)
555  ----------------------------------------------------------------
556
557  function bv_lt ( bv1, bv2 : in bit_vector ) return boolean is
558
559    variable tmp1 : bit_vector(bv1'range) := bv1;
560    variable tmp2 : bit_vector(bv2'range) := bv2;
561
562  begin
563    assert bv1'length = bv2'length
564      report "bv_lt: operands of different lengths"
565      severity failure;
566    tmp1(tmp1'left) := not tmp1(tmp1'left);
567    tmp2(tmp2'left) := not tmp2(tmp2'left);
568    return tmp1 < tmp2;
569  end function bv_lt;
570
571  function bv_le ( bv1, bv2 : in bit_vector ) return boolean is
572
573    variable tmp1 : bit_vector(bv1'range) := bv1;
574    variable tmp2 : bit_vector(bv2'range) := bv2;
575
576  begin
577    assert bv1'length = bv2'length
578      report "bv_le: operands of different lengths"
579      severity failure;
580    tmp1(tmp1'left) := not tmp1(tmp1'left);
581    tmp2(tmp2'left) := not tmp2(tmp2'left);
582    return tmp1 <= tmp2;
583  end function bv_le;
584
585  function bv_gt ( bv1, bv2 : in bit_vector ) return boolean is
586
587    variable tmp1 : bit_vector(bv1'range) := bv1;
588    variable tmp2 : bit_vector(bv2'range) := bv2;
589
590  begin
591    assert bv1'length = bv2'length
592      report "bv_gt: operands of different lengths"
593      severity failure;
594    tmp1(tmp1'left) := not tmp1(tmp1'left);
595    tmp2(tmp2'left) := not tmp2(tmp2'left);
596    return tmp1 > tmp2;
597  end function bv_gt;
598
599  function bv_ge ( bv1, bv2 : in bit_vector ) return boolean is
600
601    variable tmp1 : bit_vector(bv1'range) := bv1;
602    variable tmp2 : bit_vector(bv2'range) := bv2;
603
604  begin
605    assert bv1'length = bv2'length
606      report "bv_ged: operands of different lengths"
607      severity failure;
608    tmp1(tmp1'left) := not tmp1(tmp1'left);
609    tmp2(tmp2'left) := not tmp2(tmp2'left);
610    return tmp1 >= tmp2;
611  end function bv_ge;
612
613  ----------------------------------------------------------------
614  --  Extension operators - convert a bit vector to a longer one
615  ----------------------------------------------------------------
616
617  function bv_sext ( bv : in bit_vector;
618      	      	     length : in natural ) return bit_vector is
619
620    alias bv_norm : bit_vector(bv'length - 1 downto 0) is bv;
621    variable result : bit_vector(length - 1 downto 0) := (others => bv(bv'left));
622    variable src_length : natural := bv'length;
623
624  begin
625    if src_length > length then
626      src_length := length;
627    end if;
628    result(src_length - 1 downto 0) := bv_norm(src_length - 1 downto 0);
629    return result;
630  end function bv_sext;
631
632  function bv_zext ( bv : in bit_vector;
633      	      	     length : in natural ) return bit_vector is
634
635    alias bv_norm : bit_vector(bv'length - 1 downto 0) is bv;
636    variable result : bit_vector(length - 1 downto 0) := (others => '0');
637    variable src_length : natural := bv'length;
638
639  begin
640    if src_length > length then
641      src_length := length;
642    end if;
643    result(src_length - 1 downto 0) := bv_norm(src_length - 1 downto 0);
644    return result;
645  end function bv_zext;
646
647end package body bv_arithmetic;
648