-
Eric Kooistra authoredEric Kooistra authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
mms_diag_data_buffer.vhd 9.21 KiB
-------------------------------------------------------------------------------
--
-- Copyright (C) 2011
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-------------------------------------------------------------------------------
-- Purpose: MM data buffer and Rx seq for multiple parallel SOSI streams
-- Description:
-- . g_use_db
-- The mms_diag_data_buffer can capture data from an input stream in a data
-- buffer when g_use_db=TRUE. Dependend on g_buf_use_sync the data buffer
-- is rewritten after each in_sync or when the last word was read via MM.
-- . g_use_rx_seq
-- The mms_diag_data_buffer can continously verify a input Rx data sequence
-- when g_use_rx_seq=TRUE. The expected sequence data is typically generated
-- by an remote upstream tx_seq source.
-- . The advantage of the rx_seq is that is can continously verify the
-- correctness of all rx data in hardware, whereas the DB can only take a
-- snapshot that then needs to be examined via MM. The advandage of the DB
-- is that it can take a snapshot of the values of the received data. The
-- DB requires RAM resources and the rx_seq does not.
--
-- Block diagram:
--
-- g_use_db
-- g_buf_use_sync
-- .
-- . g_use_tx_seq
-- . .
-- . .
-- /-------------> Rx seq
-- | . |
-- in_sosi_arr -----*---> DB RAM |
-- in_sync -------------> DB reg |
-- || |
-- || |
-- MM ================================
--
-- Remark:
-- . A nice new feature would be to continuously write the DB and to stop
-- writting it on a trigger. This trigger can then eg. be when the rx_seq
-- detects an error. By delaying the trigger somewhat it the DB can then
-- capture some data before and after the trigger event.
LIBRARY IEEE, common_lib, technology_lib, dp_lib;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
USE common_lib.common_pkg.ALL;
USE common_lib.common_mem_pkg.ALL;
USE dp_lib.dp_stream_pkg.ALL;
USE work.diag_pkg.ALL;
USE technology_lib.technology_select_pkg.ALL;
ENTITY mms_diag_data_buffer IS
GENERIC (
g_technology : NATURAL := c_tech_select_default;
-- Generate configurations
g_use_db : BOOLEAN := TRUE;
g_use_rx_seq : BOOLEAN := FALSE;
-- General
g_nof_streams : POSITIVE := 16; -- each stream gets an data buffer
-- DB settings
g_data_type : t_diag_data_type_enum := e_data; -- define the sosi field that gets stored: e_data=data, e_complex=im&re, e_real=re, e_imag=im
g_data_w : NATURAL := 32; -- the g_data_w is the width of the data, re, im values or of the combined im&re value
g_buf_nof_data : NATURAL := 1024; -- nof words per data buffer
g_buf_use_sync : BOOLEAN := FALSE; -- when TRUE start filling the buffer at the in_sync, else after the last word was read
-- Rx_seq
g_use_steps : BOOLEAN := FALSE;
g_nof_steps : NATURAL := c_diag_seq_rx_reg_nof_steps;
g_seq_dat_w : NATURAL := 32 -- >= 1, test sequence data width. Choose g_seq_dat_w <= g_data_w
);
PORT (
-- System
mm_rst : IN STD_LOGIC;
mm_clk : IN STD_LOGIC;
dp_rst : IN STD_LOGIC;
dp_clk : IN STD_LOGIC;
-- MM interface
reg_data_buf_mosi : IN t_mem_mosi := c_mem_mosi_rst; -- DB control register (one per stream)
reg_data_buf_miso : OUT t_mem_miso;
ram_data_buf_mosi : IN t_mem_mosi := c_mem_mosi_rst; -- DB buffer RAM (one per streams)
ram_data_buf_miso : OUT t_mem_miso;
reg_rx_seq_mosi : IN t_mem_mosi := c_mem_mosi_rst; -- Rx seq control register (one per streams)
reg_rx_seq_miso : OUT t_mem_miso;
-- ST interface
in_sync : IN STD_LOGIC := '0'; -- input sync pulse in ST dp_clk domain that starts data buffer when g_use_in_sync = TRUE
in_sosi_arr : IN t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0)
);
END mms_diag_data_buffer;
ARCHITECTURE str OF mms_diag_data_buffer IS
CONSTANT c_buf_mm_factor : NATURAL := ceil_div(g_data_w, c_word_w);
CONSTANT c_buf_nof_data_mm : NATURAL := g_buf_nof_data*c_buf_mm_factor;
CONSTANT c_buf_adr_w : NATURAL := ceil_log2(c_buf_nof_data_mm);
CONSTANT c_reg_adr_w : NATURAL := c_diag_db_reg_adr_w;
TYPE t_data_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(g_data_w-1 DOWNTO 0);
SIGNAL in_data_arr : t_data_arr(g_nof_streams-1 DOWNTO 0);
SIGNAL ram_data_buf_mosi_arr : t_mem_mosi_arr(g_nof_streams-1 DOWNTO 0);
SIGNAL ram_data_buf_miso_arr : t_mem_miso_arr(g_nof_streams-1 DOWNTO 0);
SIGNAL reg_data_buf_mosi_arr : t_mem_mosi_arr(g_nof_streams-1 DOWNTO 0);
SIGNAL reg_data_buf_miso_arr : t_mem_miso_arr(g_nof_streams-1 DOWNTO 0);
BEGIN
no_db : IF g_use_db=FALSE GENERATE
ram_data_buf_miso <= c_mem_miso_rst;
reg_data_buf_miso <= c_mem_miso_rst;
END GENERATE;
gen_db : IF g_use_db=TRUE GENERATE
-- Combine the internal array of mm interfaces for the data_buf to one array that is connected to the port of the MM bus
u_mem_mux_data_buf : ENTITY common_lib.common_mem_mux
GENERIC MAP (
g_nof_mosi => g_nof_streams,
g_mult_addr_w => c_buf_adr_w
)
PORT MAP (
mosi => ram_data_buf_mosi,
miso => ram_data_buf_miso,
mosi_arr => ram_data_buf_mosi_arr,
miso_arr => ram_data_buf_miso_arr
);
u_mem_mux_reg : ENTITY common_lib.common_mem_mux
GENERIC MAP (
g_nof_mosi => g_nof_streams,
g_mult_addr_w => c_reg_adr_w
)
PORT MAP (
mosi => reg_data_buf_mosi,
miso => reg_data_buf_miso,
mosi_arr => reg_data_buf_mosi_arr,
miso_arr => reg_data_buf_miso_arr
);
gen_stream : FOR I IN 0 TO g_nof_streams-1 GENERATE
in_data_arr(I) <= in_sosi_arr(I).im(g_data_w/2-1 DOWNTO 0) & in_sosi_arr(I).re(g_data_w/2-1 DOWNTO 0) WHEN g_data_type=e_complex ELSE
in_sosi_arr(I).re(g_data_w-1 DOWNTO 0) WHEN g_data_type=e_real ELSE
in_sosi_arr(I).im(g_data_w-1 DOWNTO 0) WHEN g_data_type=e_imag ELSE
in_sosi_arr(I).data(g_data_w-1 DOWNTO 0); -- g_data_type=e_data is default
u_diag_data_buffer : ENTITY work.diag_data_buffer
GENERIC MAP (
g_technology => g_technology,
g_data_w => g_data_w,
g_nof_data => g_buf_nof_data,
g_use_in_sync => g_buf_use_sync -- when TRUE start filling the buffer at the in_sync, else after the last word was read
)
PORT MAP (
-- Memory-mapped clock domain
mm_rst => mm_rst,
mm_clk => mm_clk,
ram_mm_mosi => ram_data_buf_mosi_arr(I),
ram_mm_miso => ram_data_buf_miso_arr(I),
reg_mm_mosi => reg_data_buf_mosi_arr(I),
reg_mm_miso => reg_data_buf_miso_arr(I),
-- Streaming clock domain
st_rst => dp_rst,
st_clk => dp_clk,
in_data => in_data_arr(I),
in_sync => in_sync,
in_val => in_sosi_arr(I).valid
);
END GENERATE;
END GENERATE;
no_rx_seq : IF g_use_rx_seq=FALSE GENERATE
reg_rx_seq_miso <= c_mem_miso_rst;
END GENERATE;
gen_rx_seq : IF g_use_rx_seq=TRUE GENERATE
u_mms_diag_rx_seq : ENTITY work.mms_diag_rx_seq
GENERIC MAP (
g_nof_streams => g_nof_streams,
g_use_steps => g_use_steps,
g_nof_steps => g_nof_steps,
g_seq_dat_w => g_seq_dat_w, -- >= 1, test sequence data width
g_data_w => g_data_w -- >= g_seq_dat_w, user data width
)
PORT MAP (
-- Clocks and reset
mm_rst => mm_rst,
mm_clk => mm_clk,
dp_rst => dp_rst,
dp_clk => dp_clk,
-- Memory Mapped Slave
reg_mosi => reg_rx_seq_mosi, -- multiplexed port for g_nof_streams MM control/status registers
reg_miso => reg_rx_seq_miso,
-- Streaming interface
rx_snk_in_arr => in_sosi_arr
);
END GENERATE;
END str;