Skip to content
Snippets Groups Projects
Commit 7d5d0076 authored by Pepping's avatar Pepping
Browse files

Initial commit

parent 7fd88755
No related branches found
No related tags found
No related merge requests found
-------------------------------------------------------------------------------
--
-- 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 : Capture a block of streaming data for analysis via MM access
-- Description :
-- The first g_nof_data valid streaming data input words are stored in the
-- data buffer. Then they can be read via the MM interface. Dependend on
-- g_use_in_sync the nxt block of valid streaming data input words gets
-- stored when a new in_sync occurs or when the last word was read from via
-- the MM interface.
--
-- There are 3 modes of operation in the _dev version:
--
-- (1) NON-SYNC MODE: g_use_in_sync = FALSE
-- In this mode the first g_nof_data valid data input words are stored in the
-- data buffer. A new set of data will be stored when the last word is read
-- from the buffer via the MM interface.
--
-- (2) SYNC-MODE: g_use_in_sync = TRUE and reg_sync_delay = 0
-- On every received sync pulse a number of g_nof_data valid words are written
-- to the databuffer. Data will be overwritten on every new sync pulse. It is
-- up to the user to read out the data in time in between two sync pulses
--
-- (3) ARM-MODE: g_use_in_sync = TRUE and reg_sync_delay > 0
-- First the reg_sync_delay should be written with a desired delay value. Then
-- the arm register must be written. After being armed the databuffer will wait
-- for the first sync pulse to arrive. When it has arrived it will wait for
-- reg_sync_delay valid cycles before g_nof_data valid words are written to the
-- databuffer. The data can then be read out through the MM interface. New data
-- will only be written if the databuffer is being armed again.
--
-- Remarks:
-- . The actual RAM usage depends on g_data_w. Unused bits are forced to '0'
-- when read.
-- . The c_mm_factor must be a power of 2 factor. Typically c_mm_factor=1 is
-- sufficient for most purposes. If the application only requires
-- eg. c_mm_factor=3 then it needs to extend the data to c_mm_factor=4.
-- . If c_mm_factor=2 then in_data[g_data_w/2-1:0] will appear at MM address
-- even and in_data[g_data_w-1:g_data_w/2] at address odd.
-- The advantage of splitting at g_data_w/2 instead of at c_word_w=32 is
-- that streaming 36b data can then map on 18b RAM still fit in a single
-- RAM block. Whereas mapping the LS 32b part at even address and the MS 4b
-- part at odd address would require using c_word_w=32b RAM that could
-- require two RAM blocks. For g_data_w=2*c_word_w=64b there is no
-- difference between these 2 schemes. Hence by rising the g_data_w to a
-- power of 2 multiple of 32b the user can enforce using splitting the data
-- a c_word_w parts.
LIBRARY IEEE, common_lib, technology_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 work.diag_pkg.ALL;
USE technology_lib.technology_select_pkg.ALL;
ENTITY diag_data_buffer_dev IS
GENERIC (
g_technology : NATURAL := c_tech_select_default;
g_data_w : NATURAL := 32;
g_nof_data : NATURAL := 1024;
g_use_in_sync : BOOLEAN := FALSE -- when TRUE start filling the buffer at the in_sync, else after the last word was read
);
PORT (
-- Memory-mapped clock domain
mm_rst : IN STD_LOGIC;
mm_clk : IN STD_LOGIC;
ram_mm_mosi : IN t_mem_mosi; -- read and overwrite access to the data buffer
ram_mm_miso : OUT t_mem_miso;
reg_mm_mosi : IN t_mem_mosi := c_mem_mosi_rst;
reg_mm_miso : OUT t_mem_miso;
-- Streaming clock domain
st_rst : IN STD_LOGIC;
st_clk : IN STD_LOGIC;
in_data : IN STD_LOGIC_VECTOR(g_data_w-1 DOWNTO 0);
in_sync : IN STD_LOGIC := '0';
in_val : IN STD_LOGIC
);
END diag_data_buffer_dev;
ARCHITECTURE rtl OF diag_data_buffer_dev IS
CONSTANT c_mm_factor : NATURAL := ceil_div(g_data_w, c_word_w); -- must be a power of 2 multiple
CONSTANT c_nof_data_mm : NATURAL := g_nof_data*c_mm_factor;
CONSTANT g_data_mm_w : NATURAL := g_data_w/c_mm_factor;
CONSTANT c_buf_mm : t_c_mem := (latency => 1,
adr_w => ceil_log2(c_nof_data_mm),
dat_w => g_data_mm_w,
nof_dat => c_nof_data_mm,
init_sl => '0');
CONSTANT c_buf_st : t_c_mem := (latency => 1,
adr_w => ceil_log2(g_nof_data),
dat_w => g_data_w,
nof_dat => g_nof_data,
init_sl => '0');
CONSTANT c_reg : t_c_mem := (latency => 1,
adr_w => c_diag_db_dev_reg_adr_w,
dat_w => c_word_w, -- Use MM bus data width = c_word_w = 32 for all MM registers
nof_dat => c_diag_db_dev_reg_nof_dat, --3: reg_sync_delay 2: valid_cnt 1: word_cnt; 0:sync_cnt
init_sl => '0');
SIGNAL i_ram_mm_miso : t_mem_miso := c_mem_miso_rst; -- used to avoid vsim-8684 error "No drivers exist" for the unused fields
SIGNAL rd_last : STD_LOGIC;
SIGNAL rd_last_st : STD_LOGIC;
SIGNAL wr_sync : STD_LOGIC;
SIGNAL wr_done : STD_LOGIC;
SIGNAL nxt_wr_done : STD_LOGIC;
SIGNAL wr_data : STD_LOGIC_VECTOR(c_buf_st.dat_w-1 DOWNTO 0);
SIGNAL nxt_wr_data : STD_LOGIC_VECTOR(c_buf_st.dat_w-1 DOWNTO 0);
SIGNAL wr_addr : STD_LOGIC_VECTOR(c_buf_st.adr_w-1 DOWNTO 0);
SIGNAL nxt_wr_addr : STD_LOGIC_VECTOR(c_buf_st.adr_w-1 DOWNTO 0);
SIGNAL wr_en : STD_LOGIC;
SIGNAL nxt_wr_en : STD_LOGIC;
SIGNAL reg_rd_arr : STD_LOGIC_VECTOR(c_reg.nof_dat-1 DOWNTO 0);
SIGNAL reg_wr_arr : STD_LOGIC_VECTOR(c_reg.nof_dat-1 DOWNTO 0);
SIGNAL reg_slv_rd : STD_LOGIC_VECTOR(c_reg.nof_dat*c_word_w-1 DOWNTO 0);
SIGNAL reg_slv_wr : STD_LOGIC_VECTOR(c_reg.nof_dat*c_word_w-1 DOWNTO 0);
SIGNAL arm_enable : STD_LOGIC := '0';
SIGNAL sync_cnt_clr : STD_LOGIC := '0';
SIGNAL sync_cnt : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); -- Nof times buffer has been written
SIGNAL word_cnt : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0) := (OTHERS=>'0');
SIGNAL valid_cnt : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0) := (OTHERS=>'0');
SIGNAL reg_sync_delay : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0) := (OTHERS=>'0');
TYPE state_type is (s_idle, s_sync_count, s_wait_for_rd_last, s_armed);
TYPE reg_type IS RECORD
wr_sync : STD_LOGIC;
state : state_type; -- The state machine.
END RECORD;
SIGNAL r, rin : reg_type;
BEGIN
ASSERT c_mm_factor=2**true_log2(c_mm_factor) REPORT "Only support mixed width data that uses a power of 2 multiple." SEVERITY FAILURE;
ram_mm_miso <= i_ram_mm_miso;
rd_last <= '1' WHEN UNSIGNED(ram_mm_mosi.address(c_buf_mm.adr_w-1 DOWNTO 0))=c_nof_data_mm-1 AND ram_mm_mosi.rd='1' ELSE '0';
u_rd_last_clock_cross : ENTITY common_lib.common_spulse
GENERIC MAP (
g_delay_len => c_meta_delay_len
)
PORT MAP (
in_rst => mm_rst,
in_clk => mm_clk,
in_pulse => rd_last,
out_rst => st_rst,
out_clk => st_clk,
out_pulse => rd_last_st
);
-- Determine the write trigger in NON-SYNC MODE
use_rd_last : IF g_use_in_sync=FALSE GENERATE
wr_sync <= rd_last_st;
END GENERATE;
-- Determine the write trigger in SYNC MODE and ARM MODE
use_in_sync : IF g_use_in_sync=TRUE GENERATE
comb : PROCESS(st_rst, r, in_sync, rd_last_st, reg_sync_delay, arm_enable, valid_cnt)
VARIABLE v : reg_type;
BEGIN
v := r;
v.wr_sync := '0';
CASE r.state IS
WHEN s_idle =>
IF arm_enable = '1' THEN
v.state := s_armed;
END IF;
WHEN s_armed =>
IF (in_sync = '1' AND TO_UINT(reg_sync_delay) = 1) THEN
v.wr_sync := '1';
v.state := s_wait_for_rd_last;
ELSIF(in_sync = '1' AND TO_UINT(reg_sync_delay) > 1) THEN
v.state := s_sync_count;
END IF;
WHEN s_sync_count =>
IF ((TO_UINT(valid_cnt)+2) >= TO_UINT(reg_sync_delay)) THEN
v.wr_sync := '1';
v.state := s_wait_for_rd_last;
END IF;
WHEN s_wait_for_rd_last =>
IF rd_last_st = '1' THEN
v.state := s_idle;
ELSIF arm_enable = '1' THEN
v.state := s_armed;
END IF;
WHEN OTHERS =>
v.state := s_idle;
END CASE;
IF st_rst = '1' THEN
v.wr_sync := '0';
v.state := s_idle;
END IF;
rin <= v;
END PROCESS comb;
regs : PROCESS(st_clk)
BEGIN
IF rising_edge(st_clk) THEN
r <= rin;
END IF;
END PROCESS;
-- Choose between SYNC MODE and ARM MODE.
wr_sync <= in_sync WHEN TO_UINT(reg_sync_delay) = 0 ELSE r.wr_sync;
END GENERATE;
p_st_clk : PROCESS (st_clk, st_rst)
BEGIN
IF st_rst='1' THEN
wr_data <= (OTHERS => '0');
wr_addr <= (OTHERS => '0');
wr_en <= '0';
wr_done <= '0';
ELSIF rising_edge(st_clk) THEN
wr_data <= nxt_wr_data;
wr_addr <= nxt_wr_addr;
wr_en <= nxt_wr_en;
wr_done <= nxt_wr_done;
END IF;
END PROCESS;
-- Write access control
nxt_wr_data <= in_data;
nxt_wr_en <= in_val AND NOT nxt_wr_done;
p_wr_addr : PROCESS (wr_done, wr_addr, wr_sync, wr_en)
BEGIN
nxt_wr_done <= wr_done;
nxt_wr_addr <= wr_addr;
IF wr_sync='1' THEN
nxt_wr_done <= '0';
nxt_wr_addr <= (OTHERS => '0');
ELSIF wr_en='1' THEN
IF UNSIGNED(wr_addr)=g_nof_data-1 THEN
nxt_wr_done <= '1'; -- keep wr_addr, do not allow wr_addr increment >= g_nof_data to avoid RAM address out-of-bound warning in Modelsim in case c_buf.nof_dat < 2**c_buf.adr_w
ELSE
nxt_wr_addr <= INCR_UVEC(wr_addr, 1);
END IF;
END IF;
END PROCESS;
u_buf : ENTITY common_lib.common_ram_crw_crw_ratio
GENERIC MAP (
g_technology => g_technology,
g_ram_a => c_buf_mm,
g_ram_b => c_buf_st,
g_init_file => "UNUSED"
)
PORT MAP (
-- MM read/write port clock domain
rst_a => mm_rst,
clk_a => mm_clk,
wr_en_a => ram_mm_mosi.wr,
wr_dat_a => ram_mm_mosi.wrdata(c_buf_mm.dat_w-1 DOWNTO 0),
adr_a => ram_mm_mosi.address(c_buf_mm.adr_w-1 DOWNTO 0),
rd_en_a => ram_mm_mosi.rd,
rd_dat_a => i_ram_mm_miso.rddata(c_buf_mm.dat_w-1 DOWNTO 0),
rd_val_a => i_ram_mm_miso.rdval,
-- ST write only port clock domain
rst_b => st_rst,
clk_b => st_clk,
wr_en_b => wr_en,
wr_dat_b => wr_data,
adr_b => wr_addr,
rd_en_b => '0',
rd_dat_b => OPEN,
rd_val_b => OPEN
);
u_reg : ENTITY common_lib.common_reg_r_w_dc
GENERIC MAP (
g_reg => c_reg
)
PORT MAP (
-- Clocks and reset
mm_rst => mm_rst,
mm_clk => mm_clk,
st_rst => st_rst,
st_clk => st_clk,
-- Memory Mapped Slave in mm_clk domain
sla_in => reg_mm_mosi,
sla_out => reg_mm_miso,
-- MM registers in st_clk domain
reg_wr_arr => reg_wr_arr,
reg_rd_arr => reg_rd_arr,
in_reg => reg_slv_rd,
out_reg => reg_slv_wr
);
arm_enable <= reg_wr_arr(2);
reg_sync_delay <= reg_slv_wr(4*c_word_w-1 DOWNTO 3*c_word_w);
reg_slv_rd <= reg_sync_delay & valid_cnt & word_cnt & sync_cnt;
u_word_cnt : ENTITY common_lib.common_counter
PORT MAP (
rst => st_rst,
clk => st_clk,
cnt_en => wr_en,
cnt_clr => wr_sync,
count => word_cnt
);
u_sync_cnt : ENTITY common_lib.common_counter
PORT MAP (
rst => st_rst,
clk => st_clk,
cnt_en => wr_sync,
cnt_clr => sync_cnt_clr,
count => sync_cnt
);
u_valid_cnt : ENTITY common_lib.common_counter
PORT MAP (
rst => st_rst,
clk => st_clk,
cnt_en => in_val,
cnt_clr => in_sync,
count => valid_cnt
);
END rtl;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment