-------------------------------------------------------------------------------- --! @file --! @brief A bunch of useful functions for (non)synthesizable VHDL -------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.math_real.all; library std; use std.textio.all; package er_pack is -- constants used inside function 'rt' constant simres : time := 1 ps; -- simulation resolution (time) constant resreal : real := 1.0e-12; -- simulation resolution (real) ---------------------------------------------------------------------------- -- Types, Subtypes, and constants ---------------------------------------------------------------------------- type integer_vector is array (integer range <>) of integer; type natural_vector is array (integer range <>) of natural; type real_vector is array (integer range <>) of real; ---------------------------------------------------------------------------- ---------------------------------------------------------------------------- -- synthesis off function print_nibble(arg : std_logic_vector(3 downto 0)) return character; function print_message(arg : string) return boolean; -- synthesis on ---------------------------------------------------------------------------- -- print function ---------------------------------------------------------------------------- -- synthesis off function slv2string (arg : in std_logic_vector) return string; -- synthesis on ---------------------------------------------------------------------------- --! Return a vector of all ones. --! @param arg The number of bits in the output vector. --! @returns A vector of all ones. ---------------------------------------------------------------------------- function ones (arg : natural) return std_logic_vector; ---------------------------------------------------------------------------- --! Return a vector of all zeros. --! @param arg The number of bits in the output vector. --! @returns A vector of all zeros. ---------------------------------------------------------------------------- function zeros(arg : natural) return std_logic_vector; ---------------------------------------------------------------------------- --! Return the maximum (max positive) 2's complement value that can be --! expressed in the given number of bits. This is defined as {0,1,...,1}. --! @param arg The number of bits in the output vector. --! @returns The maximum 2's complement value. ---------------------------------------------------------------------------- function max (arg : natural) return std_logic_vector; ---------------------------------------------------------------------------- --! Return the minimum (max negative) 2's complement value that can be --! expressed in the given number of bits. This is defined as {1,0,...,0}. --! @param arg The number of bits in the output vector. --! @returns The minimum 2's complement value. ---------------------------------------------------------------------------- function min (arg : natural) return std_logic_vector; ---------------------------------------------------------------------------- --! Return the maximum value of two input values. --! @param a The first input value --! @param b The second input value --! @returns The maximum value of a and b ---------------------------------------------------------------------------- function max(a:natural; b:natural) return natural; ---------------------------------------------------------------------------- --! Return the minimum value of two input values. --! @param a The first input value --! @param b The second input value --! @returns The minimum value of a and b ---------------------------------------------------------------------------- function min(a:natural; b:natural) return natural; ---------------------------------------------------------------------------- --! Return the next multiple of the given variable --! @param arg The input value --! @param mult The multiple --! @returns arg rounded up to the next multiple of mult ---------------------------------------------------------------------------- function next_multiple (arg : natural; mult : natural) return natural; ---------------------------------------------------------------------------- --! Log function --! This might be the single most useful function in all of VHDL. It simply --! returns the log of a value --! @param base The base to use for the log. --! @param arg The value to log. --! @returns The log (arg) ---------------------------------------------------------------------------- function log (base : positive; arg : positive) return natural; ---------------------------------------------------------------------------- --! Log2 function --! This might be the single most useful function in all of VHDL. It simply --! returns the log2 of a value --! @param arg The value to log. --! @returns The log2 (arg) ---------------------------------------------------------------------------- function log2 (arg : positive) return natural; ---------------------------------------------------------------------------- --! Number of Bits function --! Return the number of bits necessary to hold a particular values. This --! is the log2 function rounded up --! @param arg The value to store --! @returns The number of bits necessary to hold arg ---------------------------------------------------------------------------- function num_bits (arg : positive) return natural; ---------------------------------------------------------------------------- --! delay via register --! This function should take place in a clocked process, but is an easy --! way to delay a signal --! @param reg The shift register that is doing the delaying --! @param sig The signal that is being delayed. This is put in the low --! address of the signal. --! @returns This will return the shifted (delayed) vector ---------------------------------------------------------------------------- function delay ( reg : natural_vector; sig : natural) return natural_vector; ---------------------------------------------------------------------------- --! delay via register --! This function should take place in a clocked process, but is an easy --! way to delay a signal --! @param reg The shift register that is doing the delaying --! @param sig The signal that is being delayed. This is put in the low --! address of the signal. --! @returns This will return the shifted (delayed) vector ---------------------------------------------------------------------------- function delay ( reg : integer_vector; sig : integer) return integer_vector; ---------------------------------------------------------------------------- --! delay via register --! This function should take place in a clocked process, but is an easy --! way to delay a signal --! @param reg The shift register that is doing the delaying --! @param sig The signal that is being delayed. This is put in the low --! address of the signal. --! @returns This will return the shifted (delayed) vector ---------------------------------------------------------------------------- function delay ( reg : std_logic_vector; sig : std_logic) return std_logic_vector; ---------------------------------------------------------------------------- --! Return a std_logic that is the result of a rising edge detector. There --! will need to be an input register with at least two values in it, since --! different indexes are used to derive the output. --! @param reg The input shift/Delay register --! @param idx (Optional) The index of the input reg register to start the --! the detection. The default value is the highest most index. --! @return not reg(idx) and reg(idx-1); ---------------------------------------------------------------------------- function rising_edge (reg : std_logic_vector; idx : integer) return std_logic; function rising_edge (reg : std_logic_vector) return std_logic; ---------------------------------------------------------------------------- --! Return a std_logic that is the result of a falling edge detector. There --! will need to be an input register with at least two values in it, since --! different indexes are used to derive the output. --! @param reg The input shift/Delay register --! @param idx (Optional) The index of the input reg register to start the --! the detection. The default value is the highest most index. --! @return reg(idx) and not reg(idx-1); ---------------------------------------------------------------------------- function falling_edge (reg : std_logic_vector; idx : integer) return std_logic; function falling_edge (reg : std_logic_vector) return std_logic; ---------------------------------------------------------------------------- --! Return a std_logic that is the result of an edge detector. There will --! need to be an input register with at least two values in it, since --! different indexes are used to derive the output. --! @param reg The input shift/Delay register --! @param idx (Optional) The index of the input reg register to start the --! the detection. The default value is the highest most index. --! @return reg(idx) xor reg(idx-1); ---------------------------------------------------------------------------- function edge (reg : std_logic_vector) return std_logic; function edge (reg : std_logic_vector; idx : integer) return std_logic; ---------------------------------------------------------------------------- --! Flip a register. This will put the high bits in the low positions, --! producing a mirror image of the bits. It will preserve the range of the --! input vector. --! @param ret The input register. --! @return The flipped version of the input register. ---------------------------------------------------------------------------- function flip (reg : std_logic_vector) return std_logic_vector; ---------------------------------------------------------------------------- --! Convert a real number to a std_logic_vector with a given number of bits. --! The input real should be a value between 1.0 and -1.0. Any value --! outside of this range will saturate the output vector. --! @param l The real number --! @param b The number of bits for the std_logic_vector ---------------------------------------------------------------------------- function to_slv(l:real; b:natural) return std_logic_vector; ---------------------------------------------------------------------------- -- Convert a time to a real representation for the number of seconds -- @param t The time to convert -- @return The real time (in seconds) ---------------------------------------------------------------------------- function rt(t : time) return real; ---------------------------------------------------------------------------- --! Divide two times. Return a real --! @param l The numerator --! @param r The denominator --! @returns The result of the divide in a real number ---------------------------------------------------------------------------- function "/" (l, r : time) return real; ---------------------------------------------------------------------------- --! Priority decoder --! Return the lowest index that is set high. --! @param reg the register to decode --! @returns The index of the highest bit set. If the whole register is --! zero, then it returns an out-of-bound integer ---------------------------------------------------------------------------- function priority_decode(reg : std_logic_vector) return integer; ---------------------------------------------------------------------------- --! Saturate an unsigned value to the given number of bits. --! @param val The unsigned value --! @param bits The number of bits --! @returns If the input value is greater than the requested number of bits --! can hold, it will return 2^bits-1. All other cases will return the --! original number. ---------------------------------------------------------------------------- function saturate(val : unsigned; bits : natural) return unsigned; function usat(val : std_logic_vector; bits : natural ) return std_logic_vector; ---------------------------------------------------------------------------- --! Saturate a signed value to the given number of bits. --! @param val The signed value --! @param bits The number of bits --! @returns If the absolute value of the input value is greater than --! 2^(bits-1)-1, then return the appriate signed version of 2^(bits-1)-1. --! All other cases will return the original number. ---------------------------------------------------------------------------- function saturate(val : signed; bits : natural) return signed; function ssat(val : std_logic_vector; bits : natural ) return std_logic_vector; ---------------------------------------------------------------------------- --! numeric_std helper functions --! (un)signed shift left/right ---------------------------------------------------------------------------- --! unsigned shift left function usl (val : std_logic_vector; bits : natural) return std_logic_vector; --! unsigned shift right function usr (val : std_logic_vector; bits : natural) return std_logic_vector; --! signed shift left function ssl (val : std_logic_vector; bits : natural) return std_logic_vector; --! signed shift right function ssr (val : std_logic_vector; bits : natural) return std_logic_vector; end package er_pack; -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -- Package body -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- package body er_pack is ---------------------------------------------------------------------------- -- synthesis off function print_nibble(arg : std_logic_vector(3 downto 0)) return character is variable ret : character; variable num : natural; -- status variables variable is_x : boolean; variable is_u : boolean; variable is_dash : boolean; variable is_z : boolean; variable is_w : boolean; begin for idx in arg'range loop -- take care of the special cases case arg(idx) is when 'X' => is_x := true; when 'U' => is_u := true; when '-' => is_dash := true; when 'Z' => is_z := true; when 'W' => is_w := true; when others => NULL; end case; end loop; -- Print it if is_x then ret := 'X'; elsif is_u then ret := 'U'; elsif is_dash then ret := '-'; elsif is_z then ret := 'Z'; elsif is_w then ret := 'W'; else num := to_integer(unsigned(arg)); case num is when 15 => ret := 'F'; when 14 => ret := 'E'; when 13 => ret := 'D'; when 12 => ret := 'C'; when 11 => ret := 'B'; when 10 => ret := 'A'; when 9 => ret := '9'; when 8 => ret := '8'; when 7 => ret := '7'; when 6 => ret := '6'; when 5 => ret := '5'; when 4 => ret := '4'; when 3 => ret := '3'; when 2 => ret := '2'; when 1 => ret := '1'; when 0 => ret := '0'; when others => ret := 'J'; end case; end if; -- we're done return ret; end function print_nibble; --! Just print a string. It's not hard, but it takes more than one line --! without the function function print_message(arg : string) return boolean is variable out_line : line; begin write(out_line, arg); writeline(output, out_line); return true; end function print_message; -- print function function slv2string (arg : in std_logic_vector) return string is variable ret : string (1 to arg'length/4+1); variable jdx : integer; variable tmp_nibble : std_logic_vector(3 downto 0); variable kdx : natural := 1; begin -- Try to get a useful hex value jdx := 0; kdx := ret'high; for idx in arg'reverse_range loop -- fill the next value of the nibble tmp_nibble(jdx) := arg(idx); -- correct jdx and print accordingly if jdx = 3 then -- reset the jdx value jdx := 0; ret(kdx) := print_nibble(tmp_nibble); -- correct kdx kdx := kdx - 1; else -- decrement jdx jdx := jdx + 1; end if; end loop; -- edge cases if jdx /= 0 then tmp_nibble(3 downto jdx) := (others => '0'); ret(kdx) := print_nibble(tmp_nibble); return ret; end if; -- if we got here, then we have an exact number of nibbles. Give back -- all but one character. return ret(2 to ret'high); end function slv2string; -- synthesis on ---------------------------------------------------------------------------- function ones (arg : natural) return std_logic_vector is variable ret : std_logic_vector(arg-1 downto 0) := (others => '1'); begin return ret; end function ones; ---------------------------------------------------------------------------- function zeros(arg : natural) return std_logic_vector is variable ret : std_logic_vector(arg-1 downto 0) := (others => '0'); begin return ret; end function zeros; ---------------------------------------------------------------------------- function max (arg : natural) return std_logic_vector is variable ret : std_logic_vector(arg-1 downto 0) := '0' & ones(arg-1); begin return ret; end function max; ---------------------------------------------------------------------------- function min (arg : natural) return std_logic_vector is variable ret : std_logic_vector(arg-1 downto 0) := '1' & zeros(arg-1); begin return ret; end function min; ---------------------------------------------------------------------------- function max(a:natural; b:natural) return natural is begin if a > b then return a; end if; return b; end function max; ---------------------------------------------------------------------------- function min(a:natural; b:natural) return natural is begin if a < b then return a; end if; return b; end function min; ---------------------------------------------------------------------------- function next_multiple (arg : natural; mult : natural) return natural is begin return (arg / mult) * mult; end function next_multiple; ---------------------------------------------------------------------------- function log (base : positive; arg : positive) return natural is variable div : positive := arg; variable ret : natural := 0; begin while div > 1 loop div := div / base; ret := ret + 1; end loop; return ret; end function log; ---------------------------------------------------------------------------- function log2 (arg : positive) return natural is begin return log(2, arg); end function log2; ---------------------------------------------------------------------------- function num_bits (arg : positive) return natural is variable ret : natural := log2(arg); begin if 2**ret /= arg then ret := ret + 1; end if; return ret; end function num_bits; ---------------------------------------------------------------------------- function delay ( reg : integer_vector; sig : integer) return integer_vector is variable ret : integer_vector(reg'range); begin if ret'ascending then ret := sig & reg(reg'low to reg'high-1); else ret := reg(reg'high-1 downto reg'low) & sig; end if; return ret; end function; function delay ( reg : natural_vector; sig : natural) return natural_vector is variable ret : natural_vector(reg'range); begin if ret'ascending then ret := sig & reg(reg'low to reg'high-1); else ret := reg(reg'high-1 downto reg'low) & sig; end if; return ret; end function; function delay ( reg : std_logic_vector; sig : std_logic) return std_logic_vector is variable ret : std_logic_vector(reg'range); begin if ret'ascending then ret := sig & reg(reg'low to reg'high-1); else ret := reg(reg'high-1 downto reg'low) & sig; end if; return ret; end function; ---------------------------------------------------------------------------- function rising_edge ( reg : std_logic_vector) return std_logic is variable idx : integer := reg'high; begin return rising_edge(reg, idx); end function; ---------------------------------------------------------------------------- function rising_edge ( reg : std_logic_vector; idx : integer) return std_logic is begin -- Check the input for validity assert reg'length >= 2 report "input vector not long enough" severity error; assert idx <= reg'high and idx > reg'low report "input vector not long enough" severity error; -- now just return the answer return not reg(idx) and reg(idx-1); end function; ---------------------------------------------------------------------------- function falling_edge ( reg : std_logic_vector) return std_logic is variable idx : integer := reg'high; begin return falling_edge(reg, idx); end function falling_edge; ---------------------------------------------------------------------------- function falling_edge ( reg : std_logic_vector; idx : integer) return std_logic is begin -- Check the input for validity assert reg'length >= 2 report "input vector not long enough" severity error; assert idx <= reg'high and idx > reg'low report "input vector not long enough" severity error; -- now just return the answer return reg(idx) and not reg(idx-1); end function falling_edge; ---------------------------------------------------------------------------- function edge ( reg : std_logic_vector) return std_logic is variable idx : integer := reg'high; begin return edge(reg, idx); end function edge; ---------------------------------------------------------------------------- function edge ( reg : std_logic_vector; idx : integer) return std_logic is begin -- Check the input for validity assert reg'length >= 2 report "input vector not long enough" severity error; assert idx <= reg'high and idx > reg'low report "input vector not long enough" severity error; -- now just return the answer return reg(idx) xor reg(idx-1); end function edge; ---------------------------------------------------------------------------- function flip (reg : std_logic_vector) return std_logic_vector is variable ret : std_logic_vector(reg'range); variable idx : integer := reg'high; variable jdx : integer := reg'low; begin while jdx < idx loop -- Populate ret with the reg bits backwards ret(idx) := reg(jdx); ret(jdx) := reg(idx); -- update the counters idx := idx + 1; jdx := jdx + 1; end loop; -- return the flipped register return ret; end function flip; ---------------------------------------------------------------------------- function to_slv(l:real; b:natural) return std_logic_vector is variable slv : std_logic_vector(b-1 downto 0); variable temp_r : real; variable temp_i : integer; begin -- Check the bounds and saturate when necessary if l <= -1.0 then slv := min(b); elsif l >= 1.0 then slv := max(b); else -- Compute the answer temp_r := l * real(2**(b-1)-1); -- Scale the real to not overflow temp_i := integer(round(temp_r)); -- round it and turn it into an integer slv := std_logic_vector(to_signed(temp_i, b)); -- Turn it to an slv end if; -- Now just return it return slv; end function to_slv; ---------------------------------------------------------------------------- function rt(t : time) return real is variable nat_time : natural := t / simres; variable real_time : real := real(nat_time); begin return real_time * resreal; end; ---------------------------------------------------------------------------- function "/" (l, r : time) return real is variable real_l : real := rt(l); variable real_r : real := rt(r); begin return real_l / real_r; end function "/"; ---------------------------------------------------------------------------- function priority_decode(reg : std_logic_vector) return integer is variable ret : integer; begin -- Start with the default value if reg'ascending then ret := reg'right + 1; else ret := reg'right - 1; end if; -- now determine which one is lit for idx in reg'reverse_range loop if reg(idx) = '1' then ret := idx; end if; end loop; -- return it return ret; end function priority_decode; ---------------------------------------------------------------------------- function saturate(val : unsigned; bits : natural) return unsigned is variable max_val : unsigned(bits-1 downto 0) := unsigned(ones(bits)); begin -- Check the value over the max if val > max_val then return resize(max_val, val'length); end if; -- If we got here, we just return the value return val; end function saturate; -- The std_logic_vector version function usat(val : std_logic_vector; bits : natural ) return std_logic_vector is begin return std_logic_vector(saturate(unsigned(val), bits)); end function usat; ---------------------------------------------------------------------------- function saturate(val : signed; bits : natural) return signed is variable max_val : signed(bits-1 downto 0) := '0' & signed(ones (bits-2)) & '1'; variable min_val : signed(bits-1 downto 0) := '1' & signed(zeros(bits-2)) & '1'; begin -- Check the value over the max if val > max_val then return resize(max_val, val'length); elsif val < min_val then return resize(min_val, val'length); end if; -- If we got here, we just return the value return val; end function saturate; -- The std_logic_vector version function ssat(val : std_logic_vector; bits : natural ) return std_logic_vector is begin return std_logic_vector(saturate(signed(val), bits)); end function ssat; ---------------------------------------------------------------------------- -- numeric_std helper functions ---------------------------------------------------------------------------- function usl (val : std_logic_vector; bits : natural) return std_logic_vector is begin return std_logic_vector(shift_left(unsigned(val), bits)); end function usl; function usr (val : std_logic_vector; bits : natural) return std_logic_vector is begin return std_logic_vector(shift_right(unsigned(val), bits)); end function usr; function ssl (val : std_logic_vector; bits : natural) return std_logic_vector is begin return std_logic_vector(shift_left(signed(val), bits)); end function ssl; function ssr (val : std_logic_vector; bits : natural) return std_logic_vector is begin return std_logic_vector(shift_right(signed(val), bits)); end function ssr; end package body;