aboutsummaryrefslogtreecommitdiffstats
path: root/testsuite
diff options
context:
space:
mode:
authorTristan Gingold <tgingold@free.fr>2015-11-17 05:03:49 +0100
committerTristan Gingold <tgingold@free.fr>2015-11-17 05:03:49 +0100
commit0610623b10bab98ed4e71a8fae3a62ea823f228e (patch)
tree49d0236880e5cbf6428f384432c9e951329bc2b3 /testsuite
parent4a143e962ef51149408c24461599752203b4c415 (diff)
downloadghdl-0610623b10bab98ed4e71a8fae3a62ea823f228e.tar.gz
ghdl-0610623b10bab98ed4e71a8fae3a62ea823f228e.tar.bz2
ghdl-0610623b10bab98ed4e71a8fae3a62ea823f228e.zip
Add reproducer for bug24064
Diffstat (limited to 'testsuite')
-rw-r--r--testsuite/gna/bug24064/er_pack.vhd719
-rw-r--r--testsuite/gna/bug24064/pp_fir_filter.vhd352
-rwxr-xr-xtestsuite/gna/bug24064/testsuite.sh11
3 files changed, 1082 insertions, 0 deletions
diff --git a/testsuite/gna/bug24064/er_pack.vhd b/testsuite/gna/bug24064/er_pack.vhd
new file mode 100644
index 000000000..7871fc4df
--- /dev/null
+++ b/testsuite/gna/bug24064/er_pack.vhd
@@ -0,0 +1,719 @@
+--------------------------------------------------------------------------------
+--! @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;
+
+
diff --git a/testsuite/gna/bug24064/pp_fir_filter.vhd b/testsuite/gna/bug24064/pp_fir_filter.vhd
new file mode 100644
index 000000000..e7f204a26
--- /dev/null
+++ b/testsuite/gna/bug24064/pp_fir_filter.vhd
@@ -0,0 +1,352 @@
+--------------------------------------------------------------------------------
+--! @file
+--! @brief pp_fir_filter.
+--! This implements a poly-phase fir filter that can be used for
+--! rational resampling or rational sample delay.
+--! The taps of the FIR filter are generated at compile time and start
+--! as a Hann-windowed sinc function. 0-phase offset is then normalized
+--! to be 0.98 amplitude.
+--! The generics determine the resolution of the fir-filter, as well as
+--! as the number of phases.
+--------------------------------------------------------------------------------
+library ieee;
+ use ieee.std_logic_1164.all;
+ use ieee.numeric_std.all;
+ use ieee.math_real.all;
+library work;
+ use work.er_pack.all;
+
+entity pp_fir_filter is
+ generic (
+ --! The width of each tap in bits
+ taps_width_g : natural := 16;
+ --! The number of lobes. This is basically the number of taps per filter
+ num_lobes_g : natural := 8;
+ --! The number of parallel channels
+ num_channels_g : natural := 1;
+ --! The number of taps per lobe
+ taps_per_lobe_g : natural := 512;
+ --! The number of taps to skip to get to the next tap
+ step_size_g : natural := 512);
+ port (
+ -- standard ports
+ clk_i : in std_logic;
+ rst_i : in std_logic;
+
+ -- input data ports
+ --! Run the filter without taking another sample
+ run_i : in std_logic;
+ phase_i : in std_logic_vector(log2(taps_per_lobe_g) downto 0);
+ data_en_i : in std_logic;
+ data_i : in std_logic_vector(num_channels_g*taps_width_g-1 downto 0);
+
+ -- output data ports
+ data_o : out std_logic_vector(num_channels_g*taps_width_g-1 downto 0);
+ data_en_o : out std_logic);
+end entity pp_fir_filter;
+
+architecture behavior of pp_fir_filter is
+ ----------------------------------------------------------------------------
+ -- Types, Subtypes, and Constants
+ ----------------------------------------------------------------------------
+ subtype word_t is signed(1*taps_width_g-1 downto 0);
+ subtype dword_t is signed(2*taps_width_g-1 downto 0);
+ subtype save_range is natural range 2*taps_width_g-2 downto 1*taps_width_g-1;
+ type word_vector_t is array (integer range <>) of word_t;
+ type dword_vector_t is array (integer range <>) of dword_t;
+ type rom_t is array (integer range <>) of signed(data_i'range);
+
+ -- The state machine deals with the MACCs
+ type state_type is (
+ idle_state, -- Waiting for input signal
+ load_state, -- Load the sample into the input ram
+ mult_state, -- First multiply does not accumulate product
+ macc_state, -- P += A*B
+ save_state); -- Save the output
+ type dsp_opcode_type is (
+ clear, -- P = 0
+ mult, -- P = A*B
+ macc, -- P += A*B
+ hold); -- P = P
+ constant round_val : dword_t := shift_left(to_signed(1, dword_t'length), taps_width_g-2);
+
+ -- We want the phase offset to be in relation to the middle of the center
+ -- lobe. For this reason, we will need to determine the offset of the first
+ -- sample in relation to the step_size, taps_per_lobe, and the number of
+ -- lobes
+ constant phase_offset_c : natural :=
+-- (num_lobes_g * (taps_per_lobe_g - step_size_g+1)) mod taps_per_lobe_g;
+ (num_lobes_g/2 * (taps_per_lobe_g - step_size_g));
+ constant num_regs_c : natural :=
+-- (num_lobes_g * (taps_per_lobe_g / step_size_g));
+ (num_lobes_g);
+
+ ----------------------------------------------------------------------------
+ -- functions
+ ----------------------------------------------------------------------------
+ function load_sinc_rom (
+ taps_per_lobe : natural;
+ num_lobes : natural)
+ return word_vector_t is
+ -- The returned ram
+ variable rom : word_vector_t(0 to taps_per_lobe * num_lobes-1);
+
+ -- Stuff for the actual sinc calculation
+ variable real_rom : real_vector(rom'range);
+ variable half : real := real(rom'length/2);
+ variable nm1 : real := real(rom'length-1);
+ variable phase : real;
+ variable sinc : real;
+ variable hann : real;
+
+ -- for power calculation
+ variable power : real;
+ begin
+ ------------------------------------------------------------------------
+ -- Tap generation
+ ------------------------------------------------------------------------
+ for idx in real_rom'range loop
+ -- Determine the phase, but multiply it by PI to get the correct
+ -- phase shift
+ phase := math_pi * (real(idx) - half) / real(taps_per_lobe);
+
+ -- Don't divide by zero
+ if phase = 0.0 then
+ sinc := 1.0;
+ else
+ sinc := sin(phase) / phase;
+ end if;
+
+ -- Multiply it by a hann window
+ hann := 0.5 * (1.0 - cos(2.0*math_pi*real(idx)/nm1));
+
+ -- Put it in the rom
+ real_rom(idx) := sinc*hann;
+ end loop;
+
+ ------------------------------------------------------------------------
+ -- Energy measurement
+ ------------------------------------------------------------------------
+ -- Now that the ram is complete, we still need to make sure that we
+ -- scale everything to be a power of one. This is to make sure that we
+ -- don't overflow during the actual addition.
+ power := 0.0;
+ for idx in 0 to num_regs_c-1 loop
+ power := power + real_rom(phase_offset_c + idx*step_size_g);
+ end loop;
+
+ ------------------------------------------------------------------------
+ -- Normalization
+ ------------------------------------------------------------------------
+ -- Now put it in the actual ram
+ for idx in rom'range loop
+ real_rom(idx) := real_rom(idx) * (0.98 / power);
+ rom (idx) := signed(to_slv(real_rom(idx), word_t'length));
+ end loop;
+
+ -- return it
+ return rom;
+ end function load_sinc_rom;
+
+ -----------------------------------------------------------------------------
+ constant taps_rom : word_vector_t := load_sinc_rom(taps_per_lobe_g, num_lobes_g);
+
+ ----------------------------------------------------------------------------
+ -- Signals
+ ----------------------------------------------------------------------------
+ signal phase_reg : natural;
+ signal data_reg : std_logic_vector(data_i'range);
+
+ signal state : state_type;
+ signal dsp_opcode : dsp_opcode_type;
+
+ -- DSP Signals
+ signal a : word_vector_t (0 to num_channels_g-1);
+ signal b : word_t;
+ signal p : dword_vector_t(0 to num_channels_g-1);
+ signal r : word_vector_t (0 to num_channels_g-1);
+
+ -- RAM/ROM Signals
+ signal taps_addr : natural;
+ signal next_taps_addr : natural;
+ signal z_addr : natural;
+ signal z_ram : rom_t(0 to num_regs_c-1);
+ signal z_ram_en : std_logic;
+
+ -- Quantization signals
+ signal q : dword_vector_t(0 to num_channels_g-1);
+
+ -- for internal testing
+ signal rom_data_test : word_t;
+ signal rom_addr_test : natural;
+
+--------------------------------------------------------------------------------
+begin
+--------------------------------------------------------------------------------
+ -- The actual fir filter part
+ -----------------------------------------------------------------------------
+ -- Direct signal assignments
+ -----------------------------------------------------------------------------
+ a_gen : for idx in 0 to num_channels_g-1 generate
+ -- Get the input for the multiplication
+ a(idx) <= z_ram(z_addr)((idx+1)*taps_width_g-1 downto idx*taps_width_g);
+
+ -- Since the rounding is combinational, we can sum it up here
+ q(idx) <= p(idx) + round_val;
+
+ -- Now the data out
+ data_o((idx+1)*taps_width_g-1 downto idx*taps_width_g) <=
+ std_logic_vector(r(idx));
+ end generate a_gen;
+
+ -- This one is easy
+ b <= taps_rom(taps_addr); -- Select MUX
+
+ -----------------------------------------------------------------------------
+ -- FIR process controls the main state machine behind the serial FIR
+ -----------------------------------------------------------------------------
+ fsm_proc : process(clk_i)
+ variable idx_hi : natural;
+ variable idx_lo : natural;
+ begin
+ if rising_edge(clk_i) then
+ if rst_i = '1' then
+ state <= idle_state;
+ dsp_opcode <= clear;
+ z_ram_en <= '0';
+ z_addr <= 0 ;
+ taps_addr <= 0 ;
+ next_taps_addr <= 0 ;
+ data_en_o <= '0';
+-- data_o <= (others => '0');
+ else
+ -- Default cases
+ z_ram_en <= '0';
+ data_en_o <= '0';
+ next_taps_addr <= next_taps_addr + step_size_g;
+
+ -- Other cases
+ case state is
+ -----------------------------------------------------------------
+ when idle_state =>
+ dsp_opcode <= clear;
+ z_addr <= 0 ;
+ taps_addr <= 0 ;
+ if data_en_i = '1' or run_i = '1' then
+ z_ram_en <= data_en_i;
+ state <= load_state;
+ phase_reg <= phase_offset_c + to_integer(unsigned(phase_i));
+ data_reg <= data_i;
+ end if;
+ -----------------------------------------------------------------
+ when load_state =>
+ dsp_opcode <= clear;
+ z_addr <= 0 ;
+ taps_addr <= phase_reg;
+ next_taps_addr <= phase_reg;
+ state <= mult_state;
+ -----------------------------------------------------------------
+ when mult_state =>
+ dsp_opcode <= mult;
+ z_addr <= 0 ;
+ taps_addr <= phase_reg;
+ state <= macc_state;
+ -----------------------------------------------------------------
+ when macc_state =>
+ dsp_opcode <= macc;
+
+ -- The delayed version of the incoming signal
+-- if next_taps_addr >= taps_rom'length then
+ if z_addr = z_ram'high then
+ state <= save_state;
+ else
+ z_addr <= z_addr + 1;
+ taps_addr <= next_taps_addr;
+ end if;
+ -----------------------------------------------------------------
+ when save_state =>
+ dsp_opcode <= macc;
+ z_addr <= 0 ;
+ data_en_o <= '1';
+ state <= idle_state;
+ for idx in q'range loop
+ r(idx) <= q(idx)(save_range);
+ end loop;
+ -----------------------------------------------------------------
+ end case;
+ end if;
+ end if;
+ end process fsm_proc;
+
+ -----------------------------------------------------------------------------
+ -- DSP48 process emulates a DSP48 (partially)
+ -----------------------------------------------------------------------------
+ alu_proc : process(clk_i)
+ begin
+ if rising_edge(clk_i) then
+ if rst_i = '1' then
+ p <= (others => (others => '0'));
+ else
+ case dsp_opcode is
+ ------------------------------------------------------------
+ when clear =>
+ p <= (others => (others => '0'));
+ ------------------------------------------------------------
+ when mult =>
+ for idx in p'range loop
+ p(idx) <= a(idx) * b;
+ end loop;
+ ------------------------------------------------------------
+ when macc =>
+ for idx in p'range loop
+ p(idx) <= p(idx) + a(idx) * b;
+ end loop;
+ ------------------------------------------------------------
+ when hold =>
+ null;
+ ------------------------------------------------------------
+ end case;
+ end if;
+ end if;
+ end process alu_proc;
+
+ -----------------------------------------------------------------------------
+ -- Shift RAM
+ -----------------------------------------------------------------------------
+ -- I'm calling it the z ram, since it is the z delay of the incoming signal
+ shift_ram_proc : process(clk_i)
+ begin
+ if rising_edge(clk_i) then
+ if rst_i = '1' then
+ z_ram <= (others => (others => '0'));
+ elsif z_ram_en = '1' then
+ z_ram <= signed(data_reg) & z_ram(0 to z_ram'length-2);
+ end if;
+ end if;
+ end process shift_ram_proc;
+
+ ----------------------------------------------------------------------------
+ -- tests
+ ----------------------------------------------------------------------------
+ -- synthesis off
+ -- Test the rom by iterating through the rom
+ rom_test_proc : process(clk_i)
+ begin
+ if rising_edge(clk_i) then
+ if rst_i = '1' then
+ rom_addr_test <= 0;
+ else
+ if rom_addr_test >= taps_rom'length-1 then
+ rom_addr_test <= 0;
+ else
+ rom_addr_test <= rom_addr_test + 1;
+ end if;
+ end if;
+ end if;
+ end process rom_test_proc;
+
+ -- combinational read
+ rom_data_test <= taps_rom(rom_addr_test);
+ -- synthesis on
+
+end architecture behavior;
diff --git a/testsuite/gna/bug24064/testsuite.sh b/testsuite/gna/bug24064/testsuite.sh
new file mode 100755
index 000000000..2b3d8f17f
--- /dev/null
+++ b/testsuite/gna/bug24064/testsuite.sh
@@ -0,0 +1,11 @@
+#! /bin/sh
+
+. ../../testenv.sh
+
+analyze er_pack.vhd
+analyze pp_fir_filter.vhd
+elab_simulate pp_fir_filter
+
+clean
+
+echo "Test successful"