aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTristan Gingold <tgingold@free.fr>2017-06-12 05:38:52 +0200
committerTristan Gingold <tgingold@free.fr>2017-06-12 05:38:52 +0200
commit15f250b53c21dc9898126d9476edb4322cdbb6b4 (patch)
tree3a15e42b4cceaf34f3279c8a3385f529e562d99b
parentd986b9af22f4e927e887f1bd6f9ff5174dde4aca (diff)
downloadghdl-15f250b53c21dc9898126d9476edb4322cdbb6b4.tar.gz
ghdl-15f250b53c21dc9898126d9476edb4322cdbb6b4.tar.bz2
ghdl-15f250b53c21dc9898126d9476edb4322cdbb6b4.zip
Add reproducer for #301
-rw-r--r--testsuite/gna/issue301/Makefile71
-rw-r--r--testsuite/gna/issue301/packages/pkg_components.vhd194
-rw-r--r--testsuite/gna/issue301/packages/pkg_helper.vhd58
-rw-r--r--testsuite/gna/issue301/packages/pkg_param.vhd78
-rw-r--r--testsuite/gna/issue301/packages/pkg_param_derived.vhd73
-rw-r--r--testsuite/gna/issue301/packages/pkg_trellis.vhd185
-rw-r--r--testsuite/gna/issue301/packages/pkg_types.vhd37
-rw-r--r--testsuite/gna/issue301/repro.vhdl40
-rw-r--r--testsuite/gna/issue301/src/acs.vhd134
-rw-r--r--testsuite/gna/issue301/src/axi4s_buffer.vhd130
-rw-r--r--testsuite/gna/issue301/src/branch_distance.vhd111
-rw-r--r--testsuite/gna/issue301/src/dec_viterbi.vhd399
-rw-r--r--testsuite/gna/issue301/src/generic_sp_ram.vhd90
-rw-r--r--testsuite/gna/issue301/src/ram_ctrl.vhd474
-rw-r--r--testsuite/gna/issue301/src/recursion.vhd96
-rw-r--r--testsuite/gna/issue301/src/reorder.vhd129
-rw-r--r--testsuite/gna/issue301/src/traceback.vhd101
-rwxr-xr-xtestsuite/gna/issue301/testsuite.sh29
18 files changed, 2429 insertions, 0 deletions
diff --git a/testsuite/gna/issue301/Makefile b/testsuite/gna/issue301/Makefile
new file mode 100644
index 000000000..95610d340
--- /dev/null
+++ b/testsuite/gna/issue301/Makefile
@@ -0,0 +1,71 @@
+###############################################################################
+# Copyright (c) 2015 Potential Ventures Ltd
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of Potential Ventures Ltd,
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL POTENTIAL VENTURES LTD BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+###############################################################################
+
+TOPLEVEL_LANG ?= vhdl
+
+ifneq ($(TOPLEVEL_LANG),vhdl)
+
+all:
+ @echo "Skipping test due to TOPLEVEL_LANG=$(TOPLEVEL_LANG) not being vhdl"
+clean::
+
+else
+
+TOPLEVEL = dec_viterbi_top
+
+ifeq ($(OS),Msys)
+WPWD=$(shell sh -c 'pwd -W')
+else
+WPWD=$(shell pwd)
+endif
+
+COCOTB?=$(WPWD)/../../..
+
+SRC_BASE = $(COCOTB)/tests/designs/viterbi_decoder_axi4s
+
+RTL_LIBRARY = dec_viterbi
+
+VHDL_SOURCES = $(SRC_BASE)/packages/pkg_helper.vhd \
+ $(SRC_BASE)/packages/pkg_param.vhd \
+ $(SRC_BASE)/packages/pkg_param_derived.vhd \
+ $(SRC_BASE)/packages/pkg_types.vhd \
+ $(SRC_BASE)/packages/pkg_components.vhd \
+ $(SRC_BASE)/packages/pkg_trellis.vhd \
+ $(SRC_BASE)/src/generic_sp_ram.vhd \
+ $(SRC_BASE)/src/axi4s_buffer.vhd \
+ $(SRC_BASE)/src/branch_distance.vhd \
+ $(SRC_BASE)/src/traceback.vhd \
+ $(SRC_BASE)/src/acs.vhd \
+ $(SRC_BASE)/src/ram_ctrl.vhd \
+ $(SRC_BASE)/src/reorder.vhd \
+ $(SRC_BASE)/src/recursion.vhd \
+ $(SRC_BASE)/src/dec_viterbi.vhd \
+
+include $(COCOTB)/makefiles/Makefile.inc
+include $(COCOTB)/makefiles/Makefile.sim
+
+endif
diff --git a/testsuite/gna/issue301/packages/pkg_components.vhd b/testsuite/gna/issue301/packages/pkg_components.vhd
new file mode 100644
index 000000000..fc86159aa
--- /dev/null
+++ b/testsuite/gna/issue301/packages/pkg_components.vhd
@@ -0,0 +1,194 @@
+--!
+--! Copyright (C) 2011 - 2014 Creonic GmbH
+--!
+--! This file is part of the Creonic Viterbi Decoder, which is distributed
+--! under the terms of the GNU General Public License version 2.
+--!
+--! @file
+--! @brief Component declarations for Viterbi decoder
+--! @author Markus Fehrenz
+--! @date 2011/04/07
+--!
+--!
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library dec_viterbi;
+use dec_viterbi.pkg_param.all;
+use dec_viterbi.pkg_param_derived.all;
+use dec_viterbi.pkg_types.all;
+
+package pkg_components is
+
+ component axi4s_buffer is
+ generic (
+ DATA_WIDTH : natural := 1
+ );
+ port (
+ clk : in std_logic;
+ rst : in std_logic;
+
+ input : in std_logic_vector(DATA_WIDTH - 1 downto 0);
+ input_valid : in std_logic;
+ input_last : in std_logic;
+ input_accept : out std_logic;
+
+ output : out std_logic_vector(DATA_WIDTH - 1 downto 0);
+ output_valid : out std_logic;
+ output_last : out std_logic;
+ output_accept : in std_logic
+ );
+ end component axi4s_buffer;
+
+ component branch_distance is
+ generic(
+ EDGE_WEIGHT : in std_logic_vector(NUMBER_PARITY_BITS - 1 downto 0)
+ );
+ port(
+ clk : in std_logic;
+ rst : in std_logic;
+
+ s_axis_input_tvalid : in std_logic;
+ s_axis_input_tdata : in t_input_block;
+ s_axis_input_tlast : in std_logic;
+ s_axis_input_tready : out std_logic;
+
+ m_axis_output_tvalid : out std_logic;
+ m_axis_output_tdata : out std_logic_vector(BW_BRANCH_RESULT - 1 downto 0);
+ m_axis_output_tlast : out std_logic;
+ m_axis_output_tready : in std_logic
+
+ );
+ end component branch_distance;
+
+ component acs is
+ generic(
+ initialize_value : in signed(BW_MAX_PROBABILITY - 1 downto 0)
+ );
+ port(
+ clk : in std_logic;
+ rst : in std_logic;
+
+ s_axis_inbranch_tvalid : in std_logic;
+ s_axis_inbranch_tdata_low : in std_logic_vector(BW_BRANCH_RESULT - 1 downto 0);
+ s_axis_inbranch_tdata_high : in std_logic_vector(BW_BRANCH_RESULT - 1 downto 0);
+ s_axis_inbranch_tlast : in std_logic;
+ s_axis_inbranch_tready : out std_logic;
+
+ s_axis_inprev_tvalid : in std_logic;
+ s_axis_inprev_tdata_low : in std_logic_vector(BW_MAX_PROBABILITY - 1 downto 0);
+ s_axis_inprev_tdata_high : in std_logic_vector(BW_MAX_PROBABILITY - 1 downto 0);
+ s_axis_inprev_tready : out std_logic;
+
+ m_axis_outprob_tvalid : out std_logic;
+ m_axis_outprob_tdata : out std_logic_vector(BW_MAX_PROBABILITY - 1 downto 0);
+ m_axis_outprob_tready : in std_logic;
+
+ m_axis_outdec_tvalid : out std_logic;
+ m_axis_outdec_tdata : out std_logic;
+ m_axis_outdec_tlast : out std_logic;
+ m_axis_outdec_tready : in std_logic
+ );
+ end component acs;
+
+ component ram_ctrl is
+ port(
+ clk : in std_logic;
+ rst : in std_logic;
+
+ s_axis_input_tvalid : in std_logic;
+ s_axis_input_tdata : in std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);
+ s_axis_input_tlast : in std_logic;
+ s_axis_input_tready : out std_logic;
+
+ m_axis_output_tvalid : out std_logic_vector(1 downto 0);
+ m_axis_output_tdata : out t_ram_rd_data;
+ m_axis_output_tlast : out std_logic_vector(1 downto 0);
+ m_axis_output_tready : in std_logic_vector(1 downto 0);
+ m_axis_output_window_tuser : out std_logic_vector(1 downto 0);
+ m_axis_output_last_tuser : out std_logic_vector(1 downto 0);
+
+ s_axis_ctrl_tvalid : in std_logic;
+ s_axis_ctrl_tdata : in std_logic_vector(31 downto 0);
+ s_axis_ctrl_tready : out std_logic
+ );
+ end component ram_ctrl;
+
+ component generic_sp_ram is
+ generic(
+ DISTR_RAM : boolean;
+ WORDS : integer;
+ BITWIDTH : integer
+ );
+ port(
+ clk : in std_logic;
+ rst : in std_logic;
+
+ wen : in std_logic;
+ en : in std_logic;
+
+ a : in std_logic_vector(BW_MAX_WINDOW_LENGTH - 1 downto 0);
+ d : in std_logic_vector(BITWIDTH - 1 downto 0 );
+ q : out std_logic_vector(BITWIDTH - 1 downto 0)
+ );
+ end component generic_sp_ram;
+
+ component trellis_traceback is
+ port(
+ clk : in std_logic;
+ rst : in std_logic;
+
+ s_axis_input_tvalid : in std_logic;
+ s_axis_input_tdata : in std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);
+ s_axis_input_tlast : in std_logic;
+ s_axis_input_tready : out std_logic;
+ s_axis_input_window_tuser : in std_logic;
+ s_axis_input_last_tuser : in std_logic;
+
+ m_axis_output_tvalid : out std_logic;
+ m_axis_output_tdata : out std_logic;
+ m_axis_output_tlast : out std_logic;
+ m_axis_output_last_tuser : out std_logic;
+ m_axis_output_tready : in std_logic
+ );
+ end component trellis_traceback;
+
+ component reorder is
+ port(
+ clk : in std_logic;
+ rst : in std_logic;
+
+ s_axis_input_tvalid : in std_logic;
+ s_axis_input_tdata : in std_logic;
+ s_axis_input_tlast : in std_logic;
+ s_axis_input_last_tuser : in std_logic;
+ s_axis_input_tready : out std_logic;
+
+ m_axis_output_tvalid : out std_logic;
+ m_axis_output_tdata : out std_logic;
+ m_axis_output_tlast : out std_logic;
+ m_axis_output_last_tuser : out std_logic;
+ m_axis_output_tready : in std_logic
+ );
+ end component reorder;
+
+ component recursionx is
+ port(
+ clk : in std_logic;
+ rst : in std_logic;
+
+ s_axis_input_tvalid : in std_logic;
+ s_axis_input_tdata : in std_logic;
+ s_axis_input_tlast : in std_logic;
+ s_axis_input_tready : out std_logic;
+
+ m_axis_output_tvalid : out std_logic;
+ m_axis_output_tdata : out std_logic;
+ m_axis_output_tlast : out std_logic;
+ m_axis_output_tready : in std_logic
+ );
+ end component recursionx;
+
+end package pkg_components;
diff --git a/testsuite/gna/issue301/packages/pkg_helper.vhd b/testsuite/gna/issue301/packages/pkg_helper.vhd
new file mode 100644
index 000000000..8fe59743a
--- /dev/null
+++ b/testsuite/gna/issue301/packages/pkg_helper.vhd
@@ -0,0 +1,58 @@
+--!
+--! Copyright (C) 2011 - 2014 Creonic GmbH
+--!
+--! This file is part of the Creonic Viterbi Decoder, which is distributed
+--! under the terms of the GNU General Public License version 2.
+--!
+--! @file
+--! @brief Helper package with useful functions
+--! @author Markus Fehrenz
+--! @date 2011/12/02
+--!
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+
+package pkg_helper is
+
+ --!
+ --! Return the log_2 of an natural value, i.e. the number of bits required
+ --! to represent this unsigned value.
+ --!
+ function no_bits_natural(value_in : natural) return natural;
+
+ --! Return maximum of two input values
+ function max(value_in_a, value_in_b : natural) return natural;
+
+end pkg_helper;
+
+
+package body pkg_helper is
+
+ function no_bits_natural(value_in: natural) return natural is
+ variable v_n_bit : unsigned(31 downto 0);
+ begin
+ if value_in = 0 then
+ return 0;
+ end if;
+ v_n_bit := to_unsigned(value_in, 32);
+ for i in 31 downto 0 loop
+ if v_n_bit(i) = '1' then
+ return i + 1;
+ end if;
+ end loop;
+ return 1;
+ end no_bits_natural;
+
+ function max(value_in_a, value_in_b : natural) return natural is
+ begin
+ if value_in_a > value_in_b then
+ return value_in_a;
+ else
+ return value_in_b;
+ end if;
+ end function;
+
+end pkg_helper;
diff --git a/testsuite/gna/issue301/packages/pkg_param.vhd b/testsuite/gna/issue301/packages/pkg_param.vhd
new file mode 100644
index 000000000..1bc3f6602
--- /dev/null
+++ b/testsuite/gna/issue301/packages/pkg_param.vhd
@@ -0,0 +1,78 @@
+--!
+--! Copyright (C) 2011 - 2014 Creonic GmbH
+--!
+--! This file is part of the Creonic Viterbi Decoder, which is distributed
+--! under the terms of the GNU General Public License version 2.
+--!
+--! @file
+--! @brief Parameters
+--! @author Markus Fehrenz
+--! @date 2011/07/01
+--!
+--! @details This is the configuration file of the Viterbi decoder.
+--! Any changes for parameters should be done here.
+--! Changing parameters somewhere else may result in a malicious
+--! behavior.
+--!
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+
+package pkg_param is
+ -----------------------------------
+ -- Convolutional Code Parameters --
+ -----------------------------------
+
+
+ --
+ -- Set the number of parity values
+ -- This has to correspond to PARITY_POLYNOMIALS
+ --
+ constant NUMBER_PARITY_BITS : natural := 2;
+ type t_parity is array (NUMBER_PARITY_BITS - 1 downto 0) of natural;
+
+ --
+ -- Set parity polynoms in decimal notation
+ -- NUMBER_PARITY_BITS has to correspond to the number of elements
+ -- Examples: WiFi : [121,91] or [121,91,101]
+ -- CDMA : [491,369] or [367,435,369] or [501,441,331,315]
+ -- GSM : [27,19] or [27,21,31]
+ -- DAB : [91,121,101,91]
+ -- WiMAX: [91,121,117]
+ --
+ constant PARITY_POLYNOMIALS : t_parity := (121,91);
+
+
+ --
+ -- Set a recursive polynomial
+ -- Set to 0 if no recursion is used
+ -- Setting this arbitrary may result in a worse error correction ability
+ --
+ constant FEEDBACK_POLYNOMIAL : natural := 0;
+
+
+ -----------------------------
+ -- Architecture Parameters --
+ -----------------------------
+
+ --
+ -- Set bit width of LLR input
+ -- Recommended values: 3 or 4
+ --
+ constant BW_LLR_INPUT : natural := 4;
+
+ --
+ -- Set the maximum window length which shall be allowed at runtime.
+ -- Recommended: at least 6 * constraint length
+ --
+ constant MAX_WINDOW_LENGTH : natural := 96;
+
+ --
+ -- Set to 'true' if distributed RAM shall be used
+ -- Set to 'false' if block RAM shall be used
+ --
+ constant DISTRIBUTED_RAM : boolean := true;
+
+end package pkg_param;
diff --git a/testsuite/gna/issue301/packages/pkg_param_derived.vhd b/testsuite/gna/issue301/packages/pkg_param_derived.vhd
new file mode 100644
index 000000000..f6e77cada
--- /dev/null
+++ b/testsuite/gna/issue301/packages/pkg_param_derived.vhd
@@ -0,0 +1,73 @@
+--!
+--! Copyright (C) 2011 - 2014 Creonic GmbH
+--!
+--! This file is part of the Creonic Viterbi Decoder, which is distributed
+--! under the terms of the GNU General Public License version 2.
+--!
+--! @file
+--! @brief Derived parameters
+--! @author Markus Fehrenz
+--! @date 2011/07/04
+--!
+--! @details This constants are derived from constants defined in pkg_param.
+--! In order to prevent errors, there is no user choice for these parameters.
+--!
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library dec_viterbi;
+use dec_viterbi.pkg_param.all;
+use dec_viterbi.pkg_helper.all;
+
+
+package pkg_param_derived is
+
+ -- Calculation of constraint length.
+ function calc_constraint_length return natural;
+
+ -- Memory depth of the encoder shift register.
+ constant ENCODER_MEMORY_DEPTH : natural;
+
+ -- Number of trellis states corresponds to the nubmer of ACS units.
+ constant NUMBER_TRELLIS_STATES : natural;
+
+ -- Number of branch units for a single polynomial set
+ constant NUMBER_BRANCH_UNITS : natural;
+
+ -- Bitwidth constants are needed for type conversions
+ constant BW_TRELLIS_STATES : natural;
+ constant BW_MAX_WINDOW_LENGTH : natural;
+ constant BW_BRANCH_RESULT : natural;
+ constant BW_MAX_PROBABILITY : natural;
+
+end package pkg_param_derived;
+
+
+package body pkg_param_derived is
+
+ function calc_constraint_length return natural is
+ variable v_maximum : natural := 0;
+ begin
+
+ -- Find the position of the leftmost bit in the polynomials.
+ for i in NUMBER_PARITY_BITS - 1 downto 0 loop
+ v_maximum := max(v_maximum, no_bits_natural(PARITY_POLYNOMIALS(i)));
+ end loop;
+ v_maximum := max(v_maximum, no_bits_natural(FEEDBACK_POLYNOMIAL));
+ return v_maximum;
+ end function calc_constraint_length;
+
+
+ constant ENCODER_MEMORY_DEPTH : natural := calc_constraint_length - 1;
+
+ constant NUMBER_TRELLIS_STATES : natural := 2 ** ENCODER_MEMORY_DEPTH;
+
+ constant NUMBER_BRANCH_UNITS : natural := 2 ** NUMBER_PARITY_BITS;
+
+ constant BW_TRELLIS_STATES : natural := no_bits_natural(NUMBER_TRELLIS_STATES - 1);
+ constant BW_MAX_WINDOW_LENGTH : natural := no_bits_natural(MAX_WINDOW_LENGTH - 1);
+ constant BW_BRANCH_RESULT : natural := no_bits_natural((2 ** (BW_LLR_INPUT - 1)) * NUMBER_PARITY_BITS) + 1;
+ constant BW_MAX_PROBABILITY : natural := no_bits_natural(((2 ** (BW_LLR_INPUT - 1)) * NUMBER_PARITY_BITS) * 4 * ENCODER_MEMORY_DEPTH);
+end package body pkg_param_derived;
diff --git a/testsuite/gna/issue301/packages/pkg_trellis.vhd b/testsuite/gna/issue301/packages/pkg_trellis.vhd
new file mode 100644
index 000000000..a797d3ac9
--- /dev/null
+++ b/testsuite/gna/issue301/packages/pkg_trellis.vhd
@@ -0,0 +1,185 @@
+--!
+--! Copyright (C) 2011 - 2014 Creonic GmbH
+--!
+--! This file is part of the Creonic Viterbi Decoder, which is distributed
+--! under the terms of the GNU General Public License version 2.
+--!
+--! @file
+--! @brief Trellis parameter calculations (e.g., transitions, init values).
+--! @author Markus Fehrenz
+--! @date 2011/07/27
+--!
+--!
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library dec_viterbi;
+use dec_viterbi.pkg_param.all;
+use dec_viterbi.pkg_param_derived.all;
+use dec_viterbi.pkg_types.all;
+
+
+package pkg_trellis is
+
+ type t_prev_base is array (1 downto 0) of std_logic_vector(BW_TRELLIS_STATES - 1 downto 0);
+ type t_previous_states is array (NUMBER_TRELLIS_STATES - 1 downto 0) of t_prev_base;
+
+ type t_trans_base is array (1 downto 0) of std_logic_vector(NUMBER_PARITY_BITS - 1 downto 0);
+ type t_transitions is array (NUMBER_TRELLIS_STATES - 1 downto 0) of t_trans_base;
+
+ type t_trans_base_signed is array (1 downto 0) of std_logic_vector(NUMBER_PARITY_BITS downto 0);
+ type t_transitions_signed is array (NUMBER_TRELLIS_STATES - 1 downto 0) of t_trans_base_signed;
+
+
+ --
+ -- This function calculates the previous states of each state.
+ -- The values are used to connect the ACS units.
+ --
+ function calc_previous_states return t_previous_states;
+
+
+ --
+ -- This function calculates corresponding transitions to a trellis sate.
+ -- The values are used to connect branch units to ACS units.
+ --
+ function calc_transitions return t_transitions;
+
+
+ --
+ -- This function calculates the initialization values for trellis metrics.
+ -- The values are used as a constant and written to the ACS unit, every time a new block arrives.
+ --
+ function calc_initialize return t_node_s;
+
+ constant PREVIOUS_STATES : t_previous_states;
+ constant TRANSITIONS : t_transitions;
+ constant INITIALIZE_TRELLIS : t_node_s;
+
+end package pkg_trellis;
+
+
+package body pkg_trellis is
+
+
+ function calc_previous_states return t_previous_states is
+ variable v_prev_states : t_previous_states := (others=>(others=>(others => '0')));
+ variable v_state0, v_state1 : std_logic_vector(BW_TRELLIS_STATES - 1 downto 0);
+ begin
+ for i in NUMBER_TRELLIS_STATES - 1 downto 0 loop
+ v_state0 := std_logic_vector(to_unsigned(i,BW_TRELLIS_STATES));
+ v_state1 := v_state0(BW_TRELLIS_STATES - 2 downto 0) & '0';
+ v_prev_states(i)(0) := v_state1;
+ v_state1 := v_state0(BW_TRELLIS_STATES - 2 downto 0) & '1';
+ v_prev_states(i)(1) := v_state1;
+ end loop;
+ return v_prev_states;
+ end function calc_previous_states;
+
+
+ function calc_transitions return t_transitions is
+ variable v_transitions : t_transitions_signed := (others => (others => (others => '0')));
+ variable v_transitions_out : t_transitions := (others => (others => (others => '0')));
+ variable v_one_transition : std_logic_vector(NUMBER_PARITY_BITS - 1 downto 0);
+ variable v_next_state : unsigned(ENCODER_MEMORY_DEPTH - 1 downto 0) := (others => '0');
+ variable v_state, v_states : unsigned(ENCODER_MEMORY_DEPTH downto 0);
+ variable v_bit : std_logic := '0';
+ begin
+
+ --
+ -- It is possible to reduce code size at this stage, if feedback is handled differently,
+ -- but the complexity will increase.
+ --
+
+ for i in NUMBER_TRELLIS_STATES - 1 downto 0 loop
+
+ --
+ -- for input : 0
+ -- determine correct input with feedback
+ --
+ v_next_state := to_unsigned(i,ENCODER_MEMORY_DEPTH) and to_unsigned(FEEDBACK_POLYNOMIAL, ENCODER_MEMORY_DEPTH);
+ for k in ENCODER_MEMORY_DEPTH - 1 downto 0 loop
+ v_bit := v_bit xor v_next_state(k);
+ end loop;
+ v_state(ENCODER_MEMORY_DEPTH) := v_bit;
+ v_state(ENCODER_MEMORY_DEPTH - 1 downto 0) := to_unsigned(i,ENCODER_MEMORY_DEPTH);
+ v_next_state := v_state(ENCODER_MEMORY_DEPTH downto 1);
+ v_bit := '0';
+
+ -- determine paritybits
+ for j in NUMBER_PARITY_BITS - 1 downto 0 loop
+ v_states := v_state and to_unsigned(PARITY_POLYNOMIALS(j), ENCODER_MEMORY_DEPTH + 1);
+ for k in ENCODER_MEMORY_DEPTH downto 0 loop
+ v_bit := v_bit xor v_states(k);
+ end loop;
+ v_one_transition(j) := v_bit;
+ v_bit := '0';
+ end loop;
+
+ -- decide where to save the parity result
+ if v_transitions(to_integer(v_next_state))(1)(NUMBER_PARITY_BITS) = '0' then
+ v_transitions(to_integer(v_next_state))(1)(NUMBER_PARITY_BITS) := '1';
+ v_transitions(to_integer(v_next_state))(1)(NUMBER_PARITY_BITS - 1 downto 0) := v_one_transition;
+ else
+ v_transitions(to_integer(v_next_state))(0)(NUMBER_PARITY_BITS - 1 downto 0) := v_one_transition;
+ end if;
+
+ --
+ -- for input: 1
+ -- determine correct input with feedback
+ --
+ v_next_state := to_unsigned(i,ENCODER_MEMORY_DEPTH) and to_unsigned(FEEDBACK_POLYNOMIAL, ENCODER_MEMORY_DEPTH);
+ for k in ENCODER_MEMORY_DEPTH - 1 downto 0 loop
+ v_bit := v_bit xor v_next_state(k);
+ end loop;
+ v_state(ENCODER_MEMORY_DEPTH) := '1' xor v_bit;
+ v_state(ENCODER_MEMORY_DEPTH - 1 downto 0) := to_unsigned(i,ENCODER_MEMORY_DEPTH);
+ v_next_state := v_state(ENCODER_MEMORY_DEPTH downto 1);
+ v_bit := '0';
+
+ -- determine paritybits
+ for j in NUMBER_PARITY_BITS - 1 downto 0 loop
+ v_states := v_state and to_unsigned(PARITY_POLYNOMIALS(j), ENCODER_MEMORY_DEPTH + 1);
+ for k in ENCODER_MEMORY_DEPTH downto 0 loop
+ v_bit := v_bit xor v_states(k);
+ end loop;
+ v_one_transition(j) := v_bit;
+ v_bit := '0';
+ end loop;
+
+ -- decide where to save parity result
+ if v_transitions(to_integer(v_next_state))(1)(NUMBER_PARITY_BITS) = '0' then
+ v_transitions(to_integer(v_next_state))(1)(NUMBER_PARITY_BITS) := '1';
+ v_transitions(to_integer(v_next_state))(1)(NUMBER_PARITY_BITS - 1 downto 0) := v_one_transition;
+ else
+ v_transitions(to_integer(v_next_state))(0)(NUMBER_PARITY_BITS - 1 downto 0) := v_one_transition;
+ end if;
+ end loop;
+
+ -- truncate, the bit, used to decide where to save parity result
+ for i in NUMBER_TRELLIS_STATES - 1 downto 0 loop
+ v_transitions_out(i)(1) := v_transitions(i)(1)(NUMBER_PARITY_BITS - 1 downto 0);
+ v_transitions_out(i)(0) := v_transitions(i)(0)(NUMBER_PARITY_BITS - 1 downto 0);
+ end loop;
+
+ return v_transitions_out;
+ end function calc_transitions;
+
+
+ function calc_initialize return t_node_s is
+ variable v_initialize : t_node_s;
+ begin
+ v_initialize(0) := to_signed(0, BW_MAX_PROBABILITY);
+ for i in NUMBER_TRELLIS_STATES - 1 downto 1 loop
+ v_initialize(i) := to_signed(- 2 ** (BW_MAX_PROBABILITY - 2), BW_MAX_PROBABILITY);
+ end loop;
+ return v_initialize;
+ end function calc_initialize;
+
+
+ constant PREVIOUS_STATES : t_previous_states := calc_previous_states;
+ constant TRANSITIONS : t_transitions := calc_transitions;
+ constant INITIALIZE_TRELLIS : t_node_s := calc_initialize;
+
+end package body pkg_trellis;
diff --git a/testsuite/gna/issue301/packages/pkg_types.vhd b/testsuite/gna/issue301/packages/pkg_types.vhd
new file mode 100644
index 000000000..5acdd4ebe
--- /dev/null
+++ b/testsuite/gna/issue301/packages/pkg_types.vhd
@@ -0,0 +1,37 @@
+--!
+--! Copyright (C) 2011 - 2014 Creonic GmbH
+--!
+--! This file is part of the Creonic Viterbi Decoder, which is distributed
+--! under the terms of the GNU General Public License version 2.
+--!
+--! @file
+--! @brief Global types for the Viterbi decoder
+--! @author Markus Fehrenz
+--! @date 2011/07/04
+--!
+--! @details Most types are shared and used in different context.
+--! Changing single types should be done with adding an additional type.
+--!
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library dec_viterbi;
+use dec_viterbi.pkg_param.all;
+use dec_viterbi.pkg_param_derived.all;
+
+package pkg_types is
+
+ -- Parity structure: p1_bit, p2_bit, ..., pN_bit
+ type t_input_block is array (NUMBER_PARITY_BITS - 1 downto 0) of signed(BW_LLR_INPUT - 1 downto 0);
+
+ -- Types are used for bulk information to ACS and branch unit.
+ type t_node_s is array (NUMBER_TRELLIS_STATES - 1 downto 0) of signed(BW_MAX_PROBABILITY - 1 downto 0);
+ type t_node is array (NUMBER_TRELLIS_STATES - 1 downto 0) of std_logic_vector(BW_MAX_PROBABILITY - 1 downto 0);
+ type t_branch is array (NUMBER_BRANCH_UNITS - 1 downto 0) of std_logic_vector(BW_BRANCH_RESULT - 1 downto 0);
+
+ -- RAM Data
+ type t_ram_rd_data is array (1 downto 0) of std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);
+
+end package pkg_types;
diff --git a/testsuite/gna/issue301/repro.vhdl b/testsuite/gna/issue301/repro.vhdl
new file mode 100644
index 000000000..04369e197
--- /dev/null
+++ b/testsuite/gna/issue301/repro.vhdl
@@ -0,0 +1,40 @@
+package pkgc is
+ constant width : natural;
+end pkgc;
+
+package body pkgc is
+ constant width : natural := 4;
+end pkgc;
+
+use work.pkgc.all;
+package pkgcomp is
+ component comp is
+ generic (val : bit_vector (width -1 downto 0));
+ port (b : out bit);
+ end component;
+end pkgcomp;
+
+use work.pkgc.all;
+entity comp is
+ generic (val : bit_vector (width -1 downto 0));
+ port (b : out bit);
+end comp;
+
+architecture behav of comp is
+begin
+ b <= val (val'left);
+end behav;
+
+entity repro is
+end repro;
+
+use work.pkgc.all;
+use work.pkgcomp.all;
+
+architecture behav of repro is
+ signal res : bit;
+begin
+ inst : comp
+ generic map (val => "0010")
+ port map (b => res );
+end behav;
diff --git a/testsuite/gna/issue301/src/acs.vhd b/testsuite/gna/issue301/src/acs.vhd
new file mode 100644
index 000000000..958050a39
--- /dev/null
+++ b/testsuite/gna/issue301/src/acs.vhd
@@ -0,0 +1,134 @@
+--!
+--! Copyright (C) 2011 - 2014 Creonic GmbH
+--!
+--! This file is part of the Creonic Viterbi Decoder, which is distributed
+--! under the terms of the GNU General Public License version 2.
+--!
+--! @file
+--! @brief Add-compare-select unit for trellis processing.
+--! @author Markus Fehrenz
+--! @date 2011/07/04
+--!
+--! @details The ACS decides which path is the the surviving trellis path.
+--! In the design there are 2^{K-1} ACS instances.
+--!
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library dec_viterbi;
+use dec_viterbi.pkg_param.all;
+use dec_viterbi.pkg_param_derived.all;
+use dec_viterbi.pkg_types.all;
+use dec_viterbi.pkg_helper.all;
+
+
+entity acs is
+ generic(
+
+ -- Reset value
+ INITIALIZE_VALUE : in signed(BW_MAX_PROBABILITY - 1 downto 0)
+ );
+ port(
+ clk : in std_logic;
+ rst : in std_logic;
+
+ --
+ -- Values from branch distance, signed values in std_logic_vector
+ -- high is located in the upper half.
+ --
+ s_axis_inbranch_tvalid : in std_logic;
+ s_axis_inbranch_tdata_low : in std_logic_vector(BW_BRANCH_RESULT - 1 downto 0);
+ s_axis_inbranch_tdata_high : in std_logic_vector(BW_BRANCH_RESULT - 1 downto 0);
+ s_axis_inbranch_tlast : in std_logic;
+ s_axis_inbranch_tready : out std_logic;
+
+ --
+ -- Probabilities from previous nodes, signed values in std_logic_vector
+ -- high is located in the upper half.
+ --
+ s_axis_inprev_tvalid : in std_logic;
+ s_axis_inprev_tdata_low : in std_logic_vector(BW_MAX_PROBABILITY - 1 downto 0);
+ s_axis_inprev_tdata_high : in std_logic_vector(BW_MAX_PROBABILITY - 1 downto 0);
+ s_axis_inprev_tready : out std_logic;
+
+ -- probability result of the add compare and select
+ m_axis_outprob_tvalid : out std_logic;
+ m_axis_outprob_tdata : out std_logic_vector(BW_MAX_PROBABILITY - 1 downto 0);
+ m_axis_outprob_tready : in std_logic;
+
+ -- decision result of the add compare and select
+ m_axis_outdec_tvalid : out std_logic;
+ m_axis_outdec_tdata : out std_logic;
+ m_axis_outdec_tlast : out std_logic;
+ m_axis_outdec_tready : in std_logic
+ );
+end entity acs;
+
+
+architecture rtl of acs is
+
+ signal s_axis_inbranch_tlast_d : std_logic;
+ signal m_axis_outdec_tvalid_int : std_logic;
+ signal s_axis_inbranch_tready_int : std_logic;
+
+begin
+
+ s_axis_inbranch_tready_int <= '1' when m_axis_outdec_tready = '1' or m_axis_outdec_tvalid_int = '0' else
+ '0';
+ s_axis_inbranch_tready <= s_axis_inbranch_tready_int;
+ m_axis_outdec_tvalid <= m_axis_outdec_tvalid_int;
+
+ -- Add branch to previous, compare both paths and select survivor.
+ pr_add_compare : process(clk) is
+ variable v_diff, v_high, v_low : signed(BW_MAX_PROBABILITY - 1 downto 0);
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ m_axis_outdec_tvalid_int <= '0';
+ m_axis_outdec_tdata <= '0';
+ m_axis_outdec_tlast <= '0';
+ m_axis_outprob_tvalid <= '0';
+ s_axis_inprev_tready <= '0';
+ s_axis_inbranch_tlast_d <= '0';
+ m_axis_outprob_tdata <= std_logic_vector(INITIALIZE_VALUE);
+ else
+ -- If this is the last value, prepare for processing of next incoming value.
+ if s_axis_inbranch_tlast_d = '1' then
+ m_axis_outprob_tdata <= std_logic_vector(INITIALIZE_VALUE);
+ s_axis_inbranch_tlast_d <= '0';
+ m_axis_outdec_tvalid_int <= '0';
+ end if;
+ if m_axis_outdec_tvalid_int = '1' and m_axis_outdec_tready = '1' then
+ m_axis_outdec_tvalid_int <= '0';
+ end if;
+
+ -- Process only if we receive valid data.
+ if s_axis_inbranch_tvalid = '1' and s_axis_inbranch_tready_int = '1' then
+ s_axis_inbranch_tlast_d <= s_axis_inbranch_tlast;
+
+ -- Add.
+ v_low := signed(s_axis_inbranch_tdata_low) + signed(s_axis_inprev_tdata_low);
+ v_high := signed(s_axis_inbranch_tdata_high) + signed(s_axis_inprev_tdata_high);
+
+ -- Use modulo normalization, do not extend the sign here!
+ v_diff := v_low - v_high;
+
+ -- Compare, select the correct path.
+ if v_diff < 0 then
+ m_axis_outdec_tdata <= '1';
+ m_axis_outprob_tdata <= std_logic_vector(v_high);
+ else
+ m_axis_outdec_tdata <= '0';
+ m_axis_outprob_tdata <= std_logic_vector(v_low);
+ end if;
+ m_axis_outdec_tvalid_int <= '1';
+ end if;
+
+ m_axis_outdec_tlast <= s_axis_inbranch_tlast;
+ end if;
+ end if;
+ end process pr_add_compare;
+
+end architecture rtl;
diff --git a/testsuite/gna/issue301/src/axi4s_buffer.vhd b/testsuite/gna/issue301/src/axi4s_buffer.vhd
new file mode 100644
index 000000000..8e479162e
--- /dev/null
+++ b/testsuite/gna/issue301/src/axi4s_buffer.vhd
@@ -0,0 +1,130 @@
+--!
+--! Copyright (C) 2012 - 2014 Creonic GmbH
+--!
+--! This file is part of the Creonic Viterbi Decoder, which is distributed
+--! under the terms of the GNU General Public License version 2.
+--!
+--! @file
+--! @brief AXI4-Stream buffer that allows to buffer the accept-signal.
+--! @author Matthias Alles
+--! @date 2012/04/18
+--!
+--! @details
+--! One problem when concatenating multiple AXI4-Stream builind blocks is that
+--! the accept signal has to pass from the very last component to the input
+--! of the very first component. Only then it is possible to have an interruption
+--! free data processing within the whole chain. The drawback of this approach is
+--! that the accept signal has a long path and high fanouts.
+--! This entity allows to use registers on the accept signals by introducing buffers
+--! for storing the input values. It should improve timing of bigger building blocks.
+--!
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+
+entity axi4s_buffer is
+ generic (
+ DATA_WIDTH : natural := 1
+ );
+ port (
+
+ clk : in std_logic;
+ rst : in std_logic;
+
+ -- Input data handling
+ ----------------------
+
+ input : in std_logic_vector(DATA_WIDTH - 1 downto 0);
+ input_valid : in std_logic;
+ input_last : in std_logic;
+ input_accept : out std_logic;
+
+
+ -- Output data handling
+ -----------------------
+ output : out std_logic_vector(DATA_WIDTH - 1 downto 0);
+ output_valid : out std_logic;
+ output_last : out std_logic;
+ output_accept : in std_logic
+);
+end entity axi4s_buffer;
+
+
+architecture rtl of axi4s_buffer is
+
+
+ signal input_accept_int : std_logic;
+
+ signal output_reg : std_logic_vector(DATA_WIDTH - 1 downto 0);
+ signal output_last_reg : std_logic;
+ signal output_valid_reg : std_logic;
+
+ signal buffer_full : std_logic;
+ signal buffer_data : std_logic_vector(DATA_WIDTH - 1 downto 0);
+ signal buffer_last : std_logic;
+
+begin
+
+ input_accept <= input_accept_int;
+
+ output <= output_reg;
+ output_last <= output_last_reg;
+ output_valid <= output_valid_reg;
+
+ --
+ -- This process registers all signals.
+ -- No combinatorial logic is bypassed from input to output and vice versa.
+ --
+ pr_reg: process(clk) is
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ output_reg <= (others => '0');
+ output_last_reg <= '0';
+ output_valid_reg <= '0';
+
+ input_accept_int <= '1';
+
+ buffer_full <= '0';
+ buffer_data <= (others => '0');
+ buffer_last <= '0';
+ else
+
+ --
+ -- Data is coming, buf output data can't be sent => Store input data in buffer
+ -- and remove input_accept signal!
+ --
+ if input_valid = '1' and input_accept_int = '1' and output_valid_reg = '1' and output_accept = '0' then
+ buffer_data <= input;
+ buffer_last <= input_last;
+ buffer_full <= '1';
+ input_accept_int <= '0';
+ end if;
+
+ --
+ -- Output data is being read but there is data in the buffer waiting for being sent
+ -- => Use the buffer data!
+ --
+ if output_accept = '1' and output_valid_reg = '1' and buffer_full = '1' then
+ output_reg <= buffer_data;
+ output_last_reg <= buffer_last;
+ output_valid_reg <= '1';
+ buffer_full <= '0';
+ input_accept_int <= '1';
+
+ --
+ -- Data is being read and buffer is empty => Use input data directly!
+ -- Output register is empty => Use input data directly!
+ --
+ elsif (output_accept = '1' and output_valid_reg = '1') or output_valid_reg = '0' then
+ output_reg <= input;
+ output_last_reg <= input_last;
+ output_valid_reg <= input_valid;
+ end if;
+
+ end if;
+ end if;
+ end process pr_reg;
+
+end architecture rtl;
diff --git a/testsuite/gna/issue301/src/branch_distance.vhd b/testsuite/gna/issue301/src/branch_distance.vhd
new file mode 100644
index 000000000..31aa9a4fd
--- /dev/null
+++ b/testsuite/gna/issue301/src/branch_distance.vhd
@@ -0,0 +1,111 @@
+--!
+--! Copyright (C) 2011 - 2014 Creonic GmbH
+--!
+--! This file is part of the Creonic Viterbi Decoder, which is distributed
+--! under the terms of the GNU General Public License version 2.
+--!
+--! @file
+--! @brief Branch distance calculation unit.
+--! @author Markus Fehrenz
+--! @date 2011/08/04
+--!
+--! @details Each branch has to be calculated only once.
+--! The branch calculations are configured with a generic.
+--! There is no limitation in branch calculations.
+--!
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library dec_viterbi;
+use dec_viterbi.pkg_param.all;
+use dec_viterbi.pkg_param_derived.all;
+use dec_viterbi.pkg_types.all;
+
+
+entity branch_distance is
+ generic(
+ EDGE_WEIGHT : in std_logic_vector(0 to NUMBER_PARITY_BITS - 1)
+ );
+ port(
+ clk : in std_logic;
+ rst : in std_logic;
+
+ --
+ -- Input LLR values
+ --
+ s_axis_input_tvalid : in std_logic;
+ s_axis_input_tdata : in t_input_block;
+ s_axis_input_tlast : in std_logic;
+ s_axis_input_tready : out std_logic;
+
+
+ --
+ -- Output branch metrics, going to ACS unit.
+ --
+ m_axis_output_tvalid : out std_logic;
+ m_axis_output_tdata : out std_logic_vector(BW_BRANCH_RESULT - 1 downto 0);
+ m_axis_output_tlast : out std_logic;
+ m_axis_output_tready : in std_logic
+ );
+end entity branch_distance;
+
+
+architecture rtl of branch_distance is
+
+ signal m_axis_output_tvalid_int : std_logic;
+ signal s_axis_input_tready_int : std_logic;
+
+begin
+
+ -- We are ready, when we are allowed to write to the output, or the output is idle.
+ s_axis_input_tready_int <= '1' when m_axis_output_tready = '1' else
+ '0';
+
+ -- Connect internal versions of signal to output port.
+ s_axis_input_tready <= s_axis_input_tready_int;
+ m_axis_output_tvalid <= m_axis_output_tvalid_int;
+
+
+ -- Calculation of specific branch distance with a geometric distance function.
+ pr_branch : process(clk) is
+ variable v_branch_result : integer;
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ m_axis_output_tvalid_int <= '0';
+ m_axis_output_tdata <= (others => '0');
+ m_axis_output_tlast <= '0';
+ else
+
+ if m_axis_output_tvalid_int = '1' and m_axis_output_tready = '1' then
+ m_axis_output_tvalid_int <= '0';
+ m_axis_output_tlast <= '0';
+ end if;
+
+ if s_axis_input_tready_int = '1' and s_axis_input_tvalid = '1' then
+ v_branch_result := 0;
+
+ for i in NUMBER_PARITY_BITS - 1 downto 0 loop
+
+ --
+ -- Either the value is added or subtracted, depending on
+ -- the current branch metric we are computing.
+ --
+ if EDGE_WEIGHT(i) = '0' then
+ v_branch_result := v_branch_result + to_integer(s_axis_input_tdata(i));
+ else
+ v_branch_result := v_branch_result - to_integer(s_axis_input_tdata(i));
+ end if;
+ end loop;
+ m_axis_output_tdata <= std_logic_vector(to_signed(v_branch_result, BW_BRANCH_RESULT));
+ m_axis_output_tvalid_int <= '1';
+ m_axis_output_tlast <= s_axis_input_tlast;
+ end if;
+
+ end if;
+ end if;
+ end process pr_branch;
+
+end architecture rtl;
diff --git a/testsuite/gna/issue301/src/dec_viterbi.vhd b/testsuite/gna/issue301/src/dec_viterbi.vhd
new file mode 100644
index 000000000..f81d281a8
--- /dev/null
+++ b/testsuite/gna/issue301/src/dec_viterbi.vhd
@@ -0,0 +1,399 @@
+--!
+--! Copyright (C) 2011 - 2014 Creonic GmbH
+--!
+--! This file is part of the Creonic Viterbi Decoder, which is distributed
+--! under the terms of the GNU General Public License version 2.
+--!
+--! @file
+--! @brief Viterbi decoder top entity, connecting all decoder units.
+--! @author Markus Fehrenz
+--! @date 2011/12/05
+--!
+--! @details
+--! The AXI std_logic_vector input is mapped to an internal information type.
+--! Further the correct output order is handled.
+--!
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library dec_viterbi;
+use dec_viterbi.pkg_param.all;
+use dec_viterbi.pkg_param_derived.all;
+use dec_viterbi.pkg_types.all;
+use dec_viterbi.pkg_components.all;
+use dec_viterbi.pkg_trellis.all;
+
+
+entity dec_viterbi_top is
+ port(
+
+ --
+ -- The core only uses AXI4-Stream interfaces,
+ -- based on AMBA4 AXI4-Stream Protocol with restrictions according to
+ -- Xilinx Migration, described in Xilinx AXI Reference UG761 (v13.3).
+ --
+
+ aclk : in std_logic;
+
+ -- Synchronous reset, active low.
+ aresetn : in std_logic;
+
+
+ --
+ -- Slave (input) data signals
+ -- Delivers the parity LLR values, one byte per LLR value.
+ --
+ s_axis_input_tvalid : in std_logic;
+ s_axis_input_tdata : in std_logic_vector(31 downto 0);
+ s_axis_input_tlast : in std_logic;
+ s_axis_input_tready : out std_logic;
+
+
+ --
+ -- Master (output) data signals
+ -- Delivers the decoded systematic (payload) bits.
+ --
+ m_axis_output_tvalid : out std_logic;
+ m_axis_output_tdata : out std_logic;
+ m_axis_output_tlast : out std_logic;
+ m_axis_output_tready : in std_logic;
+
+
+ --
+ -- Slave (input) configuration signals
+ -- Configures window length and acquisition length.
+ --
+ s_axis_ctrl_tvalid : in std_logic;
+ s_axis_ctrl_tdata : in std_logic_vector(31 downto 0);
+ s_axis_ctrl_tlast : in std_logic;
+ s_axis_ctrl_tready : out std_logic
+);
+end entity dec_viterbi_top;
+
+
+architecture rtl of dec_viterbi_top is
+
+ alias clk is aclk;
+ signal rst : std_logic;
+
+ -- split tdata into input array
+ signal input : t_input_block;
+
+ -- buffer signals
+ signal buffer_tdata : std_logic_vector(31 downto 0);
+ signal buffer_tvalid : std_logic;
+ signal buffer_tlast : std_logic;
+
+ -- branch signals
+ signal branch_tvalid : std_logic_vector(NUMBER_BRANCH_UNITS - 1 downto 0);
+ signal branch_tdata : t_branch;
+ signal branch_tlast : std_logic_vector(NUMBER_BRANCH_UNITS - 1 downto 0);
+ signal branch_tready : std_logic_vector(NUMBER_BRANCH_UNITS - 1 downto 0);
+
+ -- acs signals
+ signal acs_tvalid : std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);
+ signal acs_tlast : std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);
+ signal acs_tready : std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);
+ signal acs_dec_tdata : std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);
+ signal acs_prob_tdata : t_node;
+
+ -- ram signals
+ signal ram_tready : std_logic;
+ signal ram_tvalid, ram_tlast, ram_window_tuser, ram_last_tuser : std_logic_vector(1 downto 0);
+ signal ram_tdata : t_ram_rd_data;
+
+ -- traceback signals
+ signal traceback_tvalid, traceback_tdata : std_logic_vector(1 downto 0);
+ signal traceback_tready, traceback_tlast : std_logic_vector(1 downto 0);
+ signal traceback_last_tuser : std_logic_vector(1 downto 0);
+
+ -- reorder signals
+ signal reorder_tready, reorder_tvalid : std_logic_vector(1 downto 0);
+ signal reorder_tdata, reorder_tlast : std_logic_vector(1 downto 0);
+ signal reorder_last_tuser : std_logic_vector(1 downto 0);
+
+ -- output signals
+ signal output_tready : std_logic_vector(1 downto 0);
+ signal current_active : integer range 1 downto 0;
+
+begin
+
+ --
+ -- There is always one byte of data for each LLR value, even though each
+ -- LLR value is represented with BW_LLR_INPUT bits. Hence, only
+ -- BW_LLR_INPUT bits are extracted from the byte.
+ --
+ gen_input_assignment: for i in NUMBER_PARITY_BITS - 1 downto 0 generate
+ begin
+ input(i) <= signed(buffer_tdata(8 * i + BW_LLR_INPUT - 1 downto 8 * i));
+ end generate gen_input_assignment;
+
+ rst <= not aresetn;
+
+ ------------------------------
+ --- Portmapping components ---
+ ------------------------------
+
+ -------------------------------------
+ -- AXI4S input buffer
+ --------------------------------------
+
+ inst_axi4s_buffer: axi4s_buffer
+ generic map(
+ DATA_WIDTH => 32
+ )
+ port map(
+ clk => clk,
+ rst => rst,
+
+ input => s_axis_input_tdata,
+ input_valid => s_axis_input_tvalid,
+ input_last => s_axis_input_tlast,
+ input_accept => s_axis_input_tready,
+
+ output => buffer_tdata,
+ output_valid => buffer_tvalid,
+ output_last => buffer_tlast,
+ output_accept => branch_tready(0)
+ );
+
+ -------------------------------------
+ -- Branch metric unit
+ --------------------------------------
+
+ gen_branch_distance : for i in NUMBER_BRANCH_UNITS - 1 downto 0 generate
+ begin
+ inst_branch_distance : branch_distance
+ generic map(
+ EDGE_WEIGHT => std_logic_vector(to_unsigned(i, NUMBER_PARITY_BITS))
+ )
+ port map(
+ clk => clk,
+ rst => rst,
+
+ s_axis_input_tvalid => buffer_tvalid,
+ s_axis_input_tdata => input,
+ s_axis_input_tlast => buffer_tlast,
+ s_axis_input_tready => branch_tready(i),
+
+ m_axis_output_tvalid => branch_tvalid(i),
+ m_axis_output_tdata => branch_tdata(i),
+ m_axis_output_tlast => branch_tlast(i),
+ m_axis_output_tready => acs_tready(0)
+ );
+ end generate gen_branch_distance;
+
+
+ -------------------------------------
+ -- ACS unit (path metric calculation)
+ --------------------------------------
+
+ gen_acs : for i in 0 to NUMBER_TRELLIS_STATES - 1 generate
+ signal inbranch_tdata_low : std_logic_vector(BW_BRANCH_RESULT - 1 downto 0);
+ signal inbranch_tdata_high : std_logic_vector(BW_BRANCH_RESULT - 1 downto 0);
+ signal inprev_tdata_low : std_logic_vector(BW_MAX_PROBABILITY - 1 downto 0);
+ signal inprev_tdata_high : std_logic_vector(BW_MAX_PROBABILITY - 1 downto 0);
+ begin
+ inbranch_tdata_low <= branch_tdata(to_integer(unsigned(TRANSITIONS(i)(0))));
+ inbranch_tdata_high <= branch_tdata(to_integer(unsigned(TRANSITIONS(i)(1))));
+ inprev_tdata_low <= acs_prob_tdata(to_integer(unsigned(PREVIOUS_STATES(i)(0))));
+ inprev_tdata_high <= acs_prob_tdata(to_integer(unsigned(PREVIOUS_STATES(i)(1))));
+
+ inst_acs : acs
+ generic map(
+ initialize_value => INITIALIZE_TRELLIS(i)
+ )
+ port map(
+ clk => clk,
+ rst => rst,
+
+ s_axis_inbranch_tvalid => branch_tvalid(0),
+ s_axis_inbranch_tdata_low => inbranch_tdata_low,
+ s_axis_inbranch_tdata_high => inbranch_tdata_high,
+ s_axis_inbranch_tlast => branch_tlast(0),
+ s_axis_inbranch_tready => acs_tready(i),
+
+ s_axis_inprev_tvalid => '1',
+ s_axis_inprev_tdata_low => inprev_tdata_low,
+ s_axis_inprev_tdata_high => inprev_tdata_high,
+ s_axis_inprev_tready => open,
+
+ m_axis_outprob_tvalid => open,
+ m_axis_outprob_tdata => acs_prob_tdata(i),
+ m_axis_outprob_tready => '1',
+
+ m_axis_outdec_tvalid => acs_tvalid(i),
+ m_axis_outdec_tdata => acs_dec_tdata(i),
+ m_axis_outdec_tlast => acs_tlast(i),
+ m_axis_outdec_tready => ram_tready
+ );
+ end generate gen_acs;
+
+
+ -------------------------------
+ -- Traceback
+ -------------------------------
+
+ inst_ram_ctrl : ram_ctrl
+ port map (
+ clk => clk,
+ rst => rst,
+
+ s_axis_input_tvalid => acs_tvalid(0),
+ s_axis_input_tdata => acs_dec_tdata,
+ s_axis_input_tlast => acs_tlast(0),
+ s_axis_input_tready => ram_tready,
+
+ m_axis_output_tvalid => ram_tvalid,
+ m_axis_output_tdata => ram_tdata,
+ m_axis_output_tlast => ram_tlast,
+ m_axis_output_tready => traceback_tready,
+ m_axis_output_window_tuser => ram_window_tuser,
+ m_axis_output_last_tuser => ram_last_tuser,
+
+ s_axis_ctrl_tvalid => s_axis_ctrl_tvalid,
+ s_axis_ctrl_tdata => s_axis_ctrl_tdata,
+ s_axis_ctrl_tready => s_axis_ctrl_tready
+ );
+
+
+ gen_inst_trellis_traceback : for i in 1 downto 0 generate
+ begin
+ inst_trellis_traceback : trellis_traceback
+ port map(
+ clk => clk,
+ rst => rst,
+
+ s_axis_input_tvalid => ram_tvalid(i),
+ s_axis_input_tdata => ram_tdata(i),
+ s_axis_input_tlast => ram_tlast(i),
+ s_axis_input_tready => traceback_tready(i),
+ s_axis_input_window_tuser => ram_window_tuser(i),
+ s_axis_input_last_tuser => ram_last_tuser(i),
+
+ m_axis_output_tvalid => traceback_tvalid(i),
+ m_axis_output_tdata => traceback_tdata(i),
+ m_axis_output_tlast => traceback_tlast(i),
+ m_axis_output_last_tuser => traceback_last_tuser(i),
+ m_axis_output_tready => reorder_tready(i)
+ );
+ end generate gen_inst_trellis_traceback;
+
+
+ -------------------------------
+ -- Reverse output order
+ -------------------------------
+
+ gen_inst_reorder : for i in 1 downto 0 generate
+ begin
+ inst_reorder : reorder
+ port map(
+ clk => clk,
+ rst => rst,
+
+ s_axis_input_tvalid => traceback_tvalid(i),
+ s_axis_input_tdata => traceback_tdata(i),
+ s_axis_input_tlast => traceback_tlast(i),
+ s_axis_input_last_tuser => traceback_last_tuser(i),
+ s_axis_input_tready => reorder_tready(i),
+
+ m_axis_output_tvalid => reorder_tvalid(i),
+ m_axis_output_tdata => reorder_tdata(i),
+ m_axis_output_tlast => reorder_tlast(i),
+ m_axis_output_last_tuser => reorder_last_tuser(i),
+ m_axis_output_tready => output_tready(i)
+ );
+ end generate gen_inst_reorder;
+
+
+ ------------------------------
+ -- Recursive codes handling --
+ ------------------------------
+
+ gen_inst_recursion : if FEEDBACK_POLYNOMIAL /= 0 generate
+ signal reorder_recursion_tvalid : std_logic;
+ signal reorder_recursion_tdata : std_logic;
+ signal reorder_recursion_tlast : std_logic;
+ signal recursion_tready : std_logic;
+ begin
+ inst_recursion : recursionx
+ port map(
+ clk => clk,
+ rst => rst,
+
+ s_axis_input_tvalid => reorder_recursion_tvalid,
+ s_axis_input_tdata => reorder_recursion_tdata,
+ s_axis_input_tlast => reorder_recursion_tlast,
+ s_axis_input_tready => recursion_tready,
+
+ m_axis_output_tvalid => m_axis_output_tvalid,
+ m_axis_output_tdata => m_axis_output_tdata,
+ m_axis_output_tlast => m_axis_output_tlast,
+ m_axis_output_tready => m_axis_output_tready
+ );
+
+ -------------------------------
+ -- Output interface handling
+ -------------------------------
+
+ reorder_recursion_tvalid <= '1' when reorder_tvalid(0) = '1' or reorder_tvalid(1) = '1' else
+ '0';
+
+ reorder_recursion_tdata <= reorder_tdata(0) when current_active = 0 else
+ reorder_tdata(1);
+
+ reorder_recursion_tlast <= '1' when reorder_tlast(0) = '1' or reorder_tlast(1) = '1' else
+ '0';
+
+ output_tready(0) <= '1' when (current_active = 0) and m_axis_output_tready = '1' else
+ '0';
+ output_tready(1) <= '1' when (current_active = 1) and m_axis_output_tready = '1' else
+ '0';
+ end generate gen_inst_recursion;
+
+
+
+ no_recursion: if FEEDBACK_POLYNOMIAL = 0 generate
+
+ -------------------------------
+ -- Output interface handling
+ -------------------------------
+
+ m_axis_output_tdata <= reorder_tdata(0) when current_active = 0 else
+ reorder_tdata(1);
+
+ m_axis_output_tvalid <= '1' when reorder_tvalid(0) = '1' or reorder_tvalid(1) = '1' else
+ '0';
+
+ m_axis_output_tlast <= '1' when reorder_tlast(0) = '1' or reorder_tlast(1) = '1' else
+ '0';
+
+ output_tready(0) <= '1' when (current_active = 0) and m_axis_output_tready = '1' else
+ '0';
+ output_tready(1) <= '1' when (current_active = 1) and m_axis_output_tready = '1' else
+ '0';
+ end generate no_recursion;
+
+
+ recursion : if FEEDBACK_POLYNOMIAL /= 0 generate
+ begin
+ end generate recursion;
+
+
+ -- Check and merge reordering outputs and block if necessary.
+ pr_reorder_tready : process(clk) is
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ current_active <= 0;
+ else
+ if reorder_tvalid(current_active) = '1' and m_axis_output_tready = '1' and reorder_last_tuser(current_active) = '1' then
+ current_active <= 1 - current_active;
+ end if;
+ end if;
+ end if;
+ end process pr_reorder_tready;
+
+end architecture rtl;
diff --git a/testsuite/gna/issue301/src/generic_sp_ram.vhd b/testsuite/gna/issue301/src/generic_sp_ram.vhd
new file mode 100644
index 000000000..a418ad54d
--- /dev/null
+++ b/testsuite/gna/issue301/src/generic_sp_ram.vhd
@@ -0,0 +1,90 @@
+--!
+--! Copyright (C) 2010 - 2012 Creonic GmbH
+--!
+--! This file is part of the Creonic Viterbi Decoder, which is distributed
+--! under the terms of the GNU General Public License version 2.
+--!
+--! @file
+--! @brief Generic single port RAM with a single read/write port
+--! @author Matthias Alles
+--! @date 2010/09/28
+--!
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library dec_viterbi;
+use dec_viterbi.pkg_helper.all;
+
+
+entity generic_sp_ram is
+ generic(
+ DISTR_RAM : boolean := false;
+ WORDS : integer := 8;
+ BITWIDTH : integer := 8
+ );
+ port(
+ clk : in std_logic;
+ rst : in std_logic;
+
+ wen : in std_logic;
+ en : in std_logic;
+
+ a : in std_logic_vector(no_bits_natural(WORDS - 1) - 1 downto 0);
+ d : in std_logic_vector(BITWIDTH - 1 downto 0);
+ q : out std_logic_vector(BITWIDTH - 1 downto 0)
+ );
+end generic_sp_ram;
+
+
+architecture rtl of generic_sp_ram is
+
+ type t_ram is array(WORDS - 1 downto 0) of
+ std_logic_vector(BITWIDTH - 1 downto 0);
+ signal sp_ram : t_ram := (others => (others => '0'));
+
+ function get_ram_style_xilinx(dist_ram : in boolean) return string is
+ begin
+ if dist_ram then
+ return "pipe_distributed";
+ else
+ return "block";
+ end if;
+ end function;
+
+ function get_ram_style_altera(dist_ram : in boolean) return string is
+ begin
+ if dist_ram then
+ return "MLAB, no_rw_check";
+ else
+ return "AUTO";
+ end if;
+ end function;
+
+ attribute RAM_STYLE : string;
+ attribute RAM_STYLE of sp_ram : signal is get_ram_style_xilinx(DISTR_RAM);
+
+ attribute ramstyle : string;
+ attribute ramstyle of sp_ram : signal is get_ram_style_altera(DISTR_RAM);
+
+begin
+
+ --
+ -- Do not register the address for reading, since the synthesis doesn't
+ -- recognize then that this is a single-port RAM.
+ --
+ pr_sp_ram_rw: process(clk)
+ begin
+ if rising_edge(clk) then
+ if en = '1' then
+ if wen = '1' then
+ sp_ram(to_integer(UNSIGNED(a))) <= d;
+ else
+ q <= sp_ram(to_integer(UNSIGNED(a)));
+ end if;
+ end if;
+ end if;
+ end process pr_sp_ram_rw;
+
+end rtl;
diff --git a/testsuite/gna/issue301/src/ram_ctrl.vhd b/testsuite/gna/issue301/src/ram_ctrl.vhd
new file mode 100644
index 000000000..712738811
--- /dev/null
+++ b/testsuite/gna/issue301/src/ram_ctrl.vhd
@@ -0,0 +1,474 @@
+--!
+--! Copyright (C) 2011 - 2014 Creonic GmbH
+--!
+--! This file is part of the Creonic Viterbi Decoder, which is distributed
+--! under the terms of the GNU General Public License version 2.
+--!
+--! @file
+--! @brief Viterbi decoder RAM control
+--! @author Markus Fehrenz
+--! @date 2011/12/13
+--!
+--! @details Manage RAM behavior. Write and read data.
+--! The decisions are sent to the traceback units
+--! It is signaled if the data belongs to acquisition or window phase.
+--!
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library dec_viterbi;
+use dec_viterbi.pkg_param.all;
+use dec_viterbi.pkg_param_derived.all;
+use dec_viterbi.pkg_types.all;
+use dec_viterbi.pkg_components.all;
+
+
+entity ram_ctrl is
+ port(
+ clk : in std_logic;
+ rst : in std_logic;
+
+
+ --
+ -- Slave data signals, delivers the LLR parity values.
+ --
+ s_axis_input_tvalid : in std_logic;
+ s_axis_input_tdata : in std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);
+ s_axis_input_tlast : in std_logic;
+ s_axis_input_tready : out std_logic;
+
+
+ --
+ -- Master data signals for traceback units, delivers the decision vectors.
+ --
+ m_axis_output_tvalid : out std_logic_vector(1 downto 0);
+ m_axis_output_tdata : out t_ram_rd_data;
+ m_axis_output_tlast : out std_logic_vector(1 downto 0);
+ m_axis_output_tready : in std_logic_vector(1 downto 0);
+
+ -- Signals the traceback unit when the decision bits do not belong to an acquisition.
+ m_axis_output_window_tuser : out std_logic_vector(1 downto 0);
+
+ -- Signals whether this is the last decision vector of the window.
+ m_axis_output_last_tuser : out std_logic_vector(1 downto 0);
+
+
+ --
+ -- Slave configuration signals, delivering the configuration data.
+ --
+
+ s_axis_ctrl_tvalid : in std_logic;
+ s_axis_ctrl_tdata : in std_logic_vector(31 downto 0);
+ s_axis_ctrl_tready : out std_logic
+);
+end entity ram_ctrl;
+
+
+architecture rtl of ram_ctrl is
+
+ ------------------------
+ -- Type definition
+ ------------------------
+
+ --
+ -- Record contains runtime configuration.
+ -- The input configuration is stored in a register.
+ -- It is received from a AXI4-Stream interface from the top entity.
+ --
+ type trec_runtime_param is record
+ window_length : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
+ acquisition_length : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
+ end record trec_runtime_param;
+
+ -- Types for finite state machines
+ type t_write_ram_fsm is (CONFIGURE, START, RUN, WAIT_FOR_TRACEBACK, WAIT_FOR_LAST_TRACEBACK);
+ type t_read_ram_fsm is (WAIT_FOR_WINDOW, TRACEBACK, WAIT_FOR_RAM, FINISH);
+ type t_read_ram_fsm_array is array (0 to 1) of t_read_ram_fsm;
+
+ -- RAM controling types
+ type t_ram_data is array (3 downto 0) of std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);
+ type t_ram_addr is array (3 downto 0) of unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
+ type t_ram_rd_addr is array (1 downto 0) of unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
+ type t_ram_ptr is array (1 downto 0) of unsigned(1 downto 0);
+ type t_ram_ptr_int is array (1 downto 0) of integer range 3 downto 0;
+
+ type t_ram_data_cnt is array (1 downto 0) of integer range 2 * MAX_WINDOW_LENGTH downto 0;
+
+
+ ------------------------
+ -- Signal declaration
+ ------------------------
+
+ signal ram_buffer : t_ram_rd_data;
+ signal ram_buffer_full : std_logic_vector(1 downto 0);
+
+ signal config : trec_runtime_param;
+ signal write_ram_fsm : t_write_ram_fsm;
+ signal read_ram_fsm : t_read_ram_fsm_array;
+ signal wen_ram : std_logic_vector(3 downto 0);
+ signal addr : t_ram_addr;
+ signal q_reg : t_ram_data;
+
+ -- ram addess, number and data pointer
+ signal write_ram_ptr : unsigned(1 downto 0);
+ signal read_ram_ptr : t_ram_ptr;
+ signal read_ram_ptr_d : t_ram_ptr;
+ signal write_addr_ptr : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
+ signal read_addr_ptr : t_ram_rd_addr;
+
+ -- internal signals of outputs
+ signal m_axis_output_tvalid_int : std_logic_vector(1 downto 0);
+ signal m_axis_output_tlast_int : std_logic_vector(1 downto 0);
+ signal m_axis_output_window_tuser_int : std_logic_vector(1 downto 0);
+ signal m_axis_output_last_tuser_int : std_logic_vector(1 downto 0);
+ signal s_axis_input_tready_int : std_logic;
+ signal s_axis_ctrl_tready_int : std_logic;
+
+ signal next_traceback : std_logic_vector(1 downto 0);
+ signal write_window_complete : std_logic;
+ signal write_last_window_complete : std_logic;
+ signal last_of_block : std_logic;
+ signal read_last_addr_ptr : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
+begin
+
+ m_axis_output_tvalid <= m_axis_output_tvalid_int;
+ m_axis_output_tlast <= m_axis_output_tlast_int;
+ m_axis_output_window_tuser <= m_axis_output_window_tuser_int;
+ m_axis_output_last_tuser <= m_axis_output_last_tuser_int;
+ m_axis_output_tdata(0) <= q_reg(to_integer(read_ram_ptr_d(0))) when ram_buffer_full(0) = '0' else ram_buffer(0);
+ m_axis_output_tdata(1) <= q_reg(to_integer(read_ram_ptr_d(1))) when ram_buffer_full(1) = '0' else ram_buffer(1);
+
+
+ --
+ -- When the output port is not ready to read the output of the RAM immediately
+ -- we have to remember the output value of the RAM in an extra register.
+ -- When the output is ready to read, we first use the ouput of the register
+ -- and only then the output of the RAM again.
+ --
+ pr_buf_ram_output: process(clk) is
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ ram_buffer <= (others => (others => '0'));
+ ram_buffer_full <= (others => '0');
+ else
+
+ for i in 0 to 1 loop
+ if m_axis_output_tvalid_int(i) = '1' and m_axis_output_tready(i) = '0' and ram_buffer_full(i) = '0' then
+ ram_buffer(i) <= q_reg(to_integer(read_ram_ptr_d(i)));
+ ram_buffer_full(i) <= '1';
+ end if;
+
+ if m_axis_output_tvalid_int(i) = '1' and m_axis_output_tready(i) = '1' and ram_buffer_full(i) = '1' then
+ ram_buffer_full(i) <= '0';
+ end if;
+ end loop;
+
+ end if;
+ end if;
+ end process pr_buf_ram_output;
+
+ -----------------------------
+ -- Manage writing from ACS --
+ -----------------------------
+ s_axis_input_tready_int <= '0' when (write_ram_fsm = CONFIGURE) or
+ (write_ram_ptr = read_ram_ptr(0) and read_ram_fsm(0) /= WAIT_FOR_WINDOW) or
+ (write_ram_ptr = read_ram_ptr(1) and read_ram_fsm(1) /= WAIT_FOR_WINDOW) or
+ write_ram_fsm = WAIT_FOR_TRACEBACK or write_ram_fsm = WAIT_FOR_LAST_TRACEBACK else
+ '1';
+ s_axis_input_tready <= s_axis_input_tready_int;
+
+ s_axis_ctrl_tready_int <= '1' when (read_ram_fsm(0) = WAIT_FOR_WINDOW and read_ram_fsm(1) = WAIT_FOR_WINDOW and write_ram_fsm = CONFIGURE) else
+ '0';
+ s_axis_ctrl_tready <= s_axis_ctrl_tready_int;
+
+ -- Process for writing to the RAM
+ pr_write_ram: process(clk) is
+ variable v_window_length : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
+ variable v_acquisition_length : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ write_ram_fsm <= CONFIGURE;
+ write_addr_ptr <= (others => '0');
+ write_ram_ptr <= (others => '0');
+ wen_ram <= (others => '0');
+ write_window_complete <= '0';
+ write_last_window_complete <= '0';
+ read_last_addr_ptr <= (others => '0');
+ else
+
+ case write_ram_fsm is
+
+ --
+ -- It is necessary to configure the decoder before each block
+ --
+ when CONFIGURE =>
+ write_window_complete <= '0';
+ write_last_window_complete <= '0';
+ if s_axis_ctrl_tvalid = '1' and s_axis_ctrl_tready_int = '1' then
+ v_window_length := unsigned(s_axis_ctrl_tdata(BW_MAX_WINDOW_LENGTH - 1 + 16 downto 16));
+ v_acquisition_length := unsigned(s_axis_ctrl_tdata(BW_MAX_WINDOW_LENGTH - 1 downto 0));
+ write_addr_ptr <= v_window_length - v_acquisition_length;
+ config.window_length <= v_window_length;
+ config.acquisition_length <= v_acquisition_length;
+ write_ram_fsm <= START;
+
+ wen_ram(to_integer(write_ram_ptr)) <= '1';
+ end if;
+
+
+ --
+ -- After the decoder is configured, the decoder is waiting for a new block.
+ -- When the AXIS handshake is there the packet transmission begins.
+ -- The first write is a special case, since writing data starts at the acquisition length.
+ -- There is no complete window available afterwards.
+ --
+ when START =>
+ if s_axis_input_tvalid = '1' and s_axis_input_tready_int = '1' then
+
+ if write_addr_ptr = config.window_length - 1 then
+
+ -- When we switch to the next RAM, we reset the write addr.
+ write_addr_ptr <= (others => '0');
+
+ -- Switch to the next RAM.
+ write_ram_ptr <= write_ram_ptr + 1;
+ wen_ram(to_integer(write_ram_ptr)) <= '0';
+ wen_ram(to_integer(write_ram_ptr + 1)) <= '1';
+
+ write_ram_fsm <= RUN;
+ else
+ write_addr_ptr <= write_addr_ptr + 1;
+ end if;
+ end if;
+
+
+ --
+ -- The decoder is receiving data from the ACS.
+ --
+ when RUN =>
+ write_window_complete <= '0';
+ write_last_window_complete <= '0';
+
+ if s_axis_input_tvalid = '1' and s_axis_input_tready_int = '1' then
+ write_addr_ptr <= write_addr_ptr + 1;
+
+ if write_addr_ptr = config.window_length - 1 then
+
+ -- When we switch to the next RAM, we reset the write addr.
+ write_addr_ptr <= (others => '0');
+
+ -- Switch to the next RAM.
+ write_ram_ptr <= write_ram_ptr + 1;
+ wen_ram(to_integer(write_ram_ptr)) <= '0';
+ wen_ram(to_integer(write_ram_ptr + 1)) <= '1';
+
+ -- Indicate, that a complete window is within the RAM and traceback may start.
+ write_window_complete <= '1';
+
+ if read_ram_fsm(0) /= WAIT_FOR_WINDOW and read_ram_fsm(1) /= WAIT_FOR_WINDOW then
+ write_ram_fsm <= WAIT_FOR_TRACEBACK;
+ end if;
+
+ else
+ write_addr_ptr <= write_addr_ptr + 1;
+ end if;
+
+ if s_axis_input_tlast = '1' then
+ write_ram_fsm <= CONFIGURE;
+ wen_ram <= (others => '0');
+
+ write_last_window_complete <= '1';
+ if (read_ram_fsm(0) /= WAIT_FOR_WINDOW and read_ram_fsm(1) /= WAIT_FOR_WINDOW) or write_window_complete = '1' then
+ write_ram_fsm <= WAIT_FOR_LAST_TRACEBACK;
+ end if;
+ read_last_addr_ptr <= write_addr_ptr;
+
+ write_addr_ptr <= (others => '0');
+ write_ram_ptr <= write_ram_ptr + 1;
+ end if;
+ end if;
+
+ when WAIT_FOR_TRACEBACK =>
+ if read_ram_fsm(0) = WAIT_FOR_WINDOW or read_ram_fsm(1) = WAIT_FOR_WINDOW then
+ write_ram_fsm <= RUN;
+ write_window_complete <= '0';
+ end if;
+
+ when WAIT_FOR_LAST_TRACEBACK =>
+ if read_ram_fsm(0) = WAIT_FOR_WINDOW or read_ram_fsm(1) = WAIT_FOR_WINDOW then
+ write_ram_fsm <= CONFIGURE;
+ write_last_window_complete <= '0';
+ end if;
+
+ end case;
+ end if;
+ end if;
+ end process pr_write_ram;
+
+
+ -------------------------------------------
+ -- Manage reading from RAM for traceback --
+ -------------------------------------------
+
+ gen_read_ram: for i in 0 to 1 generate
+ pr_read_ram: process(clk) is
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ read_addr_ptr(i) <= (others => '0');
+ read_ram_fsm(i) <= WAIT_FOR_WINDOW;
+ m_axis_output_tvalid_int(i) <= '0';
+ m_axis_output_tlast_int(i) <= '0';
+ m_axis_output_window_tuser_int(i) <= '0';
+ m_axis_output_last_tuser_int(i) <= '0';
+ read_ram_ptr(i) <= (others => '0');
+ read_ram_ptr_d(i) <= (others => '0');
+ else
+
+ read_ram_ptr_d(i) <= read_ram_ptr(i);
+ case read_ram_fsm(i) is
+
+ -- Wait for the next window to be ready within the RAM.
+ when WAIT_FOR_WINDOW =>
+ read_addr_ptr(i) <= config.window_length - 1;
+ m_axis_output_tlast_int(i) <= '0';
+ m_axis_output_tvalid_int(i) <= '0';
+ m_axis_output_last_tuser_int(i) <= '0';
+ m_axis_output_window_tuser_int(i) <= '0';
+ read_ram_ptr(i) <= write_ram_ptr;
+
+ -- We always start from the RAM, which was written last.
+ if write_window_complete = '1' and next_traceback(i) = '1' then
+ read_ram_ptr(i) <= write_ram_ptr - 1;
+ read_addr_ptr(i) <= read_addr_ptr(i) - 1;
+ read_ram_fsm(i) <= TRACEBACK;
+ m_axis_output_tvalid_int(i) <= '1';
+ end if;
+ if write_last_window_complete = '1' and next_traceback(i) = '1' then
+ read_ram_ptr(i) <= write_ram_ptr - 1;
+ read_addr_ptr(i) <= read_last_addr_ptr;
+ read_ram_fsm(i) <= TRACEBACK;
+ m_axis_output_window_tuser_int(i) <= '1';
+ end if;
+
+ -- Perform the Traceback on the RAM data of the first RAM we need for acquisition and traceback.
+ when TRACEBACK =>
+ m_axis_output_tlast_int(i) <= '0';
+ m_axis_output_last_tuser_int(i) <= '0';
+ m_axis_output_tvalid_int(i) <= '1';
+
+ if m_axis_output_tready(i) = '1' then
+ if read_addr_ptr(i) = 0 then
+ if read_ram_fsm(1 - i) = TRACEBACK and read_ram_ptr(1 - i) = read_ram_ptr(i) - 1 then
+ read_ram_fsm(i) <= WAIT_FOR_RAM;
+ else
+ read_addr_ptr(i) <= config.window_length - 1;
+ read_ram_ptr(i) <= read_ram_ptr(i) - 1;
+ read_ram_fsm(i) <= FINISH;
+ end if;
+ else
+ read_addr_ptr(i) <= read_addr_ptr(i) - 1;
+ end if;
+
+ -- Signal the traceback unit, acquisition is over.
+ if read_addr_ptr(i) = config.window_length - config.acquisition_length - 1 then
+ m_axis_output_window_tuser_int(i) <= '1';
+ end if;
+ end if;
+
+ when WAIT_FOR_RAM =>
+ m_axis_output_tvalid_int(i) <= '0';
+ if read_ram_fsm(1 - i) /= TRACEBACK or read_ram_ptr(1 - i) /= read_ram_ptr(i) - 1 then
+ read_addr_ptr(i) <= config.window_length - 1;
+ read_ram_ptr(i) <= read_ram_ptr(i) - 1;
+ read_ram_fsm(i) <= FINISH;
+ end if;
+
+ -- Get the remaining values from the second RAM we need for traceback (no acquisition values in this RAM)
+ when FINISH =>
+ if m_axis_output_tvalid_int(i) <= '0' then
+ m_axis_output_tvalid_int(i) <= '1';
+ read_addr_ptr(i) <= read_addr_ptr(i) - 1;
+ end if;
+ if m_axis_output_tready(i) = '1' then
+
+ if read_addr_ptr(i) = config.window_length - config.acquisition_length then
+ m_axis_output_last_tuser_int(i) <= '1';
+ read_addr_ptr(i) <= config.window_length - 1;
+ read_ram_fsm(i) <= WAIT_FOR_WINDOW;
+
+ -- Check if the other read process finished processing.
+ if read_ram_fsm((i+1) mod 2) = WAIT_FOR_WINDOW and last_of_block = '1' then
+ m_axis_output_tlast_int(i) <= '1';
+ end if;
+
+ else
+ read_addr_ptr(i) <= read_addr_ptr(i) - 1;
+ end if;
+ end if;
+ end case;
+ end if;
+ end if;
+ end process pr_read_ram;
+ end generate gen_read_ram;
+
+ -- This process decides which traceback unit is the next one to use.
+ pr_next_traceback: process(clk) is
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ next_traceback <= "01";
+ last_of_block <= '0';
+ else
+ if write_window_complete = '1' then
+ if next_traceback(0) = '1' then
+ next_traceback(0) <= '0';
+ next_traceback(1) <= '1';
+ else
+ next_traceback(0) <= '1';
+ next_traceback(1) <= '0';
+ end if;
+ end if;
+
+ if s_axis_input_tlast = '1' then
+ last_of_block <= '1';
+ end if;
+
+ end if;
+ end if;
+ end process pr_next_traceback;
+
+ ------------------------------
+ --- Portmapping components ---
+ ------------------------------
+
+ gen_generic_sp_ram : for i in 0 to 3 generate
+ begin
+
+ addr(i) <= write_addr_ptr when (write_ram_fsm = RUN or write_ram_fsm = START) and to_integer(write_ram_ptr) = i else
+ read_addr_ptr(0) when (to_integer(read_ram_ptr(0)) = i and (read_ram_fsm(0) = TRACEBACK or read_ram_fsm(0) = WAIT_FOR_RAM or read_ram_fsm(0) = FINISH)) or
+ (next_traceback(0) = '1' and write_window_complete = '1' and to_integer(read_ram_ptr(0)) = i) else
+ read_addr_ptr(1);
+
+ inst_generic_sp_ram : generic_sp_ram
+ generic map(
+ DISTR_RAM => DISTRIBUTED_RAM,
+ WORDS => MAX_WINDOW_LENGTH,
+ BITWIDTH => NUMBER_TRELLIS_STATES
+ )
+ port map(
+ clk => clk,
+ rst => rst,
+ wen => wen_ram(i),
+ en => '1',
+ a => std_logic_vector(addr(i)),
+ d => s_axis_input_tdata,
+ q => q_reg(i)
+ );
+ end generate gen_generic_sp_ram;
+
+end architecture rtl;
diff --git a/testsuite/gna/issue301/src/recursion.vhd b/testsuite/gna/issue301/src/recursion.vhd
new file mode 100644
index 000000000..932058653
--- /dev/null
+++ b/testsuite/gna/issue301/src/recursion.vhd
@@ -0,0 +1,96 @@
+--!
+--! Copyright (C) 2011 - 2014 Creonic GmbH
+--!
+--! This file is part of the Creonic Viterbi Decoder, which is distributed
+--! under the terms of the GNU General Public License version 2.
+--!
+--! @file
+--! @brief Recursion unit for recursive code.
+--! @author Markus Fehrenz
+--! @date 2011/01/12
+--!
+--! @details The recusion handling buffers the reorder ouput and
+--! calculates the correct output depending on the feedback polynomial.
+--!
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library dec_viterbi;
+use dec_viterbi.pkg_param.all;
+use dec_viterbi.pkg_param_derived.all;
+
+entity recursionx is
+ port(
+ clk : in std_logic;
+ rst : in std_logic;
+
+ --
+ -- Decoded bits input from the reordering units in std_logic
+ --
+ s_axis_input_tvalid : in std_logic;
+ s_axis_input_tdata : in std_logic;
+ s_axis_input_tlast : in std_logic;
+ s_axis_input_tready : out std_logic;
+
+ --
+ -- Output decoded bits convolved with the feedback polynomial
+ --
+ m_axis_output_tvalid : out std_logic;
+ m_axis_output_tdata : out std_logic;
+ m_axis_output_tlast : out std_logic;
+ m_axis_output_tready : in std_logic
+ );
+end entity recursionx;
+
+architecture rtl of recursionx is
+ signal recursion_sreg : unsigned(ENCODER_MEMORY_DEPTH downto 0);
+ signal s_axis_input_tready_int : std_logic;
+ signal m_axis_output_tvalid_int : std_logic;
+
+begin
+ s_axis_input_tready_int <= '1' when m_axis_output_tready = '1' or m_axis_output_tvalid_int = '0' else
+ '0';
+
+ s_axis_input_tready <= s_axis_input_tready_int;
+ m_axis_output_tvalid <= m_axis_output_tvalid_int;
+
+ -- Use the feedback polynomial to convolve the global path.
+ pr_recursion : process(clk) is
+ variable v_bit : std_logic := '0';
+ variable v_recursion_state : unsigned(ENCODER_MEMORY_DEPTH downto 0);
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ recursion_sreg <= (others => '0');
+ m_axis_output_tdata <= '0';
+ m_axis_output_tlast <= '0';
+ else
+ m_axis_output_tvalid_int <= s_axis_input_tvalid;
+
+ if s_axis_input_tvalid = '1' and s_axis_input_tready_int = '1' then
+
+ -- move current decoded output bits into shift register and reset if last flag is valid
+ if s_axis_input_tlast = '1' then
+ recursion_sreg <= (others => '0');
+ else
+ recursion_sreg <= s_axis_input_tdata & recursion_sreg(ENCODER_MEMORY_DEPTH downto 1);
+ end if;
+
+ -- convolve with feedback polynomial with the output register.
+ v_bit := '0';
+ v_recursion_state := (s_axis_input_tdata & recursion_sreg(ENCODER_MEMORY_DEPTH downto 1)) and
+ ('1' & to_unsigned(FEEDBACK_POLYNOMIAL, ENCODER_MEMORY_DEPTH));
+ for i in ENCODER_MEMORY_DEPTH downto 0 loop
+ v_bit := v_bit xor v_recursion_state(i);
+ end loop;
+ m_axis_output_tdata <= v_bit;
+
+ m_axis_output_tlast <= s_axis_input_tlast;
+ end if;
+ end if;
+ end if;
+ end process pr_recursion;
+
+end architecture rtl;
diff --git a/testsuite/gna/issue301/src/reorder.vhd b/testsuite/gna/issue301/src/reorder.vhd
new file mode 100644
index 000000000..c29069098
--- /dev/null
+++ b/testsuite/gna/issue301/src/reorder.vhd
@@ -0,0 +1,129 @@
+--!
+--! Copyright (C) 2011 - 2014 Creonic GmbH
+--!
+--! This file is part of the Creonic Viterbi Decoder, which is distributed
+--! under the terms of the GNU General Public License version 2.
+--!
+--! @file
+--! @brief Reorder twisted output due to windowing
+--! @author Markus Fehrenz
+--! @date 2011/05/12
+--!
+--! @details The windowing output is twisted.
+--! The correct order is simply rebuilt by reversing
+--! the output of each traceback unit.
+--!
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library dec_viterbi;
+use dec_viterbi.pkg_param.all;
+use dec_viterbi.pkg_param_derived.all;
+use dec_viterbi.pkg_types.all;
+
+
+entity reorder is
+ port(
+ clk : in std_logic;
+ rst : in std_logic;
+
+ --
+ -- Traceback unit output, twisted order
+ --
+ s_axis_input_tvalid : in std_logic;
+ s_axis_input_tdata : in std_logic;
+ s_axis_input_tlast : in std_logic;
+ s_axis_input_last_tuser : in std_logic;
+ s_axis_input_tready : out std_logic;
+
+ --
+ -- Viterbi decoder output, original (input) order.
+ --
+ m_axis_output_tvalid : out std_logic;
+ m_axis_output_tdata : out std_logic;
+ m_axis_output_tlast : out std_logic;
+ m_axis_output_last_tuser : out std_logic; -- Last bit of one traceback window
+ m_axis_output_tready : in std_logic
+ );
+end entity reorder;
+
+
+architecture rtl of reorder is
+
+ -- used to store one reversed output of a traceback unit
+ signal buffer_sreg : unsigned(MAX_WINDOW_LENGTH - 1 downto 0);
+ signal buffer_cnt : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
+ signal buffer_end : integer range ENCODER_MEMORY_DEPTH downto 0;
+ signal send_output, last_window : boolean;
+
+ signal s_axis_input_tready_int : std_logic;
+
+begin
+
+ s_axis_input_tready <= s_axis_input_tready_int;
+ s_axis_input_tready_int <= '1' when not(send_output) else
+ '0';
+
+-- m_axis_output_tvalid <= '1' when send_output and m_axis_output_tready= '1' else
+ m_axis_output_tvalid <= '1' when send_output else
+ '0';
+ m_axis_output_tdata <= buffer_sreg(0);
+
+ m_axis_output_tlast <= '1' when buffer_cnt = ENCODER_MEMORY_DEPTH and last_window else
+ '0';
+
+ -- Reorder the global path given from an traceback unit with the help of a shift register.
+ pr_reorder : process(clk) is
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ buffer_sreg <= (others => '0');
+ buffer_cnt <= (others => '0');
+ send_output <= false;
+ last_window <= false;
+ buffer_end <= 0;
+ m_axis_output_last_tuser <= '0';
+ else
+
+ -- store output of traceback unit
+ if s_axis_input_tvalid = '1' and s_axis_input_tready_int = '1' then
+ if s_axis_input_tlast = '1' then
+ last_window <= true;
+ buffer_end <= ENCODER_MEMORY_DEPTH;
+ end if;
+ if s_axis_input_last_tuser = '1' then
+ send_output <= true;
+ buffer_sreg <= buffer_sreg(MAX_WINDOW_LENGTH - 2 downto 0) & s_axis_input_tdata;
+ else
+ buffer_sreg <= buffer_sreg(MAX_WINDOW_LENGTH - 2 downto 0) & s_axis_input_tdata;
+ buffer_cnt <= buffer_cnt + 1;
+ end if;
+ end if;
+
+ -- send reordered data to the output
+ if m_axis_output_tready = '1' and send_output then
+ buffer_sreg <= '0' & buffer_sreg(MAX_WINDOW_LENGTH - 1 downto 1);
+
+ -- Next transfer will be the last one of this window.
+ if buffer_cnt = 1 then
+ m_axis_output_last_tuser <= '1';
+ end if;
+
+ -- This was the last data transfer. Tailbits are cut off
+ if buffer_cnt = buffer_end then
+ send_output <= false;
+ last_window <= false;
+ buffer_end <= 0;
+ buffer_cnt <= (others => '0');
+ m_axis_output_last_tuser <= '0';
+ else
+ buffer_cnt <= buffer_cnt - 1;
+ end if;
+ end if;
+ end if;
+ end if;
+ end process pr_reorder;
+
+end architecture rtl;
diff --git a/testsuite/gna/issue301/src/traceback.vhd b/testsuite/gna/issue301/src/traceback.vhd
new file mode 100644
index 000000000..b3da85734
--- /dev/null
+++ b/testsuite/gna/issue301/src/traceback.vhd
@@ -0,0 +1,101 @@
+--!
+--! Copyright (C) 2011 - 2014 Creonic GmbH
+--!
+--! This file is part of the Creonic Viterbi Decoder, which is distributed
+--! under the terms of the GNU General Public License version 2.
+--!
+--! @file
+--! @brief Traceback unit for a viterbi decoder
+--! @author Markus Fehrenz
+--! @date 2011/07/11
+--!
+--! @details The traceback unit only processes a data stream.
+--! There is no knowledge about the decoder configuration.
+--! The information about acquisition and window lengths is received from ram control.
+--!
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library dec_viterbi;
+use dec_viterbi.pkg_param.all;
+use dec_viterbi.pkg_param_derived.all;
+
+
+entity trellis_traceback is
+ port(
+ -- general signals
+ clk : in std_logic;
+ rst : in std_logic;
+
+ s_axis_input_tvalid : in std_logic;
+ s_axis_input_tdata : in std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);
+ s_axis_input_tlast : in std_logic;
+ s_axis_input_tready : out std_logic;
+ s_axis_input_window_tuser : in std_logic;
+ s_axis_input_last_tuser : in std_logic;
+
+ m_axis_output_tvalid : out std_logic;
+ m_axis_output_tdata : out std_logic;
+ m_axis_output_tlast : out std_logic;
+ m_axis_output_last_tuser : out std_logic;
+ m_axis_output_tready : in std_logic
+ );
+end entity trellis_traceback;
+
+
+architecture rtl of trellis_traceback is
+
+ signal current_node : unsigned(BW_TRELLIS_STATES - 1 downto 0);
+ signal m_axis_output_tvalid_int : std_logic;
+ signal s_axis_input_tready_int : std_logic;
+
+begin
+ s_axis_input_tready_int <= '1' when m_axis_output_tready = '1' or m_axis_output_tvalid_int = '0' else
+ '0';
+ s_axis_input_tready <= s_axis_input_tready_int;
+
+ m_axis_output_tvalid <= m_axis_output_tvalid_int;
+
+
+ -- Traceback the ACS local path decisions and output the resulting global path.
+ pr_traceback : process(clk) is
+ begin
+ if rising_edge(clk) then
+ if rst = '1' then
+ m_axis_output_tvalid_int <= '0';
+ m_axis_output_tdata <= '0';
+ m_axis_output_tlast <= '0';
+ m_axis_output_last_tuser <= '0';
+ current_node <= (others => '0');
+ else
+
+ if m_axis_output_tready = '1' then
+ m_axis_output_tvalid_int <= '0';
+ end if;
+
+ -- calculate the decoded bit with an shift register
+ if s_axis_input_tvalid = '1' and s_axis_input_tready_int = '1' then
+
+ m_axis_output_tlast <= s_axis_input_tlast;
+ m_axis_output_last_tuser <= s_axis_input_last_tuser;
+
+ -- handle tvalid output signal
+ if s_axis_input_window_tuser = '1' then
+ m_axis_output_tvalid_int <= '1';
+ m_axis_output_tdata <= current_node(BW_TRELLIS_STATES - 1);
+ end if;
+
+ -- last value of current window?
+ if s_axis_input_last_tuser = '1' then
+ current_node <= to_unsigned(0, BW_TRELLIS_STATES);
+ else
+ current_node <= current_node(BW_TRELLIS_STATES - 2 downto 0)
+ & s_axis_input_tdata(to_integer(current_node(BW_TRELLIS_STATES - 1 downto 0)));
+ end if;
+ end if;
+ end if;
+ end if;
+ end process pr_traceback;
+end architecture rtl;
diff --git a/testsuite/gna/issue301/testsuite.sh b/testsuite/gna/issue301/testsuite.sh
new file mode 100755
index 000000000..96fae042b
--- /dev/null
+++ b/testsuite/gna/issue301/testsuite.sh
@@ -0,0 +1,29 @@
+#! /bin/sh
+
+. ../../testenv.sh
+
+analyze repro.vhdl
+elab_simulate repro
+
+analyze --work=dec_viterbi packages/pkg_helper.vhd
+analyze --work=dec_viterbi packages/pkg_param.vhd
+analyze --work=dec_viterbi packages/pkg_param_derived.vhd
+analyze --work=dec_viterbi packages/pkg_types.vhd
+analyze --work=dec_viterbi packages/pkg_components.vhd
+analyze --work=dec_viterbi packages/pkg_trellis.vhd
+analyze --work=dec_viterbi src/generic_sp_ram.vhd
+analyze --work=dec_viterbi src/axi4s_buffer.vhd
+analyze --work=dec_viterbi src/branch_distance.vhd
+analyze --work=dec_viterbi src/traceback.vhd
+analyze --work=dec_viterbi src/acs.vhd
+analyze --work=dec_viterbi src/ram_ctrl.vhd
+analyze --work=dec_viterbi src/reorder.vhd
+analyze --work=dec_viterbi src/recursion.vhd
+analyze --work=dec_viterbi src/dec_viterbi.vhd
+
+elab_simulate --work=dec_viterbi dec_viterbi_top
+
+clean
+clean dec_viterbi
+
+echo "Test successful"