OpenCores
URL https://opencores.org/ocsvn/viterbi_decoder_axi4s/viterbi_decoder_axi4s/trunk

Subversion Repositories viterbi_decoder_axi4s

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /viterbi_decoder_axi4s
    from Rev 5 to Rev 6
    Reverse comparison

Rev 5 → Rev 6

/trunk/testbench/tb_dec_viterbi.vhd
1,5 → 1,5
--!
--! Copyright (C) 2011 - 2012 Creonic GmbH
--! 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.
29,12 → 29,12
CLK_PERIOD : time := 10 ns; -- Clock period within simulation.
 
BLOCK_LENGTH_START : natural := 200; -- First block length to simulate.
BLOCK_LENGTH_END : natural := 300; -- Last block length to simulate.
BLOCK_LENGTH_INCR : integer := 100; -- Increment from one block length to another.
BLOCK_LENGTH_END : natural := 500; -- Last block length to simulate.
BLOCK_LENGTH_INCR : integer := 20; -- Increment from one block length to another.
 
SIM_ALL_BLOCKS : boolean := true; -- Set to true in order to simulate all blocks within a data file.
SIM_BLOCK_START : natural := 396; -- If SIM_ALL_BLOCKS = false, gives block to start simulation with.
SIM_BLOCK_END : natural := 398; -- If SIM_ALL_BLOCKS = false, gives last block of simulation.
SIM_BLOCK_START : natural := 0; -- If SIM_ALL_BLOCKS = false, gives block to start simulation with.
SIM_BLOCK_END : natural := 10; -- If SIM_ALL_BLOCKS = false, gives last block of simulation.
 
WINDOW_LENGTH : natural := 55; -- Window length to use for simulation.
ACQUISITION_LENGTH : natural := 50; -- Acquisition length to use for simulation.
91,7 → 91,7
-- Input data send signals.
--
 
type t_send_data_fsm is (READ_FILE, CONFIGURE, SEND_DATA, SEND_DATA_FINISHED);
type t_send_data_fsm is (READ_FILE, CONFIGURE, SEND_DATA, DEASSERT_VALID, SEND_DATA_FINISHED, SEND_FIRST_DATA);
signal send_data_fsm : t_send_data_fsm;
 
signal block_send_end : natural;
115,7 → 115,6
signal last_block_out : natural;
signal current_block_out : natural;
signal current_block_length_out : natural;
signal current_block_length_out_d : natural;
signal sys_bit_counter_out : natural;
 
 
130,6 → 129,8
 
shared variable v_decoded_software : t_nat_array_ptr;
 
signal valid_cnt : natural :=0;
signal ready_cnt : natural :=0;
begin
 
clk <= not clk after CLK_PERIOD / 2;
152,8 → 153,6
variable v_filename_ptr : t_string_ptr;
variable v_num_lines : natural := 0;
variable v_num_blocks : natural := 0;
variable v_current_block_length : natural := 0;
variable v_sys_bit_counter : integer := 0;
begin
if rising_edge(clk) then
if aresetn = '0' then
174,6 → 173,7
sys_bit_counter <= 0;
 
send_data_fsm <= READ_FILE;
valid_cnt <= 0;
 
else
 
221,11 → 221,20
-- Check whether configuration succeeded
if m_axis_ctrl_tvalid = '1' and m_axis_ctrl_tready = '1' then
m_axis_ctrl_tvalid <= '0';
send_data_fsm <= SEND_DATA;
send_data_fsm <= SEND_FIRST_DATA;
 
else
m_axis_ctrl_tvalid <= '1';
end if;
 
when SEND_FIRST_DATA =>
for j in 0 to NUMBER_PARITY_BITS - 1 loop
m_axis_input_tdata(j * 8 + BW_LLR_INPUT - 1 downto j * 8) <=
std_logic_vector(to_signed(v_llr(current_block * (current_block_length_tail * NUMBER_PARITY_BITS) + sys_bit_counter * NUMBER_PARITY_BITS + j), BW_LLR_INPUT));
end loop;
sys_bit_counter <= sys_bit_counter + 1;
send_data_fsm <= SEND_DATA;
m_axis_input_tvalid <= '1';
 
--
-- Send all data of a block. If we are done with this, we check what to do next:
239,34 → 248,38
 
