----------------------------------------------------------------------------
--					
-- Copyright (c) 1990, 1991, 1992 by Synopsys, Inc.  All rights reserved.
-- 
-- This source file may be used and distributed without restriction 
-- provided that this copyright statement is not removed from the file 
-- and that any derivative work contains this copyright notice.
--
--	Package name: BV_ARITHMETIC
--
--	Purpose: 
--	 A set of functions for conversions from BIT_VECTOR to
--	 INTEGER and vice versa, as well as for arithmetic
--	 operations with bit vectors.
--
--	 This package is built in to the analyzer, so this source
--	 should not be analyzed on the Synopsys VHDL system for
--	 simulation.  It is provided for reference and portability 
--	 to other systems.
--
--								
----------------------------------------------------------------------------

package BV_ARITHMETIC is

    -- unsigned bit vector to integer
    -- discards all bits other than rightmost wordlength-1
    FUNCTION bvtoi(x: BIT_VECTOR) RETURN INTEGER;

    -- signed bit vector to integer
    -- discards all bits other than rightmost wordlength
    FUNCTION sbvtoi(x: BIT_VECTOR) RETURN INTEGER;

    -- integer to bit_vector conversion
    -- returns bit_vector(length-1 downto 0) if length >= 0, null range otherwise
    FUNCTION itobv(x: INTEGER; length: INTEGER) RETURN BIT_VECTOR;

    -- sign extend bit vector (x) to length, length < 0 is same as length = 0
    -- returns bit_vector(length-1 downto 0)
    FUNCTION sxt(x: BIT_VECTOR; length: INTEGER) RETURN BIT_VECTOR;

    -- zero extend bit vector (x) to length, length < 0 is same as length = 0
    -- returns bit_vector(length-1 downto 0)
    FUNCTION ext(x: BIT_VECTOR; length: INTEGER) RETURN BIT_VECTOR;

    -- add left + right bit vectors, sign extending the shorter one
    -- returns bit_vector(max(left'length,right'length)-1 downto 0)
    FUNCTION "+"(left: BIT_VECTOR; right: BIT_VECTOR) RETURN BIT_VECTOR;

    -- sub left - right bit vectors, sign extending the shorter one
    -- returns bit_vector(max(left'length,right'length)-1 downto 0)
    FUNCTION "-"(left: BIT_VECTOR; right: BIT_VECTOR) RETURN BIT_VECTOR;

    -- 2's complement (negative) of bit vector (right)
    -- returns bit_vector(right'length-1 downto 0)
    FUNCTION "-"(right: BIT_VECTOR) RETURN BIT_VECTOR;

    -- absolute value of bit vector (right)
    -- returns bit_vector(right'length-1 downto 0)
    FUNCTION "abs"(right: BIT_VECTOR) RETURN BIT_VECTOR;


end BV_ARITHMETIC;

package body BV_ARITHMETIC is


    type BVUNSIGNED is array (NATURAL range <>) of BIT;
    type BVSIGNED is array (NATURAL range <>) of BIT;

    FUNCTION "+"(L: BVSIGNED; R: BVSIGNED) return BVSIGNED;
    FUNCTION "-"(L: BVSIGNED; R: BVSIGNED) return BVSIGNED;
    FUNCTION "-"(L: INTEGER; R: BVSIGNED) return BVSIGNED;
    FUNCTION "ABS"(L: BVSIGNED) return BVSIGNED;

    FUNCTION C_INTEGER(ARG: BVUNSIGNED) return INTEGER;
    FUNCTION C_INTEGER(ARG: BVSIGNED) return INTEGER;
    FUNCTION C_UNSIGNED(ARG: BVUNSIGNED; SIZE: INTEGER) return BVUNSIGNED;
    FUNCTION C_SIGNED(ARG: INTEGER; SIZE: INTEGER) return BVSIGNED;
    FUNCTION C_SIGNED(ARG: BVSIGNED; SIZE: INTEGER) return BVSIGNED;


    -- word length(number of bits in an integer on this machine)
    constant wordlength: integer := 32;

    FUNCTION bvmax(L, R: INTEGER) return INTEGER is
    begin
	if L > R then
	    return L;
	else
	    return R;
	end if;
    end;


    FUNCTION bvmin(L, R: INTEGER) return INTEGER is
    begin
	if L < R then
	    return L;
	else
	    return R;
	end if;
    end;


    -- subtract two unsigned numbers of the same length
    -- both arrays must have range (msb downto 0)
    function unsigned_minus(A, B: BVUNSIGNED) return BVUNSIGNED is
	variable carry: BIT;
	variable BV: BIT_VECTOR (A'left downto 0);
	variable sum: BVUNSIGNED (A'left downto 0);

	-- pragma map_to_operator SUB_UNS_OP
	-- pragma type_function LEFT_UNSIGNED_ARG
        -- pragma return_port_name Z

    begin
	carry := '1';
	BV := not BIT_VECTOR(B);

	for i in 0 to A'left loop
	    sum(i) := A(i) xor BV(i) xor carry;
	    carry := (A(i) and BV(i)) or
		    (A(i) and carry) or
		    (carry and BV(i));
	end loop;
	return sum;
    end;


    -- add two unsigned numbers of the same length
    -- both arrays must have range (msb downto 0)
    function unsigned_plus(A, B: BVUNSIGNED) return BVUNSIGNED is
	variable carry: BIT;
	variable BV, sum: BVUNSIGNED (A'left downto 0);

	-- pragma map_to_operator ADD_UNS_OP
	-- pragma type_function LEFT_UNSIGNED_ARG
        -- pragma return_port_name Z

    begin
	carry := '0';
	BV := B;

	for i in 0 to A'left loop
	    sum(i) := A(i) xor BV(i) xor carry;
	    carry := (A(i) and BV(i)) or
		    (A(i) and carry) or
		    (carry and BV(i));
	end loop;
	return sum;
    end;


    -- Type propagation FUNCTION which returns a signed type with the
    -- size of the left arg.
    FUNCTION LEFT_SIGNED_ARG(A,B: BVSIGNED) return BVSIGNED is
      variable Z: BVSIGNED (A'left downto 0);
      -- pragma return_port_name Z
    begin
      return(Z);
    end;
	
    -- subtract two signed numbers of the same length
    -- both arrays must have range (msb downto 0)
    FUNCTION minus(A, B: BVSIGNED) return BVSIGNED is
	variable carry: BIT;
	variable BV: BIT_VECTOR (A'left downto 0);
	variable sum: BVSIGNED (A'left downto 0);

	-- pragma map_to_operator SUB_TC_OP

	-- pragma type_FUNCTION LEFT_SIGNED_ARG
        -- pragma return_port_name Z

    begin
	carry := '1';
	BV := not BIT_VECTOR(B);

	for i in 0 to A'left loop
	    sum(i) := A(i) xor BV(i) xor carry;
	    carry := (A(i) and BV(i)) or
		    (A(i) and carry) or
		    (carry and BV(i));
	end loop;
	return sum;
    end;

    -- add two signed numbers of the same length
    -- both arrays must have range (msb downto 0)
    FUNCTION plus(A, B: BVSIGNED) return BVSIGNED is
	variable carry: BIT;
	variable BV, sum: BVSIGNED (A'left downto 0);

	-- pragma map_to_operator ADD_TC_OP
	-- pragma type_FUNCTION LEFT_SIGNED_ARG
        -- pragma return_port_name Z

    begin
	carry := '0';
	BV := B;

	for i in 0 to A'left loop
	    sum(i) := A(i) xor BV(i) xor carry;
	    carry := (A(i) and BV(i)) or
		    (A(i) and carry) or
		    (carry and BV(i));
	end loop;
	return sum;
    end;


    FUNCTION "+"(L: BVSIGNED; R: BVSIGNED) return BVSIGNED is
	-- pragma label_applies_to plus
	constant length: INTEGER := bvmax(L'length, R'length);
    begin
	return plus(C_SIGNED(L, length),
		    C_SIGNED(R, length)); -- pragma label plus
    end;


    FUNCTION "-"(L: BVSIGNED; R: BVSIGNED) return BVSIGNED is
	-- pragma label_applies_to minus
	constant length: INTEGER := bvmax(L'length, R'length);
    begin
	return minus(C_SIGNED(L, length),
		     C_SIGNED(R, length)); -- pragma label minus
    end;


    FUNCTION "-"(L: INTEGER; R: BVSIGNED) return BVSIGNED is
	-- pragma label_applies_to minus
	constant length: INTEGER := R'length;
    begin
	return minus(C_SIGNED(L, length),
		     C_SIGNED(R, length)); -- pragma label minus
    end;


    FUNCTION "ABS"(L: BVSIGNED) return BVSIGNED is
    begin
	if L(L'left) = '0' then
	    return L;
	else
	    return 0 - L;
	end if;
    end;



    FUNCTION C_INTEGER(ARG: BVSIGNED) return INTEGER is
	variable result: INTEGER;
	-- synopsys built_in SYN_SIGNED_TO_INTEGER;
    begin
	-- synopsys synthesis_off
	assert ARG'length <= 32
	    report "ARG is too large in C_INTEGER"
	    severity FAILURE;
	result := 0;
	for i in ARG'range loop
	    if i /= ARG'left then
		result := result * 2;
		if ARG(i) = '1' then
		    result := result + 1;
		end if;
	    end if;
	end loop;
	if ARG(ARG'left) = '1' then
	    if ARG'length = 32 then
		result := (result - 2**30) - 2**30;
	    else
		result := result - (2 ** (ARG'length-1));
	    end if;
	end if;
	return result;
	-- synopsys synthesis_on
    end;


    FUNCTION C_INTEGER(ARG: BVUNSIGNED) return INTEGER is
	variable result: INTEGER;
	-- synopsys built_in SYN_UNSIGNED_TO_INTEGER;
    begin
	-- synopsys synthesis_off
	assert ARG'length <= 31
	    report "ARG is too large in C_INTEGER"
	    severity FAILURE;
	result := 0;
	for i in ARG'range loop
	    result := result * 2;
	    if ARG(i) = '1' then
		result := result + 1;
	    end if;
	end loop;
	return result;
	-- synopsys synthesis_on
    end;


    FUNCTION C_UNSIGNED(ARG: BVUNSIGNED; SIZE: INTEGER) return BVUNSIGNED is
	constant msb: INTEGER := bvmin(ARG'length, SIZE) - 1;
	subtype rtype is BVUNSIGNED (SIZE-1 downto 0);
	variable new_bounds: BVUNSIGNED (ARG'length-1 downto 0);
	variable result: rtype;
	-- synopsys built_in SYN_ZERO_EXTEND
    begin
	-- synopsys synthesis_off
	result := rtype'(others => '0');
	new_bounds := ARG;
	result(msb downto 0) := new_bounds(msb downto 0);
	return result;
	-- synopsys synthesis_on
    end;


    -- convert an integer to a 2's complement BIT_VECTOR
    FUNCTION C_SIGNED(ARG: INTEGER; SIZE: INTEGER) return BVSIGNED is
	variable result: BVSIGNED (SIZE-1 downto 0);
	variable temp: integer;
	variable negative: boolean;
	-- synopsys built_in SYN_INTEGER_TO_SIGNED
    begin
	-- synopsys synthesis_off
	temp := ARG;
	if temp < 0 then
	    -- In order to make the "/2" operation like a shift,
	    -- we need to make the arg a positive number.
	    temp := (temp + (2**30)) + (2**30);
	    negative := TRUE;
	else
	    negative := FALSE;
	end if;
	for i in  0 to SIZE-1 loop
	    if (temp mod 2) = 1 then
		result(i) := '1';
	    else 
		result(i) := '0';
	    end if;
	    temp := temp / 2;
	end loop;
	-- If we are converting a >31 bit number which is negative, 
	-- the high bits have been calculated incorrectly.
	if negative and (SIZE > 31) then
	    for i in 31 to SIZE-1 loop
		result(i) := '1';
	    end loop;
	end if;
	return result;
	-- synopsys synthesis_on
    end;


    FUNCTION C_SIGNED(ARG: BVSIGNED; SIZE: INTEGER) return BVSIGNED is
	constant msb: INTEGER := bvmin(ARG'length, SIZE) - 1;
	subtype rtype is BVSIGNED (SIZE-1 downto 0);
	variable new_bounds : BVSIGNED (ARG'length-1 downto 0);
	variable result: rtype;
	-- synopsys built_in SYN_SIGN_EXTEND
    begin
	-- synopsys synthesis_off
	result := rtype'(others => ARG(ARG'left));
	new_bounds := ARG;
	result(msb downto 0) := new_bounds(msb downto 0);
	return result;
	-- synopsys synthesis_on
    end;

--
--------
--
    FUNCTION bvtoi(x: BIT_VECTOR) RETURN INTEGER is
	begin
		return C_INTEGER(BVUNSIGNED(x));
	end;


    FUNCTION sbvtoi(x: BIT_VECTOR) RETURN INTEGER is
	begin
		return C_INTEGER(BVSIGNED(x));
	end;


    FUNCTION itobv(x: INTEGER;
                   length: INTEGER) RETURN BIT_VECTOR is
    	variable result: BIT_VECTOR(length-1 downto 0);
	begin
		result := BIT_VECTOR(C_SIGNED(x,length));
		return (result);
	end;


    FUNCTION sxt(x: BIT_VECTOR;
                 length: INTEGER) RETURN BIT_VECTOR is
    	variable result: BIT_VECTOR(length-1 downto 0);
	begin
		result := BIT_VECTOR(C_SIGNED(BVSIGNED(x),length));
		return (result);
	end;


    FUNCTION ext(x: BIT_VECTOR;
                 length: INTEGER) RETURN BIT_VECTOR is
    	variable result: BIT_VECTOR(length-1 downto 0);
	begin
		result := BIT_VECTOR(C_UNSIGNED(BVUNSIGNED(x),length));
		return (result);
	end;


    FUNCTION "+"(left: BIT_VECTOR;
                 right: BIT_VECTOR) RETURN BIT_VECTOR is
	begin
		return BIT_VECTOR(BVSIGNED(left) + BVSIGNED(right));
	end;


    FUNCTION "-"(left: BIT_VECTOR;
                 right: BIT_VECTOR) RETURN BIT_VECTOR is
	begin
		return BIT_VECTOR(BVSIGNED(left) - BVSIGNED(right));
	end;


    FUNCTION "-"(right: BIT_VECTOR) RETURN BIT_VECTOR is
	begin
		return BIT_VECTOR(0 - BVSIGNED(right));
	end;


    FUNCTION "abs"(right: BIT_VECTOR) RETURN BIT_VECTOR is
	begin
		return BIT_VECTOR(ABS(BVSIGNED(right)));
	end;

end BV_ARITHMETIC;

<div align="center"><br /><script type="text/javascript"><!--
google_ad_client = "pub-7293844627074885";
//468x60, Created at 07. 11. 25
google_ad_slot = "8619794253";
google_ad_width = 468;
google_ad_height = 60;
//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script><br />&nbsp;</div>