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) |