-- Data transmission => increase bit counter and update data for next cycle.
if m_axis_input_tvalid = '1' and m_axis_input_tready = '1' then
v_sys_bit_counter := sys_bit_counter + 1;
sys_bit_counter <= v_sys_bit_counter;
else
v_sys_bit_counter := sys_bit_counter;
if valid_cnt = 5 then
valid_cnt <= 0;
send_data_fsm <= DEASSERT_VALID;
m_axis_input_tvalid <= '0';
else
valid_cnt <= valid_cnt + 1;
end if;
sys_bit_counter <= sys_bit_counter + 1;
end if;
 
 
if v_sys_bit_counter < current_block_length_tail then
-- trim and move data to stream
for j in 0 to NUMBER_PARITY_BITS - 1 loop
m_axis_input_tdata(j * 8 + BW_LLR_INPUT - 1 downto j * 8) <=
std_logic_vector(to_signed(v_llr(current_block * (current_block_length_tail * NUMBER_PARITY_BITS) + v_sys_bit_counter * NUMBER_PARITY_BITS + j), BW_LLR_INPUT));
end loop;
end if;
if m_axis_input_tvalid = '1' and m_axis_input_tready = '1' then
if sys_bit_counter < current_block_length_tail then
-- trim and move data to stream
for j in 0 to NUMBER_PARITY_BITS - 1 loop
m_axis_input_tdata(j * 8 + BW_LLR_INPUT - 1 downto j * 8) <=
std_logic_vector(to_signed(v_llr(current_block * (current_block_length_tail * NUMBER_PARITY_BITS) + sys_bit_counter * NUMBER_PARITY_BITS + j), BW_LLR_INPUT));
end loop;
end if;
 
 
-- Next data will be last of block
if v_sys_bit_counter = current_block_length_tail - 1 then
m_axis_input_tlast <= '1';
else
m_axis_input_tlast <= '0';
-- Next data will be last of block
if sys_bit_counter = current_block_length_tail - 1 then
m_axis_input_tlast <= '1';
else
m_axis_input_tlast <= '0';
end if;
end if;
 
-- We have just sent the very last bit of this block.
if m_axis_input_tvalid = '1' and
m_axis_input_tready = '1' and
if m_axis_input_tvalid = '1' and m_axis_input_tready = '1' and
m_axis_input_tlast = '1' then
-- if v_sys_bit_counter = current_block_length then
sys_bit_counter <= 0;
m_axis_input_tvalid <= '0';
 
287,6 → 300,8
end if;
end if;
 
when DEASSERT_VALID =>
send_data_fsm <= SEND_DATA;
 
--
-- We are done with all blocks, do nothing anynmore.
312,20 → 327,26
if aresetn = '0' then
 
current_block_length_out <= 0;
current_block_length_out_d <= 0;
sys_bit_counter_out <= 0;
s_axis_output_tready <= '1';
block_receive_complete <= false;
new_block_length <= false;
ready_cnt <= 0;
 
else
 
block_receive_complete <= false;
new_block_length <= false;
current_block_length_out_d <= current_block_length_out;
s_axis_output_tready <= '1';
 
-- Data passes the output interface.
if s_axis_output_tvalid = '1' and s_axis_output_tready = '1' then
if ready_cnt = 8 then
ready_cnt <= 0;
s_axis_output_tready <= '0';
else
ready_cnt <= ready_cnt + 1;
end if;
 
decoded_hardware(sys_bit_counter_out) <= s_axis_output_tdata;
 
347,7 → 368,7
 
if SIM_ALL_BLOCKS then
first_block_out <= 0;
last_block_out <= v_num_lines / (sys_bit_counter_out + 1);
last_block_out <= v_num_lines / (sys_bit_counter_out + 1) - 1;
else
first_block_out <= SIM_BLOCK_START;
last_block_out <= SIM_BLOCK_END;
396,23 → 417,24
v_bit_error_count := v_bit_error_count + 1;
 
assert false report "Decoded bit " & str(i) & " in block " & str(v_current_block) & " does not match!"
severity warning;
severity failure;
end if;
end loop;
 
