- added
git-svn-id: http://moon:8086/svn/vhdl/trunk@1424 cc03376c-175c-47c8-b038-4cd826a8556b
This commit is contained in:
@@ -0,0 +1,982 @@
|
||||
--------------------------------------------------------------------------
|
||||
--
|
||||
-- Copyright (C) 1993, Peter J. Ashenden
|
||||
-- Mail: Dept. Computer Science
|
||||
-- University of Adelaide, SA 5005, Australia
|
||||
-- e-mail: petera@cs.adelaide.edu.au
|
||||
--
|
||||
-- This program is free software; you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation; either version 1, or (at your option)
|
||||
-- any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License
|
||||
-- along with this program; if not, write to the Free Software
|
||||
-- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
--
|
||||
--------------------------------------------------------------------------
|
||||
--
|
||||
-- $RCSfile: bv_arithmetic-body.vhdl,v $ $Revision: 2.1 $ $Date: 1993/11/02 22:50:39 $
|
||||
--
|
||||
--------------------------------------------------------------------------
|
||||
--
|
||||
-- Bit vector arithmetic package body.
|
||||
--
|
||||
-- Does arithmetic and logical operations on bit vectors, treating them
|
||||
-- as either unsigned or signed (2's complement) integers. Leftmost bit
|
||||
-- is most significant or sign bit, rightmost bit is least significant
|
||||
-- bit. Dyadic operations need the two arguments to be of the same
|
||||
-- length, however their index ranges and directions may differ. Results
|
||||
-- must be of the same length as the operands.
|
||||
--
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
package body bv_arithmetic is
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- Type conversions
|
||||
----------------------------------------------------------------
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_to_natural
|
||||
--
|
||||
-- Convert bit vector encoded unsigned integer to natural.
|
||||
----------------------------------------------------------------
|
||||
|
||||
function bv_to_natural(bv : in bit_vector) return natural is
|
||||
|
||||
variable result : natural := 0;
|
||||
|
||||
begin
|
||||
for index in bv'range loop
|
||||
result := result * 2 + bit'pos(bv(index));
|
||||
end loop;
|
||||
return result;
|
||||
end bv_to_natural;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- natural_to_bv
|
||||
--
|
||||
-- Convert natural to bit vector encoded unsigned integer.
|
||||
-- (length is used as the size of the result.)
|
||||
----------------------------------------------------------------
|
||||
|
||||
function natural_to_bv(nat : in natural;
|
||||
length : in natural) return bit_vector is
|
||||
|
||||
variable temp : natural := nat;
|
||||
variable result : bit_vector(0 to length-1);
|
||||
|
||||
begin
|
||||
for index in result'reverse_range loop
|
||||
result(index) := bit'val(temp rem 2);
|
||||
temp := temp / 2;
|
||||
end loop;
|
||||
return result;
|
||||
end natural_to_bv;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_to_integer
|
||||
--
|
||||
-- Convert bit vector encoded signed integer to integer
|
||||
----------------------------------------------------------------
|
||||
|
||||
function bv_to_integer(bv : in bit_vector) return integer is
|
||||
|
||||
variable temp : bit_vector(bv'range);
|
||||
variable result : integer := 0;
|
||||
|
||||
begin
|
||||
if bv(bv'left) = '1' then -- negative number
|
||||
temp := not bv;
|
||||
else
|
||||
temp := bv;
|
||||
end if;
|
||||
for index in bv'range loop -- sign bit of temp = '0'
|
||||
result := result * 2 + bit'pos(temp(index));
|
||||
end loop;
|
||||
if bv(bv'left) = '1' then
|
||||
result := (-result) - 1;
|
||||
end if;
|
||||
return result;
|
||||
end bv_to_integer;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- integer_to_bv
|
||||
--
|
||||
-- Convert integer to bit vector encoded signed integer.
|
||||
-- (length is used as the size of the result.)
|
||||
----------------------------------------------------------------
|
||||
|
||||
function integer_to_bv(int : in integer;
|
||||
length : in natural) return bit_vector is
|
||||
|
||||
variable temp : integer;
|
||||
variable result : bit_vector(0 to length-1);
|
||||
|
||||
begin
|
||||
if int < 0 then
|
||||
temp := -(int+1);
|
||||
else
|
||||
temp := int;
|
||||
end if;
|
||||
for index in result'reverse_range loop
|
||||
result(index) := bit'val(temp rem 2);
|
||||
temp := temp / 2;
|
||||
end loop;
|
||||
if int < 0 then
|
||||
result := not result;
|
||||
result(result'left) := '1';
|
||||
end if;
|
||||
return result;
|
||||
end integer_to_bv;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- Arithmetic operations
|
||||
----------------------------------------------------------------
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_add
|
||||
--
|
||||
-- Signed addition with overflow detection
|
||||
----------------------------------------------------------------
|
||||
|
||||
procedure bv_add (bv1, bv2 : in bit_vector;
|
||||
bv_result : out bit_vector;
|
||||
overflow : out boolean) is
|
||||
|
||||
alias op1 : bit_vector(1 to bv1'length) is bv1;
|
||||
alias op2 : bit_vector(1 to bv2'length) is bv2;
|
||||
variable result : bit_vector(1 to bv_result'length);
|
||||
variable carry_in : bit;
|
||||
variable carry_out : bit := '0';
|
||||
|
||||
begin
|
||||
assert bv1'length = bv2'length and bv1'length = bv_result'length
|
||||
report "bv_add: operands of different lengths"
|
||||
severity failure;
|
||||
for index in result'reverse_range loop
|
||||
carry_in := carry_out; -- of previous bit
|
||||
result(index) := op1(index) xor op2(index) xor carry_in;
|
||||
carry_out := (op1(index) and op2(index))
|
||||
or (carry_in and (op1(index) xor op2(index)));
|
||||
end loop;
|
||||
bv_result := result;
|
||||
overflow := carry_out /= carry_in;
|
||||
end bv_add;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- "+"
|
||||
--
|
||||
-- Signed addition without overflow detection
|
||||
----------------------------------------------------------------
|
||||
|
||||
function "+" (bv1, bv2 : in bit_vector) return bit_vector is
|
||||
|
||||
alias op1 : bit_vector(1 to bv1'length) is bv1;
|
||||
alias op2 : bit_vector(1 to bv2'length) is bv2;
|
||||
variable result : bit_vector(1 to bv1'length);
|
||||
variable carry_in : bit;
|
||||
variable carry_out : bit := '0';
|
||||
|
||||
begin
|
||||
assert bv1'length = bv2'length
|
||||
-- use concatenation to work around Synthesia MINT code gen bug
|
||||
report '"' & '+' & '"' & ": operands of different lengths"
|
||||
severity failure;
|
||||
for index in result'reverse_range loop
|
||||
carry_in := carry_out; -- of previous bit
|
||||
result(index) := op1(index) xor op2(index) xor carry_in;
|
||||
carry_out := (op1(index) and op2(index))
|
||||
or (carry_in and (op1(index) xor op2(index)));
|
||||
end loop;
|
||||
return result;
|
||||
end "+";
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_sub
|
||||
--
|
||||
-- Signed subtraction with overflow detection
|
||||
----------------------------------------------------------------
|
||||
|
||||
procedure bv_sub (bv1, bv2 : in bit_vector;
|
||||
bv_result : out bit_vector;
|
||||
overflow : out boolean) is
|
||||
|
||||
-- subtraction implemented by adding ((not bv2) + 1), ie -bv2
|
||||
|
||||
alias op1 : bit_vector(1 to bv1'length) is bv1;
|
||||
alias op2 : bit_vector(1 to bv2'length) is bv2;
|
||||
variable result : bit_vector(1 to bv_result'length);
|
||||
variable carry_in : bit;
|
||||
variable carry_out : bit := '1';
|
||||
|
||||
begin
|
||||
assert bv1'length = bv2'length and bv1'length = bv_result'length
|
||||
report "bv_sub: operands of different lengths"
|
||||
severity failure;
|
||||
for index in result'reverse_range loop
|
||||
carry_in := carry_out; -- of previous bit
|
||||
result(index) := op1(index) xor (not op2(index)) xor carry_in;
|
||||
carry_out := (op1(index) and (not op2(index)))
|
||||
or (carry_in and (op1(index) xor (not op2(index))));
|
||||
end loop;
|
||||
bv_result := result;
|
||||
overflow := carry_out /= carry_in;
|
||||
end bv_sub;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- "-"
|
||||
--
|
||||
-- Signed subtraction without overflow detection
|
||||
----------------------------------------------------------------
|
||||
|
||||
function "-" (bv1, bv2 : in bit_vector) return bit_vector is
|
||||
|
||||
-- subtraction implemented by adding ((not bv2) + 1), ie -bv2
|
||||
|
||||
alias op1 : bit_vector(1 to bv1'length) is bv1;
|
||||
alias op2 : bit_vector(1 to bv2'length) is bv2;
|
||||
variable result : bit_vector(1 to bv1'length);
|
||||
variable carry_in : bit;
|
||||
variable carry_out : bit := '1';
|
||||
|
||||
begin
|
||||
assert bv1'length = bv2'length
|
||||
-- use concatenation to work around Synthesia MINT code gen bug
|
||||
report '"' & '-' & '"' & ": operands of different lengths"
|
||||
severity failure;
|
||||
for index in result'reverse_range loop
|
||||
carry_in := carry_out; -- of previous bit
|
||||
result(index) := op1(index) xor (not op2(index)) xor carry_in;
|
||||
carry_out := (op1(index) and (not op2(index)))
|
||||
or (carry_in and (op1(index) xor (not op2(index))));
|
||||
end loop;
|
||||
return result;
|
||||
end "-";
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_addu
|
||||
--
|
||||
-- Unsigned addition with overflow detection
|
||||
----------------------------------------------------------------
|
||||
|
||||
procedure bv_addu (bv1, bv2 : in bit_vector;
|
||||
bv_result : out bit_vector;
|
||||
overflow : out boolean) is
|
||||
|
||||
alias op1 : bit_vector(1 to bv1'length) is bv1;
|
||||
alias op2 : bit_vector(1 to bv2'length) is bv2;
|
||||
variable result : bit_vector(1 to bv_result'length);
|
||||
variable carry : bit := '0';
|
||||
|
||||
begin
|
||||
assert bv1'length = bv2'length and bv1'length = bv_result'length
|
||||
report "bv_addu: operands of different lengths"
|
||||
severity failure;
|
||||
for index in result'reverse_range loop
|
||||
result(index) := op1(index) xor op2(index) xor carry;
|
||||
carry := (op1(index) and op2(index))
|
||||
or (carry and (op1(index) xor op2(index)));
|
||||
end loop;
|
||||
bv_result := result;
|
||||
overflow := carry = '1';
|
||||
end bv_addu;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_addu
|
||||
--
|
||||
-- Unsigned addition without overflow detection
|
||||
----------------------------------------------------------------
|
||||
|
||||
procedure bv_addu (bv1, bv2 : in bit_vector;
|
||||
bv_result : out bit_vector) is
|
||||
|
||||
alias op1 : bit_vector(1 to bv1'length) is bv1;
|
||||
alias op2 : bit_vector(1 to bv2'length) is bv2;
|
||||
variable result : bit_vector(1 to bv_result'length);
|
||||
variable carry : bit := '0';
|
||||
|
||||
begin
|
||||
assert bv1'length = bv2'length and bv1'length = bv_result'length
|
||||
report "bv_addu: operands of different lengths"
|
||||
severity failure;
|
||||
for index in result'reverse_range loop
|
||||
result(index) := op1(index) xor op2(index) xor carry;
|
||||
carry := (op1(index) and op2(index))
|
||||
or (carry and (op1(index) xor op2(index)));
|
||||
end loop;
|
||||
bv_result := result;
|
||||
end bv_addu;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_subu
|
||||
--
|
||||
-- Unsigned subtraction with overflow detection
|
||||
----------------------------------------------------------------
|
||||
|
||||
procedure bv_subu (bv1, bv2 : in bit_vector;
|
||||
bv_result : out bit_vector;
|
||||
overflow : out boolean) is
|
||||
|
||||
alias op1 : bit_vector(1 to bv1'length) is bv1;
|
||||
alias op2 : bit_vector(1 to bv2'length) is bv2;
|
||||
variable result : bit_vector(1 to bv_result'length);
|
||||
variable borrow : bit := '0';
|
||||
|
||||
begin
|
||||
assert bv1'length = bv2'length and bv1'length = bv_result'length
|
||||
report "bv_subu: operands of different lengths"
|
||||
severity failure;
|
||||
for index in result'reverse_range loop
|
||||
result(index) := op1(index) xor op2(index) xor borrow;
|
||||
borrow := (not op1(index) and op2(index))
|
||||
or (borrow and not (op1(index) xor op2(index)));
|
||||
end loop;
|
||||
bv_result := result;
|
||||
overflow := borrow = '1';
|
||||
end bv_subu;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_subu
|
||||
--
|
||||
-- Unsigned subtraction without overflow detection
|
||||
----------------------------------------------------------------
|
||||
|
||||
procedure bv_subu (bv1, bv2 : in bit_vector;
|
||||
bv_result : out bit_vector) is
|
||||
|
||||
alias op1 : bit_vector(1 to bv1'length) is bv1;
|
||||
alias op2 : bit_vector(1 to bv2'length) is bv2;
|
||||
variable result : bit_vector(1 to bv_result'length);
|
||||
variable borrow : bit := '0';
|
||||
|
||||
begin
|
||||
assert bv1'length = bv2'length and bv1'length = bv_result'length
|
||||
report "bv_subu: operands of different lengths"
|
||||
severity failure;
|
||||
for index in result'reverse_range loop
|
||||
result(index) := op1(index) xor op2(index) xor borrow;
|
||||
borrow := (not op1(index) and op2(index))
|
||||
or (borrow and not (op1(index) xor op2(index)));
|
||||
end loop;
|
||||
bv_result := result;
|
||||
end bv_subu;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_neg
|
||||
--
|
||||
-- Signed negation with overflow detection
|
||||
----------------------------------------------------------------
|
||||
|
||||
procedure bv_neg (bv : in bit_vector;
|
||||
bv_result : out bit_vector;
|
||||
overflow : out boolean) is
|
||||
|
||||
CONSTANT zero : bit_vector(bv'range) := (others => '0');
|
||||
|
||||
begin
|
||||
bv_sub( zero, bv, bv_result, overflow );
|
||||
end bv_neg;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- "-"
|
||||
--
|
||||
-- Signed negation without overflow detection
|
||||
----------------------------------------------------------------
|
||||
|
||||
function "-" (bv : in bit_vector) return bit_vector is
|
||||
|
||||
CONSTANT zero : bit_vector(bv'range) := (others => '0');
|
||||
|
||||
begin
|
||||
return zero - bv;
|
||||
end "-";
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_mult
|
||||
--
|
||||
-- Signed multiplication with overflow detection
|
||||
----------------------------------------------------------------
|
||||
|
||||
procedure bv_mult (bv1, bv2 : in bit_vector;
|
||||
bv_result : out bit_vector;
|
||||
overflow : out boolean) is
|
||||
|
||||
variable negative_result : boolean;
|
||||
variable op1 : bit_vector(bv1'range) := bv1;
|
||||
variable op2 : bit_vector(bv2'range) := bv2;
|
||||
variable multu_result : bit_vector(bv1'range);
|
||||
variable multu_overflow : boolean;
|
||||
-- constant abs_min_int : bit_vector(bv1'range)
|
||||
-- := (bv1'left => '1', others => '0');
|
||||
-- causes Synthesia MINT code generator to prang. Work around:
|
||||
variable abs_min_int : bit_vector(bv1'range) := (others => '0');
|
||||
|
||||
begin
|
||||
assert bv1'length = bv2'length and bv1'length = bv_result'length
|
||||
report "bv_mult: operands of different lengths"
|
||||
severity failure;
|
||||
abs_min_int(bv1'left) := '1'; -- Synthesia work around
|
||||
negative_result := (op1(op1'left) = '1') xor (op2(op2'left) = '1');
|
||||
if (op1(op1'left) = '1') then
|
||||
op1 := - bv1;
|
||||
end if;
|
||||
if (op2(op2'left) = '1') then
|
||||
op2 := - bv2;
|
||||
end if;
|
||||
bv_multu(op1, op2, multu_result, multu_overflow);
|
||||
if (negative_result) then
|
||||
overflow := multu_overflow or (multu_result > abs_min_int);
|
||||
bv_result := - multu_result;
|
||||
else
|
||||
overflow := multu_overflow or (multu_result(multu_result'left) = '1');
|
||||
bv_result := multu_result;
|
||||
end if;
|
||||
end bv_mult;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- "*"
|
||||
--
|
||||
-- Signed multiplication without overflow detection
|
||||
----------------------------------------------------------------
|
||||
|
||||
function "*" (bv1, bv2 : in bit_vector) return bit_vector is
|
||||
|
||||
variable negative_result : boolean;
|
||||
variable op1 : bit_vector(bv1'range) := bv1;
|
||||
variable op2 : bit_vector(bv2'range) := bv2;
|
||||
variable result : bit_vector(bv1'range);
|
||||
|
||||
begin
|
||||
assert bv1'length = bv2'length
|
||||
-- use concatenation to work around Synthesia MINT code gen bug
|
||||
report '"' & '*' & '"' & ": operands of different lengths"
|
||||
severity failure;
|
||||
negative_result := (op1(op1'left) = '1') xor (op2(op2'left) = '1');
|
||||
if (op1(op1'left) = '1') then
|
||||
op1 := - bv1;
|
||||
end if;
|
||||
if (op2(op2'left) = '1') then
|
||||
op2 := - bv2;
|
||||
end if;
|
||||
bv_multu(op1, op2, result);
|
||||
if (negative_result) then
|
||||
result := - result;
|
||||
end if;
|
||||
return result;
|
||||
end "*";
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_multu
|
||||
--
|
||||
-- Unsigned multiplication with overflow detection
|
||||
----------------------------------------------------------------
|
||||
|
||||
procedure bv_multu (bv1, bv2 : in bit_vector;
|
||||
bv_result : out bit_vector;
|
||||
overflow : out boolean) is
|
||||
|
||||
-- Based on shift&add multiplier in Appendix A of Hennessy & Patterson
|
||||
|
||||
constant bv_length : natural := bv1'length;
|
||||
constant accum_length : natural := bv_length * 2;
|
||||
constant zero : bit_vector(accum_length-1 downto bv_length)
|
||||
:= (others => '0');
|
||||
variable accum : bit_vector(accum_length-1 downto 0);
|
||||
variable addu_overflow : boolean;
|
||||
variable carry : bit;
|
||||
|
||||
begin
|
||||
assert bv1'length = bv2'length and bv1'length = bv_result'length
|
||||
report "bv_multu: operands of different lengths"
|
||||
severity failure;
|
||||
accum(bv_length-1 downto 0) := bv1;
|
||||
accum(accum_length-1 downto bv_length) := zero;
|
||||
for count in 1 to bv_length loop
|
||||
if (accum(0) = '1') then
|
||||
bv_addu( accum(accum_length-1 downto bv_length), bv2,
|
||||
accum(accum_length-1 downto bv_length), addu_overflow);
|
||||
carry := bit'val(boolean'pos(addu_overflow));
|
||||
else
|
||||
carry := '0';
|
||||
end if;
|
||||
accum := carry & accum(accum_length-1 downto 1);
|
||||
end loop;
|
||||
bv_result := accum(bv_length-1 downto 0);
|
||||
overflow := accum(accum_length-1 downto bv_length) /= zero;
|
||||
end bv_multu;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_multu
|
||||
--
|
||||
-- Unsigned multiplication without overflow detection
|
||||
----------------------------------------------------------------
|
||||
|
||||
procedure bv_multu (bv1, bv2 : in bit_vector;
|
||||
bv_result : out bit_vector) is
|
||||
|
||||
-- Use bv_multu with overflow detection, but ignore overflow flag
|
||||
|
||||
variable tmp_overflow : boolean;
|
||||
|
||||
begin
|
||||
-- following procedure asserts bv1'length = bv2'length
|
||||
bv_multu(bv1, bv2, bv_result, tmp_overflow);
|
||||
end bv_multu;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_div
|
||||
--
|
||||
-- Signed division with divide by zero and overflow detection
|
||||
----------------------------------------------------------------
|
||||
|
||||
procedure bv_div (bv1, bv2 : in bit_vector;
|
||||
bv_result : out bit_vector;
|
||||
div_by_zero : out boolean;
|
||||
overflow : out boolean) is
|
||||
|
||||
-- Need overflow, in case divide b"10...0" (min_int) by -1
|
||||
-- Don't use bv_to_int, in case size bigger than host machine!
|
||||
|
||||
variable negative_result : boolean;
|
||||
variable op1 : bit_vector(bv1'range) := bv1;
|
||||
variable op2 : bit_vector(bv2'range) := bv2;
|
||||
variable divu_result : bit_vector(bv1'range);
|
||||
|
||||
begin
|
||||
assert bv1'length = bv2'length
|
||||
report "bv_div: operands of different lengths"
|
||||
severity failure;
|
||||
negative_result := (op1(op1'left) = '1') xor (op2(op2'left) = '1');
|
||||
if (op1(op1'left) = '1') then
|
||||
op1 := - bv1;
|
||||
end if;
|
||||
if (op2(op2'left) = '1') then
|
||||
op2 := - bv2;
|
||||
end if;
|
||||
bv_divu(op1, op2, divu_result, div_by_zero);
|
||||
if (negative_result) then
|
||||
overflow := false;
|
||||
bv_result := - divu_result;
|
||||
else
|
||||
overflow := divu_result(divu_result'left) = '1';
|
||||
bv_result := divu_result;
|
||||
end if;
|
||||
end bv_div;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- "/"
|
||||
--
|
||||
-- Signed division without divide by zero and overflow detection
|
||||
----------------------------------------------------------------
|
||||
|
||||
function "/" (bv1, bv2 : in bit_vector) return bit_vector is
|
||||
|
||||
variable negative_result : boolean;
|
||||
variable op1 : bit_vector(bv1'range) := bv1;
|
||||
variable op2 : bit_vector(bv2'range) := bv2;
|
||||
variable result : bit_vector(bv1'range);
|
||||
|
||||
begin
|
||||
assert bv1'length = bv2'length
|
||||
-- use concatenation to work around Synthesia MINT code gen bug
|
||||
report '"' & '/' & '"' & ": operands of different lengths"
|
||||
severity failure;
|
||||
negative_result := (op1(op1'left) = '1') xor (op2(op2'left) = '1');
|
||||
if (op1(op1'left) = '1') then
|
||||
op1 := - bv1;
|
||||
end if;
|
||||
if (op2(op2'left) = '1') then
|
||||
op2 := - bv2;
|
||||
end if;
|
||||
bv_divu(op1, op2, result);
|
||||
if (negative_result) then
|
||||
result := - result;
|
||||
end if;
|
||||
return result;
|
||||
end "/";
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_divu
|
||||
--
|
||||
-- Unsigned division with divide by zero detection
|
||||
----------------------------------------------------------------
|
||||
|
||||
procedure bv_divu (bv1, bv2 : in bit_vector;
|
||||
bv_result : out bit_vector;
|
||||
div_by_zero : out boolean) is
|
||||
|
||||
-- based on algorithm in Sun Sparc architecture manual
|
||||
|
||||
constant len : natural := bv1'length;
|
||||
variable zero, one,
|
||||
big_value : bit_vector(len-1 downto 0)
|
||||
:= (others => '0');
|
||||
variable dividend : bit_vector(bv1'length-1 downto 0) := bv1;
|
||||
variable divisor : bit_vector(bv2'length-1 downto 0) := bv2;
|
||||
variable quotient : bit_vector(len-1 downto 0); -- unsigned
|
||||
variable remainder : bit_vector(len-1 downto 0); -- signed
|
||||
variable shifted_divisor,
|
||||
shifted_1 : bit_vector(len-1 downto 0);
|
||||
variable log_quotient : natural;
|
||||
variable ignore_overflow : boolean;
|
||||
|
||||
begin
|
||||
assert bv1'length = bv2'length
|
||||
report "bv_divu: operands of different lengths"
|
||||
severity failure;
|
||||
one(0) := '1';
|
||||
big_value(len-2) := '1';
|
||||
--
|
||||
-- check for zero divisor
|
||||
--
|
||||
if (divisor = zero) then
|
||||
div_by_zero := true;
|
||||
return;
|
||||
end if;
|
||||
--
|
||||
-- estimate log of quotient
|
||||
--
|
||||
log_quotient := 0;
|
||||
shifted_divisor := divisor;
|
||||
loop
|
||||
exit when (log_quotient >= len)
|
||||
or (shifted_divisor > big_value)
|
||||
or (shifted_divisor >= dividend);
|
||||
log_quotient := log_quotient + 1;
|
||||
shifted_divisor := bv_sll(shifted_divisor, 1);
|
||||
end loop;
|
||||
--
|
||||
-- perform division
|
||||
--
|
||||
remainder := dividend;
|
||||
quotient := zero;
|
||||
shifted_divisor := bv_sll(divisor, log_quotient);
|
||||
shifted_1 := bv_sll(one, log_quotient);
|
||||
for iter in log_quotient downto 0 loop
|
||||
if bv_ge(remainder, zero) then
|
||||
bv_sub(remainder, shifted_divisor, remainder, ignore_overflow);
|
||||
bv_addu(quotient, shifted_1, quotient, ignore_overflow);
|
||||
else
|
||||
bv_add(remainder, shifted_divisor, remainder, ignore_overflow);
|
||||
bv_subu(quotient, shifted_1, quotient, ignore_overflow);
|
||||
end if;
|
||||
shifted_divisor := '0' & shifted_divisor(len-1 downto 1);
|
||||
shifted_1 := '0' & shifted_1(len-1 downto 1);
|
||||
end loop;
|
||||
if (bv_lt(remainder, zero)) then
|
||||
bv_add(remainder, divisor, remainder, ignore_overflow);
|
||||
bv_subu(quotient, one, quotient, ignore_overflow);
|
||||
end if;
|
||||
bv_result := quotient;
|
||||
end bv_divu;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_divu
|
||||
--
|
||||
-- Unsigned division without divide by zero detection
|
||||
----------------------------------------------------------------
|
||||
|
||||
procedure bv_divu (bv1, bv2 : in bit_vector;
|
||||
bv_result : out bit_vector) is
|
||||
|
||||
-- Use bv_divu with divide by zero detection,
|
||||
-- but ignore div_by_zero flag
|
||||
|
||||
variable tmp_div_by_zero : boolean;
|
||||
|
||||
begin
|
||||
-- following procedure asserts bv1'length = bv2'length
|
||||
bv_divu(bv1, bv2, bv_result, tmp_div_by_zero);
|
||||
end bv_divu;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- Logical operators
|
||||
-- (Provided for VHDL-87, built in for VHDL-93)
|
||||
----------------------------------------------------------------
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_sll
|
||||
--
|
||||
-- Shift left logical (fill with '0' bits)
|
||||
----------------------------------------------------------------
|
||||
|
||||
function bv_sll (bv : in bit_vector;
|
||||
shift_count : in natural) return bit_vector is
|
||||
|
||||
constant bv_length : natural := bv'length;
|
||||
constant actual_shift_count : natural := shift_count mod bv_length;
|
||||
alias bv_norm : bit_vector(1 to bv_length) is bv;
|
||||
variable result : bit_vector(1 to bv_length) := (others => '0');
|
||||
|
||||
begin
|
||||
result(1 to bv_length - actual_shift_count)
|
||||
:= bv_norm(actual_shift_count + 1 to bv_length);
|
||||
return result;
|
||||
end bv_sll;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_srl
|
||||
--
|
||||
-- Shift right logical (fill with '0' bits)
|
||||
----------------------------------------------------------------
|
||||
|
||||
function bv_srl (bv : in bit_vector;
|
||||
shift_count : in natural) return bit_vector is
|
||||
|
||||
constant bv_length : natural := bv'length;
|
||||
constant actual_shift_count : natural := shift_count mod bv_length;
|
||||
alias bv_norm : bit_vector(1 to bv_length) is bv;
|
||||
variable result : bit_vector(1 to bv_length) := (others => '0');
|
||||
|
||||
begin
|
||||
result(actual_shift_count + 1 to bv_length)
|
||||
:= bv_norm(1 to bv_length - actual_shift_count);
|
||||
return result;
|
||||
end bv_srl;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_sra
|
||||
--
|
||||
-- Shift right arithmetic (fill with copy of sign bit)
|
||||
----------------------------------------------------------------
|
||||
|
||||
|
||||
function bv_sra (bv : in bit_vector;
|
||||
shift_count : in natural) return bit_vector is
|
||||
|
||||
constant bv_length : natural := bv'length;
|
||||
constant actual_shift_count : natural := shift_count mod bv_length;
|
||||
alias bv_norm : bit_vector(1 to bv_length) is bv;
|
||||
variable result : bit_vector(1 to bv_length) := (others => bv(bv'left));
|
||||
|
||||
begin
|
||||
result(actual_shift_count + 1 to bv_length)
|
||||
:= bv_norm(1 to bv_length - actual_shift_count);
|
||||
return result;
|
||||
end bv_sra;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_rol
|
||||
--
|
||||
-- Rotate left
|
||||
----------------------------------------------------------------
|
||||
|
||||
function bv_rol (bv : in bit_vector;
|
||||
rotate_count : in natural) return bit_vector is
|
||||
|
||||
constant bv_length : natural := bv'length;
|
||||
constant actual_rotate_count : natural := rotate_count mod bv_length;
|
||||
alias bv_norm : bit_vector(1 to bv_length) is bv;
|
||||
variable result : bit_vector(1 to bv_length);
|
||||
|
||||
begin
|
||||
result(1 to bv_length - actual_rotate_count)
|
||||
:= bv_norm(actual_rotate_count + 1 to bv_length);
|
||||
result(bv_length - actual_rotate_count + 1 to bv_length)
|
||||
:= bv_norm(1 to actual_rotate_count);
|
||||
return result;
|
||||
end bv_rol;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_ror
|
||||
--
|
||||
-- Rotate right
|
||||
----------------------------------------------------------------
|
||||
|
||||
function bv_ror (bv : in bit_vector;
|
||||
rotate_count : in natural) return bit_vector is
|
||||
|
||||
constant bv_length : natural := bv'length;
|
||||
constant actual_rotate_count : natural := rotate_count mod bv_length;
|
||||
alias bv_norm : bit_vector(1 to bv_length) is bv;
|
||||
variable result : bit_vector(1 to bv_length);
|
||||
|
||||
begin
|
||||
result(actual_rotate_count + 1 to bv_length)
|
||||
:= bv_norm(1 to bv_length - actual_rotate_count);
|
||||
result(1 to actual_rotate_count)
|
||||
:= bv_norm(bv_length - actual_rotate_count + 1 to bv_length);
|
||||
return result;
|
||||
end bv_ror;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- Arithmetic comparison operators.
|
||||
-- Perform comparisons on bit vector encoded signed integers.
|
||||
-- (For unsigned integers, built in lexical comparison does
|
||||
-- the required operation.)
|
||||
----------------------------------------------------------------
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_lt
|
||||
--
|
||||
-- Signed less than comparison
|
||||
----------------------------------------------------------------
|
||||
|
||||
function bv_lt (bv1, bv2 : in bit_vector) return boolean is
|
||||
|
||||
variable tmp1 : bit_vector(bv1'range) := bv1;
|
||||
variable tmp2 : bit_vector(bv2'range) := bv2;
|
||||
|
||||
begin
|
||||
assert bv1'length = bv2'length
|
||||
report "bv_lt: operands of different lengths"
|
||||
severity failure;
|
||||
tmp1(tmp1'left) := not tmp1(tmp1'left);
|
||||
tmp2(tmp2'left) := not tmp2(tmp2'left);
|
||||
return tmp1 < tmp2;
|
||||
end bv_lt;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_le
|
||||
--
|
||||
-- Signed less than or equal comparison
|
||||
----------------------------------------------------------------
|
||||
|
||||
function bv_le (bv1, bv2 : in bit_vector) return boolean is
|
||||
|
||||
variable tmp1 : bit_vector(bv1'range) := bv1;
|
||||
variable tmp2 : bit_vector(bv2'range) := bv2;
|
||||
|
||||
begin
|
||||
assert bv1'length = bv2'length
|
||||
report "bv_le: operands of different lengths"
|
||||
severity failure;
|
||||
tmp1(tmp1'left) := not tmp1(tmp1'left);
|
||||
tmp2(tmp2'left) := not tmp2(tmp2'left);
|
||||
return tmp1 <= tmp2;
|
||||
end bv_le;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_gt
|
||||
--
|
||||
-- Signed greater than comparison
|
||||
----------------------------------------------------------------
|
||||
|
||||
function bv_gt (bv1, bv2 : in bit_vector) return boolean is
|
||||
|
||||
variable tmp1 : bit_vector(bv1'range) := bv1;
|
||||
variable tmp2 : bit_vector(bv2'range) := bv2;
|
||||
|
||||
begin
|
||||
assert bv1'length = bv2'length
|
||||
report "bv_gt: operands of different lengths"
|
||||
severity failure;
|
||||
tmp1(tmp1'left) := not tmp1(tmp1'left);
|
||||
tmp2(tmp2'left) := not tmp2(tmp2'left);
|
||||
return tmp1 > tmp2;
|
||||
end bv_gt;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_ge
|
||||
--
|
||||
-- Signed greater than or equal comparison
|
||||
----------------------------------------------------------------
|
||||
|
||||
function bv_ge (bv1, bv2 : in bit_vector) return boolean is
|
||||
|
||||
variable tmp1 : bit_vector(bv1'range) := bv1;
|
||||
variable tmp2 : bit_vector(bv2'range) := bv2;
|
||||
|
||||
begin
|
||||
assert bv1'length = bv2'length
|
||||
report "bv_ged: operands of different lengths"
|
||||
severity failure;
|
||||
tmp1(tmp1'left) := not tmp1(tmp1'left);
|
||||
tmp2(tmp2'left) := not tmp2(tmp2'left);
|
||||
return tmp1 >= tmp2;
|
||||
end bv_ge;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- Extension operators - convert a bit vector to a longer one
|
||||
----------------------------------------------------------------
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_sext
|
||||
--
|
||||
-- Sign extension - replicate the sign bit of the operand into
|
||||
-- the most significant bits of the result. Length parameter
|
||||
-- determines size of result. If length < bv'length, result is
|
||||
-- rightmost length bits of bv.
|
||||
----------------------------------------------------------------
|
||||
|
||||
function bv_sext (bv : in bit_vector;
|
||||
length : in natural) return bit_vector is
|
||||
|
||||
alias bv_norm : bit_vector(1 to bv'length) is bv;
|
||||
variable result : bit_vector(1 to length) := (others => bv(bv'left));
|
||||
variable src_length : natural := bv'length;
|
||||
|
||||
begin
|
||||
if src_length > length then
|
||||
src_length := length;
|
||||
end if;
|
||||
result(length - src_length + 1 to length)
|
||||
:= bv_norm(bv'length - src_length + 1 to bv'length);
|
||||
return result;
|
||||
end bv_sext;
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- bv_zext
|
||||
--
|
||||
-- Zero extension - replicate zero bits into the most significant
|
||||
-- bits of the result. Length parameter determines size of result.
|
||||
-- If length < bv'length, result is rightmost length bits of bv.
|
||||
----------------------------------------------------------------
|
||||
|
||||
function bv_zext (bv : in bit_vector;
|
||||
length : in natural) return bit_vector is
|
||||
|
||||
alias bv_norm : bit_vector(1 to bv'length) is bv;
|
||||
variable result : bit_vector(1 to length) := (others => '0');
|
||||
variable src_length : natural := bv'length;
|
||||
|
||||
begin
|
||||
if src_length > length then
|
||||
src_length := length;
|
||||
end if;
|
||||
result(length - src_length + 1 to length)
|
||||
:= bv_norm(bv'length - src_length + 1 to bv'length);
|
||||
return result;
|
||||
end bv_zext;
|
||||
|
||||
|
||||
end bv_arithmetic;
|
||||
Reference in New Issue
Block a user