Files
vhdl/projects/dlx/src/bv_arithmetic-body.vhdl
T
jens bdb8fec295 - added
git-svn-id: http://moon:8086/svn/vhdl/trunk@1424 cc03376c-175c-47c8-b038-4cd826a8556b
2021-03-21 11:37:55 +00:00

983 lines
32 KiB
VHDL

--------------------------------------------------------------------------
--
-- 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;