-- Dump message.
write(v_line_out, string'("Block length: ") & str(current_block_length_out));
write(v_line_out, string'(", Block: ") & str(current_block_out));
write(v_line_out, string'(", Block: ") & str(v_current_block));
write(v_line_out, string'(", errors: ") & str(v_bit_error_count));
writeline(output, v_line_out);
 
if current_block_out /= last_block_out - 1 then
current_block_out <= current_block_out + 1;
else
current_block_out <= current_block_out + 1;
if current_block_out = last_block_out then
current_block_out <= 0;
 
-- Stop simulation, if we are done with all blocks of all block lengths.
if current_block_length_out = BLOCK_LENGTH_END then
assert false report "End" severity failure;
assert false report "Simulation finished with no errors." severity failure;
end if;
end if;
end if;
/trunk/scripts/perform_simulation.sh
17,6 → 17,7
vcom -work dec_viterbi ../packages/pkg_components.vhd
vcom -work dec_viterbi ../packages/pkg_trellis.vhd
vcom -work dec_viterbi ../src/generic_sp_ram.vhd
vcom -work dec_viterbi ../src/axi4s_buffer.vhd
vcom -work dec_viterbi ../src/branch_distance.vhd
vcom -work dec_viterbi ../src/traceback.vhd
vcom -work dec_viterbi ../src/acs.vhd
/trunk/src/dec_viterbi.vhd
1,5 → 1,5
--!
--! Copyright (C) 2011 - 2012 Creonic GmbH
--! 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.
81,6 → 81,11
-- 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;
108,16 → 113,10
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);
signal reorder_recursion_tvalid : std_logic;
signal reorder_recursion_tdata : std_logic;
signal reorder_recursion_tlast : std_logic;
 
-- recursion signals
signal recursion_tready : std_logic;
 
-- output signals
signal output_tready : std_logic_vector(1 downto 0);
signal current_active, semaphore_output : integer range 1 downto 0;
signal current_active : integer range 1 downto 0;
 
begin
 
128,7 → 127,7
--
gen_input_assignment: for i in NUMBER_PARITY_BITS - 1 downto 0 generate
begin
input(i) <= signed(s_axis_input_tdata(8 * i + BW_LLR_INPUT - 1 downto 8 * i));
input(i) <= signed(buffer_tdata(8 * i + BW_LLR_INPUT - 1 downto 8 * i));
end generate gen_input_assignment;
 
rst <= not aresetn;
138,6 → 137,29
------------------------------
 
-------------------------------------
-- 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
--------------------------------------
 
151,9 → 173,9
clk => clk,
rst => rst,
 
s_axis_input_tvalid => s_axis_input_tvalid,
s_axis_input_tvalid => buffer_tvalid,
s_axis_input_tdata => input,
s_axis_input_tlast => s_axis_input_tlast,
s_axis_input_tlast => buffer_tlast,
s_axis_input_tready => branch_tready(i),
m_axis_output_tvalid => branch_tvalid(i),
291,6 → 313,10
------------------------------
 
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 : recursion
port map(
307,21 → 333,35
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;
 
-------------------------------
-- Input interface handling
-------------------------------
 
s_axis_input_tready <= branch_tready(0);
 
no_recursion: if FEEDBACK_POLYNOMIAL = 0 generate
 
-------------------------------
-- Output interface handling
-------------------------------
-------------------------------
-- Output interface handling
-------------------------------
 
no_recursion: if FEEDBACK_POLYNOMIAL = 0 generate
m_axis_output_tdata <= reorder_tdata(0) when reorder_tvalid(0) = '1' else
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
330,9 → 370,9
m_axis_output_tlast <= '1' when reorder_tlast(0) = '1' or reorder_tlast(1) = '1' else
'0';
 
output_tready(0) <= '1' when (semaphore_output = 1 or current_active = 0) and m_axis_output_tready = '1' else
output_tready(0) <= '1' when (current_active = 0) and m_axis_output_tready = '1' else
'0';
output_tready(1) <= '1' when (semaphore_output = 1 or current_active = 1) and m_axis_output_tready = '1' else
output_tready(1) <= '1' when (current_active = 1) and m_axis_output_tready = '1' else
'0';
end generate no_recursion;
 
339,19 → 379,6
 
recursion : if FEEDBACK_POLYNOMIAL /= 0 generate
begin
reorder_recursion_tvalid <= '1' when reorder_tvalid(0) = '1' or reorder_tvalid(1) = '1' else
'0';
 
reorder_recursion_tdata <= reorder_tdata(0) when reorder_tvalid(0) = '1' 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 (semaphore_output = 1 or current_active = 0) and recursion_tready = '1' else
'0';
output_tready(1) <= '1' when (semaphore_output = 1 or current_active = 1) and recursion_tready = '1' else
'0';
end generate recursion;
 
 
361,21 → 388,10
if rising_edge(clk) then
if rst = '1' then
current_active <= 0;
semaphore_output <= 1;
else
if reorder_last_tuser(current_active) = '1' then
semaphore_output <= 1;
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;
if semaphore_output = 1 then
if reorder_tvalid(0) = '1' then
current_active <= 0;
semaphore_output <= 0;
end if;
if reorder_tvalid(1) = '1' then
current_active <= 1;
semaphore_output <= 0;
end if;
end if;
end if;
end if;
end process pr_reorder_tready;
/trunk/src/traceback.vhd
1,5 → 1,5
--!
--! Copyright (C) 2011 - 2012 Creonic GmbH
--! 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.
49,7 → 49,6
 
signal current_node : unsigned(BW_TRELLIS_STATES - 1 downto 0);
signal m_axis_output_tvalid_int : std_logic;
signal s_axis_input_last_tuser_d1 : std_logic;
signal s_axis_input_tready_int : std_logic;
 
begin
59,6 → 58,7
 
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
68,29 → 68,33
m_axis_output_tdata <= '0';
m_axis_output_tlast <= '0';
m_axis_output_last_tuser <= '0';
s_axis_input_last_tuser_d1 <= '0';
current_node <= (others => '0');
else
m_axis_output_tlast <= s_axis_input_tlast;
s_axis_input_last_tuser_d1 <= s_axis_input_last_tuser;
m_axis_output_last_tuser <= s_axis_input_last_tuser;
 
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_last_tuser_d1 = '0' then
if s_axis_input_tvalid = '1' and s_axis_input_tready_int = '1' then
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)));
m_axis_output_tdata <= current_node(BW_TRELLIS_STATES - 1);
end if;
else
current_node <= to_unsigned(0, BW_TRELLIS_STATES);
end if;
-- handle tvalid output signal
if s_axis_input_window_tuser = '1' then
m_axis_output_tvalid_int <= '1';
else
m_axis_output_tvalid_int <= '0';
end if;
end if;
end if;
end process pr_traceback;
/trunk/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;
/trunk/src/reorder.vhd
1,5 → 1,5
--!
--! Copyright (C) 2011 - 2012 Creonic GmbH
--! 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.
52,7 → 52,7
 
architecture rtl of reorder is
 
-- used to store one reversed output of an traceback unit
-- 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;
66,7 → 66,8
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 and m_axis_output_tready= '1' else
m_axis_output_tvalid <= '1' when send_output else
'0';
m_axis_output_tdata <= buffer_sreg(0);
 
73,7 → 74,7
m_axis_output_tlast <= '1' when buffer_cnt = ENCODER_MEMORY_DEPTH and last_window else
'0';
 
-- Reorder the global path given from an tracebackunit with the help of an shift register.
-- 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
/trunk/src/ram_ctrl.vhd
1,5 → 1,5
--!
--! Copyright (C) 2011 - 2012 Creonic GmbH
--! 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.
77,23 → 77,15
-- The input configuration is stored in a register.
-- It is received from a AXI4-Stream interface from the top entity.
--
-- We just receive window_length and acquisition_length from the outside. All
-- other values are computed internally in order to impreove timing of the core:
-- m denotes minus,
-- p denotes plus.
--
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);
window_p_acquisition : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
window_p_acquisition_m1 : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
window_p_acquisition_m2 : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
window_p_acquisition_m3 : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
window_m1 : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
end record trec_runtime_param;
 
-- Types for finite state machines
type t_ram_ctrl is (CONFIGURE, START, BEGINNING, RUNNING, ENDING);
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);
109,324 → 101,347
-- 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 ram_ctrl_fsm : t_ram_ctrl;
signal en_ram, wen_ram : std_logic_vector(3 downto 0);
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 d : std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);
signal q : t_ram_rd_data;
signal q_reg : t_ram_data;
 
-- ram addess, number and data pointer
signal write_ram_ptr : unsigned(1 downto 0);
signal read_ram_ptr, read_ram_data_ptr : t_ram_ptr;
signal read_ram_data_ptr_d1 : t_ram_ptr;
signal write_addr_ptr, read_addr_ptr, last_addr_ptr : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
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;
 
-- control flags
signal switch_ram, switch_state, ram_writing : boolean;
 
-- internal signals of outputs
signal m_axis_output_tvalid_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 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;
 
-- delay signals of inputs
signal m_axis_output_tvalid_d1, m_axis_output_tvalid_d2 : std_logic_vector(1 downto 0);
 
signal next_traceback, not_next_traceback : integer range 1 downto 0;
signal data_cnt : t_ram_data_cnt;
 
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
 
s_axis_input_tready <= '1' when (m_axis_output_tready = "11" or m_axis_output_tvalid_int(0) = '0'
or m_axis_output_tvalid_int(1) = '0')
and ram_ctrl_fsm /= CONFIGURE and ram_ctrl_fsm /= ENDING else
'0';
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);
 
