-- $Source: /evtfs/home/tres/vhdl/play/RCS/min_vec_len.vhd,v $
-- Revision  : $Revision: 1.7 $
-- Vector length functions
-- Mike Treseler Sun Jul 30 14:59:23 2006

-- run assertions: vsim -c min_vec_len -do run
-------------------------------------------------------------------------------
library ieee;
use ieee.STD_LOGIC_1164.all;
use ieee.numeric_std.all;

package vec_functions is
   function vec_image(arg   : std_logic_vector) return string;
   function vec_image(arg   : unsigned) return string;
   function vec_image(arg   : signed) return string;
   function min_len_uns(arg : natural) return natural;
   function power2(arg      : unsigned) return boolean;
   function min_len_sgn(arg : integer) return natural;
   function nat2uns (arg  : natural) return unsigned;
   function int2sgn (arg  : integer) return signed;
end package vec_functions;

package body vec_functions is
-------------------------------------------------------------------------------
   function vec_image(arg : std_logic_vector) return string is
-- recursive function call turns ('1','0','1') into "101"
-------------------------------------------------------------------------------
      constant arg_norm        : std_logic_vector(1 to arg'length) := arg;
      constant center          : natural := 2;     --  123
      variable bit_image       : string(1 to 3);   --  '0'
      variable just_the_number : character;
   begin
      if (arg'length > 0) then
         bit_image       := std_logic'image(arg_norm(1));   -- 3 chars: '0'
         just_the_number := bit_image(center);              -- 1 char    0
         return just_the_number                          -- first digit
            & vec_image(arg_norm(2 to arg_norm'length)); -- rest the same way
      else
         return ""; -- until "the rest" is nothing
      end if;
   end function vec_image;
-------------------------------------------------------------------------------
   function vec_image(arg : unsigned) return string is
   begin  -- overloaded for unsigned
      return vec_image(std_logic_vector(arg));
   end function vec_image;
-------------------------------------------------------------------------------
   function vec_image(arg : signed) return string is
   begin  -- overloaded for signed
      return vec_image(std_logic_vector(arg));
   end function vec_image;
-------------------------------------------------------------------------------
   function min_len_uns(arg : natural) return natural is
   begin
      case arg is
         when 1 | 0 =>
            return 1;
         when others =>
            return 1 + min_len_uns(arg/2);
      end case;
   end;
-------------------------------------------------------------------------------
   function power2(arg : unsigned) return boolean is
      variable bit_cnt_v : natural;
   begin
      bit_cnt_v := 0;
      scan : for i in arg'range loop
         if arg(i) = '1' then
            got_one: bit_cnt_v := bit_cnt_v + 1;
         end if;
      end loop scan;
      just_one: return(bit_cnt_v = 1);
   end function power2;
-------------------------------------------------------------------------------
   function min_len_sgn(arg : integer) return natural is
      constant min_c : natural := min_len_uns(abs(arg));
   begin
      case arg is
         when -1 | 0 =>
            return 1;
         when others =>
            if arg < -1 and power2(to_unsigned(-arg, min_c)) then
               -- case of ..., -8, -4, -2
               return min_c;
            else
               return min_c +1;
               -- case of ... -9, -7, -6, -5, -3, 1, 2, 3, ...
            end if;
      end case;
   end;
-------------------------------------------------------------------------------
   function nat2uns (arg : natural) return unsigned is
      constant min_c : natural    := min_len_uns(arg);
      subtype  this_uns_t is unsigned(min_c -1 downto 0);
      constant ret_c : this_uns_t := to_unsigned(arg, min_c);
   begin
      return ret_c;
   end function nat2uns;
-------------------------------------------------------------------------------
   function int2sgn (arg : integer) return signed is
      subtype  vec_t is signed(127 downto 0);  -- eliminates tuncation warning
      variable arg_v : vec_t   := to_signed(arg, vec_t'length);
      constant min_c : natural := min_len_sgn(arg);
      subtype  this_sgn_t is signed(min_c -1 downto 0);
   begin
      return arg_v(this_sgn_t'range);
   end function int2sgn;
-------------------------------------------------------------------------------
end package body vec_functions;



-------------------------------------------------------------------------------
-- Verification of vec_functions:
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.vec_functions.all;
-------------------------------------------------------------------------------
entity min_vec_len is
end entity min_vec_len;
-------------------------------------------------------------------------------
architecture sim of min_vec_len is
begin  -- architecture sim
   verify : process is
   begin
      -- debug_example:report vec_image(int2sgn(-8));

      assert vec_image(nat2uns(0))   =     "0"   report "fix uns 0";
      assert vec_image(nat2uns(1))   =     "1"   report "fix uns 1";
      assert vec_image(nat2uns(4))   =   "100"   report "fix uns 4";
      assert vec_image(nat2uns(5))   =   "101"   report "fix uns 5";      
      assert vec_image(nat2uns(15))  =  "1111"   report "fix uns 15";
      assert vec_image(nat2uns(16))  = "10000"   report "fix uns 16";
      
      assert vec_image(int2sgn(-16)) = "10000"   report "fix sgn -16";
      assert vec_image(int2sgn(-15)) = "10001"   report "fix sgn -15";
      assert vec_image(int2sgn(-8))  =  "1000"   report "fix sgn -8";
      assert vec_image(int2sgn(-3))  =   "101"   report "fix sgn -3";
      assert vec_image(int2sgn(-2))  =    "10"   report "fix sgn -2";
      assert vec_image(int2sgn(-1))  =     "1"   report "fix sgn -1";
      assert vec_image(int2sgn(-0))  =     "0"   report "fix sgn -0";
      assert vec_image(int2sgn(0))   =     "0"   report "fix sgn 0";
      assert vec_image(int2sgn(1))   =     "01"  report "fix sgn 1";

      report "assertion tests are complete";
      wait;

   end process verify;
end architecture sim;

-- example session:
-- > vsim -c min_vec_len -do run

--Reading /flip/usr1/modeltech/tcl/vsim/pref.tcl
--# 6.2a
--# Loading /flip/usr1/modeltech/linux/../std.standard
--# Loading /flip/usr1/modeltech/linux/../ieee.std_logic_1164(body)
--# Loading /flip/usr1/modeltech/linux/../ieee.numeric_std(body)
--# Loading work.min_vec_len(sim)
--# run 1
--# ** Note: assertions tests are complete
--#    Time: 0 ns  Iteration: 0  Instance: /min_vec_len