Line 1... |
Line 1... |
--!
|
--!
|
--! Copyright (C) 2011 - 2012 Creonic GmbH
|
--! Copyright (C) 2011 - 2014 Creonic GmbH
|
--!
|
--!
|
--! This file is part of the Creonic Viterbi Decoder, which is distributed
|
--! This file is part of the Creonic Viterbi Decoder, which is distributed
|
--! under the terms of the GNU General Public License version 2.
|
--! under the terms of the GNU General Public License version 2.
|
--!
|
--!
|
--! @file
|
--! @file
|
Line 75... |
Line 75... |
--
|
--
|
-- Record contains runtime configuration.
|
-- Record contains runtime configuration.
|
-- The input configuration is stored in a register.
|
-- The input configuration is stored in a register.
|
-- It is received from a AXI4-Stream interface from the top entity.
|
-- 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
|
type trec_runtime_param is record
|
window_length : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
|
window_length : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
|
acquisition_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;
|
end record trec_runtime_param;
|
|
|
-- Types for finite state machines
|
-- 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
|
-- RAM controling types
|
type t_ram_data is array (3 downto 0) of std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);
|
type t_ram_data is array (3 downto 0) of std_logic_vector(NUMBER_TRELLIS_STATES - 1 downto 0);
|
type t_ram_addr is array (3 downto 0) of unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
|
type t_ram_addr is array (3 downto 0) of unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
|
type t_ram_rd_addr is array (1 downto 0) of unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
|
type t_ram_rd_addr is array (1 downto 0) of unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
|
Line 107... |
Line 99... |
|
|
------------------------
|
------------------------
|
-- Signal declaration
|
-- 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 config : trec_runtime_param;
|
signal ram_ctrl_fsm : t_ram_ctrl;
|
signal write_ram_fsm : t_write_ram_fsm;
|
signal en_ram, wen_ram : std_logic_vector(3 downto 0);
|
signal read_ram_fsm : t_read_ram_fsm_array;
|
|
signal wen_ram : std_logic_vector(3 downto 0);
|
signal addr : t_ram_addr;
|
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;
|
signal q_reg : t_ram_data;
|
|
|
-- ram addess, number and data pointer
|
-- ram addess, number and data pointer
|
signal write_ram_ptr : unsigned(1 downto 0);
|
signal write_ram_ptr : unsigned(1 downto 0);
|
signal read_ram_ptr, read_ram_data_ptr : t_ram_ptr;
|
signal read_ram_ptr : t_ram_ptr;
|
signal read_ram_data_ptr_d1 : t_ram_ptr;
|
signal read_ram_ptr_d : t_ram_ptr;
|
signal write_addr_ptr, read_addr_ptr, last_addr_ptr : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
|
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
|
-- internal signals of outputs
|
signal m_axis_output_tvalid_int : std_logic_vector(1 downto 0);
|
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 m_axis_output_last_tuser_int : std_logic_vector(1 downto 0);
|
signal s_axis_input_tready_int : std_logic;
|
signal s_axis_input_tready_int : std_logic;
|
|
signal s_axis_ctrl_tready_int : std_logic;
|
|
|
-- delay signals of inputs
|
signal next_traceback : std_logic_vector(1 downto 0);
|
signal m_axis_output_tvalid_d1, m_axis_output_tvalid_d2 : std_logic_vector(1 downto 0);
|
signal write_window_complete : std_logic;
|
|
signal write_last_window_complete : std_logic;
|
signal next_traceback, not_next_traceback : integer range 1 downto 0;
|
signal last_of_block : std_logic;
|
signal data_cnt : t_ram_data_cnt;
|
signal read_last_addr_ptr : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
|
|
|
begin
|
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';
|
|
|
|
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_tvalid <= m_axis_output_tvalid_int;
|
m_axis_output_tdata <= q;
|
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);
|
|
|
|
|
--
|
--
|
-- Statemachine handles configuration, write/read to/from ram
|
-- When the output port is not ready to read the output of the RAM immediately
|
-- and forwarding decision vectors to corresponding traceback units
|
-- we have to remember the output value of the RAM in an extra register.
|
|
-- When the output is ready to read, we first use the ouput of the register
|
|
-- and only then the output of the RAM again.
|
--
|
--
|
|
pr_buf_ram_output: process(clk) is
|
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;
|
|
begin
|
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 rising_edge(clk) then
|
if rst = '1' 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');
|
for i in 0 to 1 loop
|
config.acquisition_length <= (others => '0');
|
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');
|
if m_axis_output_tvalid_int(i) = '1' and m_axis_output_tready(i) = '1' and ram_buffer_full(i) = '1' then
|
wen_ram <= (others => '0');
|
ram_buffer_full(i) <= '0';
|
addr <= (others => (others => '0'));
|
end if;
|
|
end loop;
|
|
|
write_ram_ptr <= to_unsigned(0, 2);
|
end if;
|
write_addr_ptr <= (others => '0');
|
end if;
|
last_addr_ptr <= (others => '0');
|
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));
|
-- Manage writing from ACS --
|
read_ram_data_ptr_d1 <= (to_unsigned(2, 2), to_unsigned(3, 2));
|
-----------------------------
|
read_addr_ptr <= (others => '0');
|
s_axis_input_tready_int <= '0' when (write_ram_fsm = CONFIGURE) or
|
next_traceback <= 0;
|
(write_ram_ptr = read_ram_ptr(0) and read_ram_fsm(0) /= WAIT_FOR_WINDOW) or
|
not_next_traceback <= 1;
|
(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
|
switch_ram <= false;
|
'1';
|
switch_state <= false;
|
s_axis_input_tready <= s_axis_input_tready_int;
|
ram_writing <= true;
|
|
|
|
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';
|
|
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;
|
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;
|
|
|
q(0) <= q_reg(to_integer(read_ram_data_ptr(0)));
|
-- Process for writing to the RAM
|
q(1) <= q_reg(to_integer(read_ram_data_ptr(1)));
|
pr_write_ram: process(clk) is
|
|
variable v_window_length : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
|
|
variable v_acquisition_length : unsigned(BW_MAX_WINDOW_LENGTH - 1 downto 0);
|
|
begin
|
|
if rising_edge(clk) then
|
|
if rst = '1' then
|
|
write_ram_fsm <= CONFIGURE;
|
|
write_addr_ptr <= (others => '0');
|
|
write_ram_ptr <= (others => '0');
|
|
wen_ram <= (others => '0');
|
|
write_window_complete <= '0';
|
|
write_last_window_complete <= '0';
|
|
read_last_addr_ptr <= (others => '0');
|
|
else
|
|
|
case ram_ctrl_fsm is
|
case write_ram_fsm is
|
|
|
--
|
--
|
-- It is necessary to configure the decoder before each block
|
-- 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 =>
|
when CONFIGURE =>
|
if s_axis_ctrl_tvalid = '1' then
|
write_window_complete <= '0';
|
config.window_length <= unsigned(s_axis_ctrl_tdata(BW_MAX_WINDOW_LENGTH - 1 + 16 downto 16));
|
write_last_window_complete <= '0';
|
config.acquisition_length <= unsigned(s_axis_ctrl_tdata(BW_MAX_WINDOW_LENGTH - 1 downto 0));
|
if s_axis_ctrl_tvalid = '1' and s_axis_ctrl_tready_int = '1' then
|
ram_ctrl_fsm <= START;
|
v_window_length := unsigned(s_axis_ctrl_tdata(BW_MAX_WINDOW_LENGTH - 1 + 16 downto 16));
|
wen_ram(v_write_ram_ptr) <= '1';
|
v_acquisition_length := unsigned(s_axis_ctrl_tdata(BW_MAX_WINDOW_LENGTH - 1 downto 0));
|
s_axis_ctrl_tready <= '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;
|
end if;
|
|
|
|
|
--
|
--
|
-- After the decoder is configured, the decoder is waiting for a new block
|
-- After the decoder is configured, the decoder is waiting for a new block.
|
-- When the AXIS handshake is there the packettransmission begins
|
-- 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 =>
|
when START =>
|
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
|
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;
|
if write_addr_ptr = config.window_length - 1 then
|
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;
|
|
|
|
--
|
-- When we switch to the next RAM, we reset the write addr.
|
-- The first arriving data have to be stored on special locations to guarantee
|
write_addr_ptr <= (others => '0');
|
-- a non malicious behavior of the traceback units.
|
|
--
|
-- Switch to the next RAM.
|
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;
|
|
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;
|
write_ram_ptr <= write_ram_ptr + 1;
|
switch_ram <= true;
|
wen_ram(to_integer(write_ram_ptr)) <= '0';
|
|
wen_ram(to_integer(write_ram_ptr + 1)) <= '1';
|
|
|
|
write_ram_fsm <= RUN;
|
else
|
else
|
write_addr_ptr <= write_addr_ptr + 1;
|
write_addr_ptr <= write_addr_ptr + 1;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
|
--
|
--
|
-- The running state handles the most decoding
|
-- The decoder is receiving data from the ACS.
|
-- It handels the writing of forward to ram and reading the decision vecotors
|
--
|
-- the decision vecotrs are forwarded to the traceback units.
|
when RUN =>
|
--
|
write_window_complete <= '0';
|
when RUNNING =>
|
write_last_window_complete <= '0';
|
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
|
if s_axis_input_tvalid = '1' and s_axis_input_tready_int = '1' then
|
|
write_addr_ptr <= write_addr_ptr + 1;
|
read_ram_data_ptr_d1 <= read_ram_ptr;
|
|
read_ram_data_ptr <= read_ram_data_ptr_d1;
|
if write_addr_ptr = config.window_length - 1 then
|
m_axis_output_tvalid_int <= m_axis_output_tvalid_d1;
|
|
m_axis_output_tvalid_d1 <= m_axis_output_tvalid_d2;
|
-- When we switch to the next RAM, we reset the write addr.
|
|
write_addr_ptr <= (others => '0');
|
if switch_ram then
|
|
if ram_writing then
|
-- Switch to the next RAM.
|
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';
|
|
end if;
|
|
switch_ram <= false;
|
|
else
|
|
if write_addr_ptr = config.window_m1 then
|
|
write_ram_ptr <= write_ram_ptr + 1;
|
write_ram_ptr <= write_ram_ptr + 1;
|
read_ram_ptr(next_traceback) <= write_ram_ptr;
|
wen_ram(to_integer(write_ram_ptr)) <= '0';
|
read_ram_ptr(not_next_traceback) <= write_ram_ptr - 2;
|
wen_ram(to_integer(write_ram_ptr + 1)) <= '1';
|
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
|
-- Indicate, that a complete window is within the RAM and traceback may start.
|
if s_axis_input_tlast = '1' then
|
write_window_complete <= '1';
|
ram_writing <= false;
|
|
last_addr_ptr <= write_addr_ptr;
|
if read_ram_fsm(0) /= WAIT_FOR_WINDOW and read_ram_fsm(1) /= WAIT_FOR_WINDOW then
|
-- wen_ram(v_write_ram_ptr) <= '0';
|
write_ram_fsm <= WAIT_FOR_TRACEBACK;
|
end if;
|
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
|
else
|
write_addr_ptr <= write_addr_ptr + 1;
|
write_addr_ptr <= write_addr_ptr + 1;
|
read_addr_ptr <= read_addr_ptr - 1;
|
|
end if;
|
end if;
|
|
|
-- Handle side channel information for traceback units.
|
if s_axis_input_tlast = '1' then
|
for i in 1 downto 0 loop
|
write_ram_fsm <= CONFIGURE;
|
if m_axis_output_tvalid_d1(i) = '1' then
|
wen_ram <= (others => '0');
|
data_cnt(i) <= data_cnt(i) + 1;
|
|
|
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;
|
end if;
|
|
read_last_addr_ptr <= write_addr_ptr;
|
|
|
-- Signals the valid signal
|
write_addr_ptr <= (others => '0');
|
if data_cnt(i) = config.window_p_acquisition_m2 then
|
write_ram_ptr <= write_ram_ptr + 1;
|
m_axis_output_tvalid_d2(i) <= '0';
|
|
end if;
|
end if;
|
if switch_ram and ram_writing then
|
|
m_axis_output_tvalid_d2(next_traceback) <= '1';
|
|
end if;
|
end if;
|
|
|
-- Signals the end of the current window
|
when WAIT_FOR_TRACEBACK =>
|
if m_axis_output_last_tuser_int(i) = '1' then
|
if read_ram_fsm(0) = WAIT_FOR_WINDOW or read_ram_fsm(1) = WAIT_FOR_WINDOW then
|
m_axis_output_last_tuser_int(i) <= '0';
|
write_ram_fsm <= RUN;
|
end if;
|
write_window_complete <= '0';
|
if data_cnt(i) = config.window_p_acquisition_m1 then
|
|
m_axis_output_last_tuser_int(i) <= '1';
|
|
end if;
|
end if;
|
|
|
-- Signals, whether there is acquisition or window
|
when WAIT_FOR_LAST_TRACEBACK =>
|
if data_cnt(i) = config.window_p_acquisition then
|
if read_ram_fsm(0) = WAIT_FOR_WINDOW or read_ram_fsm(1) = WAIT_FOR_WINDOW then
|
m_axis_output_window_tuser(i) <= '0';
|
write_ram_fsm <= CONFIGURE;
|
|
write_last_window_complete <= '0';
|
end if;
|
end if;
|
if data_cnt(i) = config.acquisition_length then
|
|
m_axis_output_window_tuser(i) <= '1';
|
end case;
|
end if;
|
end if;
|
end loop;
|
|
end if;
|
end if;
|
|
end process pr_write_ram;
|
|
|
--
|
|
-- 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
|
|
|
|
read_ram_data_ptr_d1 <= read_ram_ptr;
|
-------------------------------------------
|
read_ram_data_ptr <= read_ram_data_ptr_d1;
|
-- Manage reading from RAM for traceback --
|
m_axis_output_tvalid_int <= m_axis_output_tvalid_d1;
|
-------------------------------------------
|
|
|
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
|
gen_read_ram: for i in 0 to 1 generate
|
read_addr_ptr <= last_addr_ptr;
|
pr_read_ram: process(clk) is
|
elsif read_addr_ptr = 0 then
|
begin
|
read_ram_ptr(0) <= read_ram_ptr(0) - 1;
|
if rising_edge(clk) then
|
read_ram_ptr(1) <= read_ram_ptr(1) - 1;
|
if rst = '1' then
|
read_addr_ptr <= config.window_m1;
|
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
|
else
|
read_addr_ptr <= read_addr_ptr - 1;
|
|
end if;
|
|
|
|
if data_cnt(not_next_traceback) = config.window_p_acquisition_m1 then
|
read_ram_ptr_d(i) <= read_ram_ptr(i);
|
m_axis_output_last_tuser_int(not_next_traceback) <= '1';
|
case read_ram_fsm(i) is
|
m_axis_output_tvalid_d1(next_traceback) <= '1';
|
|
m_axis_output_tvalid_d1(not_next_traceback) <= '0';
|
-- Wait for the next window to be ready within the RAM.
|
|
when WAIT_FOR_WINDOW =>
|
|
read_addr_ptr(i) <= config.window_length - 1;
|
|
m_axis_output_tlast_int(i) <= '0';
|
|
m_axis_output_tvalid_int(i) <= '0';
|
|
m_axis_output_last_tuser_int(i) <= '0';
|
|
m_axis_output_window_tuser_int(i) <= '0';
|
|
read_ram_ptr(i) <= write_ram_ptr;
|
|
|
|
-- We always start from the RAM, which was written last.
|
|
if write_window_complete = '1' and next_traceback(i) = '1' then
|
|
read_ram_ptr(i) <= write_ram_ptr - 1;
|
|
read_addr_ptr(i) <= read_addr_ptr(i) - 1;
|
|
read_ram_fsm(i) <= TRACEBACK;
|
|
m_axis_output_tvalid_int(i) <= '1';
|
|
end if;
|
|
if write_last_window_complete = '1' and next_traceback(i) = '1' then
|
|
read_ram_ptr(i) <= write_ram_ptr - 1;
|
|
read_addr_ptr(i) <= read_last_addr_ptr;
|
|
read_ram_fsm(i) <= TRACEBACK;
|
|
m_axis_output_window_tuser_int(i) <= '1';
|
|
end if;
|
|
|
|
-- Perform the Traceback on the RAM data of the first RAM we need for acquisition and traceback.
|
|
when TRACEBACK =>
|
|
m_axis_output_tlast_int(i) <= '0';
|
|
m_axis_output_last_tuser_int(i) <= '0';
|
|
m_axis_output_tvalid_int(i) <= '1';
|
|
|
|
if m_axis_output_tready(i) = '1' then
|
|
if read_addr_ptr(i) = 0 then
|
|
if read_ram_fsm(1 - i) = TRACEBACK and read_ram_ptr(1 - i) = read_ram_ptr(i) - 1 then
|
|
read_ram_fsm(i) <= WAIT_FOR_RAM;
|
|
else
|
|
read_addr_ptr(i) <= config.window_length - 1;
|
|
read_ram_ptr(i) <= read_ram_ptr(i) - 1;
|
|
read_ram_fsm(i) <= FINISH;
|
|
end if;
|
|
else
|
|
read_addr_ptr(i) <= read_addr_ptr(i) - 1;
|
end if;
|
end if;
|
|
|
if data_cnt(not_next_traceback) = config.window_p_acquisition then
|
-- Signal the traceback unit, acquisition is over.
|
m_axis_output_window_tuser(not_next_traceback) <= '0';
|
if read_addr_ptr(i) = config.window_length - config.acquisition_length - 1 then
|
m_axis_output_window_tuser(next_traceback) <= '1';
|
m_axis_output_window_tuser_int(i) <= '1';
|
|
end if;
|
end if;
|
end if;
|
|
|
if data_cnt(not_next_traceback) = config.acquisition_length then
|
when WAIT_FOR_RAM =>
|
m_axis_output_window_tuser(not_next_traceback) <= '1';
|
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;
|
end if;
|
|
|
if m_axis_output_last_tuser_int(not_next_traceback) = '1' then
|
-- Get the remaining values from the second RAM we need for traceback (no acquisition values in this RAM)
|
m_axis_output_last_tuser_int(not_next_traceback) <= '0';
|
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;
|
end if;
|
|
if m_axis_output_tready(i) = '1' then
|
|
|
|
if read_addr_ptr(i) = config.window_length - config.acquisition_length then
|
|
m_axis_output_last_tuser_int(i) <= '1';
|
|
read_addr_ptr(i) <= config.window_length - 1;
|
|
read_ram_fsm(i) <= WAIT_FOR_WINDOW;
|
|
|
if data_cnt(next_traceback) = last_addr_ptr + config.acquisition_length - 1 then
|
-- Check if the other read process finished processing.
|
m_axis_output_tvalid_d1(next_traceback) <= '0';
|
if read_ram_fsm((i+1) mod 2) = WAIT_FOR_WINDOW and last_of_block = '1' then
|
m_axis_output_last_tuser_int(next_traceback) <= '1';
|
m_axis_output_tlast_int(i) <= '1';
|
m_axis_output_tlast(next_traceback) <= '1';
|
|
switch_state <= true;
|
|
end if;
|
end if;
|
|
|
-- block is finished and the decoder is ready for a new configuration and block
|
else
|
if switch_state then
|
read_addr_ptr(i) <= read_addr_ptr(i) - 1;
|
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;
|
end if;
|
end if;
|
end if;
|
end case;
|
end case;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process pr_ctrl_ram;
|
end process pr_read_ram;
|
|
end generate gen_read_ram;
|
|
|
|
-- This process decides which traceback unit is the next one to use.
|
|
pr_next_traceback: process(clk) is
|
|
begin
|
|
if rising_edge(clk) then
|
|
if rst = '1' then
|
|
next_traceback <= "01";
|
|
last_of_block <= '0';
|
|
else
|
|
if write_window_complete = '1' then
|
|
if next_traceback(0) = '1' then
|
|
next_traceback(0) <= '0';
|
|
next_traceback(1) <= '1';
|
|
else
|
|
next_traceback(0) <= '1';
|
|
next_traceback(1) <= '0';
|
|
end if;
|
|
end if;
|
|
|
|
if s_axis_input_tlast = '1' then
|
|
last_of_block <= '1';
|
|
end if;
|
|
|
|
end if;
|
|
end if;
|
|
end process pr_next_traceback;
|
|
|
------------------------------
|
------------------------------
|
--- Portmapping components ---
|
--- Portmapping components ---
|
------------------------------
|
------------------------------
|
|
|
gen_generic_sp_ram : for i in 0 to 3 generate
|
gen_generic_sp_ram : for i in 0 to 3 generate
|
begin
|
begin
|
|
|
|
addr(i) <= write_addr_ptr when (write_ram_fsm = RUN or write_ram_fsm = START) and to_integer(write_ram_ptr) = i else
|
|
read_addr_ptr(0) when (to_integer(read_ram_ptr(0)) = i and (read_ram_fsm(0) = TRACEBACK or read_ram_fsm(0) = WAIT_FOR_RAM or read_ram_fsm(0) = FINISH)) or
|
|
(next_traceback(0) = '1' and write_window_complete = '1' and to_integer(read_ram_ptr(0)) = i) else
|
|
read_addr_ptr(1);
|
|
|
inst_generic_sp_ram : generic_sp_ram
|
inst_generic_sp_ram : generic_sp_ram
|
generic map(
|
generic map(
|
DISTR_RAM => DISTRIBUTED_RAM,
|
DISTR_RAM => DISTRIBUTED_RAM,
|
WORDS => MAX_WINDOW_LENGTH,
|
WORDS => MAX_WINDOW_LENGTH,
|
BITWIDTH => NUMBER_TRELLIS_STATES
|
BITWIDTH => NUMBER_TRELLIS_STATES
|
)
|
)
|
port map(
|
port map(
|
clk => clk,
|
clk => clk,
|
rst => rst,
|
rst => rst,
|
wen => wen_ram(i),
|
wen => wen_ram(i),
|
en => en_ram(i),
|
en => '1',
|
a => std_logic_vector(addr(i)),
|
a => std_logic_vector(addr(i)),
|
d => d,
|
d => s_axis_input_tdata,
|
q => q_reg(i)
|
q => q_reg(i)
|
);
|
);
|
end generate gen_generic_sp_ram;
|
end generate gen_generic_sp_ram;
|
|
|
end architecture rtl;
|
end architecture rtl;
|