s_axis_input_tready_int <= '1' when (m_axis_output_tready = "11" or m_axis_output_tvalid_int(0) = '0'
or m_axis_output_tvalid_int(1) = '0')
and ram_ctrl_fsm /= CONFIGURE and ram_ctrl_fsm /= ENDING else
'0';
 
m_axis_output_last_tuser <= m_axis_output_last_tuser_int;
m_axis_output_tvalid <= m_axis_output_tvalid_int;
m_axis_output_tdata <= q;
 
 
--
-- Statemachine handles configuration, write/read to/from ram
-- and forwarding decision vectors to corresponding traceback units
-- 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_ctrl_ram : process(clk, write_ram_ptr, read_ram_ptr) is
variable v_write_ram_ptr : integer range 3 downto 0;
variable v_read_ram_ptr : t_ram_ptr_int;
pr_buf_ram_output: process(clk) is
begin
v_write_ram_ptr := to_integer(write_ram_ptr);
v_read_ram_ptr(0) := to_integer(read_ram_ptr(0));
v_read_ram_ptr(1) := to_integer(read_ram_ptr(1));
if rising_edge(clk) then
if rst = '1' then
ram_ctrl_fsm <= CONFIGURE;
ram_buffer <= (others => (others => '0'));
ram_buffer_full <= (others => '0');
else
 
config.window_length <= (others => '0');
config.acquisition_length <= (others => '0');
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;
 
en_ram <= (others => '1');
wen_ram <= (others => '0');
addr <= (others => (others => '0'));
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;
 
write_ram_ptr <= to_unsigned(0, 2);
write_addr_ptr <= (others => '0');
last_addr_ptr <= (others => '0');
end if;
end if;
end process pr_buf_ram_output;
 
read_ram_ptr <= (to_unsigned(2, 2), to_unsigned(3, 2));
read_ram_data_ptr <= (to_unsigned(2, 2), to_unsigned(3, 2));
read_ram_data_ptr_d1 <= (to_unsigned(2, 2), to_unsigned(3, 2));
read_addr_ptr <= (others => '0');
next_traceback <= 0;
not_next_traceback <= 1;
-----------------------------
-- 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;
 
switch_ram <= false;
switch_state <= false;
ram_writing <= true;
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;
 
m_axis_output_last_tuser_int <= (others => '0');
m_axis_output_window_tuser <= (others => '0');
m_axis_output_tvalid_int <= (others => '0');
m_axis_output_tvalid_d1 <= (others => '0');
m_axis_output_tvalid_d2 <= (others => '0');
m_axis_output_tlast <= (others => '0');
s_axis_ctrl_tready <= '1';
-- 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
addr(v_write_ram_ptr) <= write_addr_ptr;
addr(v_read_ram_ptr(0)) <= read_addr_ptr;
addr(v_read_ram_ptr(1)) <= read_addr_ptr;
 
d <= s_axis_input_tdata;
case write_ram_fsm is
 
q(0) <= q_reg(to_integer(read_ram_data_ptr(0)));
q(1) <= q_reg(to_integer(read_ram_data_ptr(1)));
 
case ram_ctrl_fsm is
 
--
-- It is necessary to configure the decoder before each block
-- The decoder is always ready to receive on the ctrl channel, when it is in this state
--
when CONFIGURE =>
if s_axis_ctrl_tvalid = '1' then
config.window_length <= unsigned(s_axis_ctrl_tdata(BW_MAX_WINDOW_LENGTH - 1 + 16 downto 16));
config.acquisition_length <= unsigned(s_axis_ctrl_tdata(BW_MAX_WINDOW_LENGTH - 1 downto 0));
ram_ctrl_fsm <= START;
wen_ram(v_write_ram_ptr) <= '1';
s_axis_ctrl_tready <= '0';
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 packettransmission begins
-- 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
ram_ctrl_fsm <= BEGINNING;
write_addr_ptr <= write_addr_ptr + 1;
read_ram_ptr(next_traceback) <= write_ram_ptr - 1;
read_ram_ptr(not_next_traceback) <= write_ram_ptr - 2;
else
write_addr_ptr <= config.window_length - config.acquisition_length;
 
config.window_p_acquisition <= config.window_length + config.acquisition_length;
config.window_p_acquisition_m1 <= config.window_length + config.acquisition_length - 1;
config.window_p_acquisition_m2 <= config.window_length + config.acquisition_length - 2;
config.window_p_acquisition_m3 <= config.window_length + config.acquisition_length - 3;
config.window_m1 <= config.window_length - 1;
end if;
if write_addr_ptr = config.window_length - 1 then
 
--
-- The first arriving data have to be stored on special locations to guarantee
-- a non malicious behavior of the traceback units.
--
when BEGINNING =>
if s_axis_input_tvalid = '1' and s_axis_input_tready_int = '1' then
if switch_ram then
ram_ctrl_fsm <= RUNNING;
wen_ram(to_integer(unsigned(write_ram_ptr - 1))) <= '0';
wen_ram(v_write_ram_ptr) <= '1';
write_addr_ptr <= write_addr_ptr + 1;
read_addr_ptr <= read_addr_ptr - 1;
switch_ram <= false;
-- 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
if write_addr_ptr = config.window_m1 then
write_addr_ptr <= to_unsigned(0, BW_MAX_WINDOW_LENGTH);
read_addr_ptr <= config.window_m1;
write_ram_ptr <= write_ram_ptr + 1;
switch_ram <= true;
else
write_addr_ptr <= write_addr_ptr + 1;
end if;
write_addr_ptr <= write_addr_ptr + 1;
end if;
end if;
 
 
--
-- The running state handles the most decoding
-- It handels the writing of forward to ram and reading the decision vecotors
-- the decision vecotrs are forwarded to the traceback units.
-- The decoder is receiving data from the ACS.
--
when RUNNING =>
if (s_axis_input_tvalid = '1' and s_axis_input_tready_int = '1' and ram_writing) or
((m_axis_output_tready(0) = '1' and m_axis_output_tready(1) = '1') and not(ram_writing)) then
when RUN =>
write_window_complete <= '0';
write_last_window_complete <= '0';
 
read_ram_data_ptr_d1 <= read_ram_ptr;
read_ram_data_ptr <= read_ram_data_ptr_d1;
m_axis_output_tvalid_int <= m_axis_output_tvalid_d1;
m_axis_output_tvalid_d1 <= m_axis_output_tvalid_d2;
if s_axis_input_tvalid = '1' and s_axis_input_tready_int = '1' then
write_addr_ptr <= write_addr_ptr + 1;
 
if switch_ram then
if ram_writing then
wen_ram(to_integer(unsigned(write_ram_ptr - 1))) <= '0';
wen_ram(v_write_ram_ptr) <= '1';
next_traceback <= not_next_traceback;
not_next_traceback <= next_traceback;
else
ram_ctrl_fsm <= ENDING;
ram_writing <= true;
wen_ram(to_integer(unsigned(write_ram_ptr - 1))) <= '0';
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;
switch_ram <= false;
else
if write_addr_ptr = config.window_m1 then
write_ram_ptr <= write_ram_ptr + 1;
read_ram_ptr(next_traceback) <= write_ram_ptr;
read_ram_ptr(not_next_traceback) <= write_ram_ptr - 2;
switch_ram <= true;
data_cnt(next_traceback) <= 0;
end if;
end if;
 
-- Store last RAM address and stop writing after last bit of a block arrives
if s_axis_input_tlast = '1' then
ram_writing <= false;
last_addr_ptr <= write_addr_ptr;
-- wen_ram(v_write_ram_ptr) <= '0';
end if;
 
-- Handle RAM addess point increase and reset
if write_addr_ptr = config.window_m1 then
write_addr_ptr <= to_unsigned(0, BW_MAX_WINDOW_LENGTH);
read_addr_ptr <= config.window_m1;
else
write_addr_ptr <= write_addr_ptr + 1;
read_addr_ptr <= read_addr_ptr - 1;
end if;
 
-- Handle side channel information for traceback units.
for i in 1 downto 0 loop
if m_axis_output_tvalid_d1(i) = '1' then
data_cnt(i) <= data_cnt(i) + 1;
end if;
if s_axis_input_tlast = '1' then
write_ram_fsm <= CONFIGURE;
wen_ram <= (others => '0');
 
-- Signals the valid signal
if data_cnt(i) = config.window_p_acquisition_m2 then
m_axis_output_tvalid_d2(i) <= '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;
if switch_ram and ram_writing then
m_axis_output_tvalid_d2(next_traceback) <= '1';
end if;
read_last_addr_ptr <= write_addr_ptr;
 
-- Signals the end of the current window
if m_axis_output_last_tuser_int(i) = '1' then
m_axis_output_last_tuser_int(i) <= '0';
end if;
if data_cnt(i) = config.window_p_acquisition_m1 then
m_axis_output_last_tuser_int(i) <= '1';
end if;
write_addr_ptr <= (others => '0');
write_ram_ptr <= write_ram_ptr + 1;
end if;
end if;
 
-- Signals, whether there is acquisition or window
if data_cnt(i) = config.window_p_acquisition then
m_axis_output_window_tuser(i) <= '0';
end if;
if data_cnt(i) = config.acquisition_length then
m_axis_output_window_tuser(i) <= '1';
end if;
end loop;
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;
 
--
-- Handle last traceback with no acquisition
-- Maybe the resulting window is longer than others
--
when ENDING =>
if m_axis_output_tready(0) = '1' and m_axis_output_tready(1) = '1' then
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;
 
read_ram_data_ptr_d1 <= read_ram_ptr;
read_ram_data_ptr <= read_ram_data_ptr_d1;
m_axis_output_tvalid_int <= m_axis_output_tvalid_d1;
end case;
end if;
end if;
end process pr_write_ram;
 
for i in 1 downto 0 loop
if m_axis_output_tvalid_int(i) = '1' then
data_cnt(i) <= data_cnt(i) + 1;
end if;
end loop;
 
if data_cnt(not_next_traceback) = config.window_p_acquisition_m3 then
read_addr_ptr <= last_addr_ptr;
elsif read_addr_ptr = 0 then
read_ram_ptr(0) <= read_ram_ptr(0) - 1;
read_ram_ptr(1) <= read_ram_ptr(1) - 1;
read_addr_ptr <= config.window_m1;
else
read_addr_ptr <= read_addr_ptr - 1;
end if;
-------------------------------------------
-- Manage reading from RAM for traceback --
-------------------------------------------
 
if data_cnt(not_next_traceback) = config.window_p_acquisition_m1 then
m_axis_output_last_tuser_int(not_next_traceback) <= '1';
m_axis_output_tvalid_d1(next_traceback) <= '1';
m_axis_output_tvalid_d1(not_next_traceback) <= '0';
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;
 
if data_cnt(not_next_traceback) = config.window_p_acquisition then
m_axis_output_window_tuser(not_next_traceback) <= '0';
m_axis_output_window_tuser(next_traceback) <= '1';
-- 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;
 
if data_cnt(not_next_traceback) = config.acquisition_length then
m_axis_output_window_tuser(not_next_traceback) <= '1';
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;
 
if m_axis_output_last_tuser_int(not_next_traceback) = '1' then
m_axis_output_last_tuser_int(not_next_traceback) <= '0';
-- 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 data_cnt(next_traceback) = last_addr_ptr + config.acquisition_length - 1 then
m_axis_output_tvalid_d1(next_traceback) <= '0';
m_axis_output_last_tuser_int(next_traceback) <= '1';
m_axis_output_tlast(next_traceback) <= '1';
switch_state <= true;
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;
 
-- block is finished and the decoder is ready for a new configuration and block
if switch_state then
switch_state <= false;
m_axis_output_last_tuser_int <= "00";
m_axis_output_window_tuser <= "00";
m_axis_output_tlast <= "00";
ram_ctrl_fsm <= CONFIGURE;
s_axis_ctrl_tready <= '1';
data_cnt(0) <= 0;
data_cnt(1) <= 0;
m_axis_output_tvalid_int <= (others => '0');
m_axis_output_tvalid_d1 <= (others => '0');
m_axis_output_tvalid_d2 <= (others => '0');
end if;
-- 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 case;
end if;
 
if s_axis_input_tlast = '1' then
last_of_block <= '1';
end if;
 
end if;
end if;
end process pr_ctrl_ram;
end process pr_next_traceback;
 
 
------------------------------
--- Portmapping components ---
------------------------------
433,7 → 448,13
 
gen_generic_sp_ram : for i in 0 to 3 generate
begin
inst_generic_sp_ram : generic_sp_ram
 
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,
443,9 → 464,9
clk => clk,
rst => rst,
wen => wen_ram(i),
en => en_ram(i),
en => '1',
a => std_logic_vector(addr(i)),
d => d,
d => s_axis_input_tdata,
q => q_reg(i)
);
end generate gen_generic_sp_ram;
/trunk/src/acs.vhd
1,5 → 1,5
--!
--! Copyright (C) 2011 - 2012 Creonic GmbH
--! 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.
89,6 → 89,7
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);
97,8 → 98,11
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';
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
119,7 → 123,7
m_axis_outdec_tdata <= '0';
m_axis_outprob_tdata <= std_logic_vector(v_low);
end if;
m_axis_outdec_tvalid_int <= s_axis_inbranch_tvalid;
m_axis_outdec_tvalid_int <= '1';
end if;
 
m_axis_outdec_tlast <= s_axis_inbranch_tlast;
/trunk/src/branch_distance.vhd
1,5 → 1,5
--!
--! Copyright (C) 2011 - 2012 Creonic GmbH
--! 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.
60,7 → 60,6
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' or m_axis_output_tvalid_int = '0' else
s_axis_input_tready_int <= '1' when m_axis_output_tready = '1' else
'0';
 
79,6 → 78,12
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;
 
85,7 → 90,7
for i in NUMBER_PARITY_BITS - 1 downto 0 loop
 
--
-- Either the value is added or subtrcated, depending on
-- Either the value is added or subtracted, depending on
-- the current branch metric we are computing.
--
if EDGE_WEIGHT(i) = '0' then
95,10 → 100,10
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;
 
m_axis_output_tvalid_int <= s_axis_input_tvalid;
m_axis_output_tlast <= s_axis_input_tlast;
end if;
end if;
end process pr_branch;
/trunk/src/recursion.vhd
1,5 → 1,5
--!
--! Copyright (C) 2011 - 2012 Creonic GmbH
--! 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.
/trunk/packages/pkg_trellis.vhd
1,5 → 1,5
--!
--! Copyright (C) 2011 - 2012 Creonic GmbH
--! 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.
/trunk/packages/pkg_helper.vhd
1,5 → 1,5
--!
--! Copyright (C) 2011 - 2012 Creonic GmbH
--! 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.
/trunk/packages/pkg_param.vhd
1,5 → 1,5
--!
--! Copyright (C) 2011 - 2012 Creonic GmbH
--! 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.
/trunk/packages/pkg_param_derived.vhd
1,5 → 1,5
--!
--! Copyright (C) 2011 - 2012 Creonic GmbH
--! 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.
/trunk/packages/pkg_types.vhd
1,5 → 1,5
--!
--! Copyright (C) 2011 - 2012 Creonic GmbH
--! 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.
/trunk/packages/pkg_components.vhd
1,5 → 1,5
--!
--! Copyright (C) 2011 - 2012 Creonic GmbH
--! 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.
22,6 → 22,26
 
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)

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.