Skip to content
Snippets Groups Projects
Commit 31df60fc authored by Eric Kooistra's avatar Eric Kooistra
Browse files

Merge branch 'L2SDP-364' into 'master'

st_histogram updates. Ready for integration in LOFAR2.

Closes L2SDP-364

See merge request desp/hdl!137
parents ea6187b8 12cfc82e
Branches
No related tags found
1 merge request!137st_histogram updates. Ready for integration in LOFAR2.
......@@ -60,13 +60,13 @@ PACKAGE common_mem_pkg IS
CONSTANT c_mem_address_sz : NATURAL := c_mem_address_w/c_byte_w;
CONSTANT c_mem_data_sz : NATURAL := c_mem_data_w/c_byte_w;
TYPE t_mem_miso IS RECORD -- Master In Slave Out
TYPE t_mem_miso IS RECORD -- Master In Slave Out. For backward compatibility only. Use t_mem_copi for new designs.
rddata : STD_LOGIC_VECTOR(c_mem_data_w-1 DOWNTO 0); -- data width (suits 1, 2 or 4 bytes)
rdval : STD_LOGIC;
waitrequest : STD_LOGIC;
END RECORD;
TYPE t_mem_mosi IS RECORD -- Master Out Slave In
TYPE t_mem_mosi IS RECORD -- Master Out Slave In. For backward compatibility only. Use t_mem_cipo for new designs.
address : STD_LOGIC_VECTOR(c_mem_address_w-1 DOWNTO 0); -- address range (suits 32-bit processor)
wrdata : STD_LOGIC_VECTOR(c_mem_data_w-1 DOWNTO 0); -- data width (suits 1, 2 or 4 bytes)
wr : STD_LOGIC;
......@@ -95,6 +95,16 @@ PACKAGE common_mem_pkg IS
FUNCTION RESIZE_MEM_SDATA( vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR; -- sign extended
FUNCTION RESIZE_MEM_XDATA( vec : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR; -- set unused MSBits to 'X'
-- MOSI/MISO subtypes
SUBTYPE t_mem_copi IS t_mem_mosi; -- Controller Out Peripheral In
SUBTYPE t_mem_cipo IS t_mem_miso; -- Peripheral In Controller Out
CONSTANT c_mem_cipo_rst : t_mem_cipo := c_mem_miso_rst;
CONSTANT c_mem_copi_rst : t_mem_copi := c_mem_mosi_rst;
SUBTYPE t_mem_cipo_arr IS t_mem_miso_arr;
SUBTYPE t_mem_copi_arr IS t_mem_mosi_arr;
------------------------------------------------------------------------------
-- Burst memory access (for DDR access interface)
......
......@@ -16,8 +16,7 @@ synth_files =
src/vhdl/st_xst.vhd
# src/vhdl/st_top.vhd
src/vhdl/st_histogram.vhd
src/vhdl/st_histogram_reg.vhd
src/vhdl/mms_st_histogram.vhd
src/vhdl/mmp_st_histogram.vhd
tb/vhdl/tb_st_pkg.vhd
......@@ -31,7 +30,7 @@ test_bench_files =
tb/vhdl/tb_tb_st_xst.vhd
tb/vhdl/tb_st_histogram.vhd
tb/vhdl/tb_mms_st_histogram.vhd
tb/vhdl/tb_mmp_st_histogram.vhd
tb/vhdl/tb_st_histogram.vhd
tb/vhdl/tb_tb_st_histogram.vhd
......
-------------------------------------------------------------------------------
--
-- Copyright 2020
-- Copyright 2021
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
......@@ -21,22 +21,18 @@
-- Author:
-- . Daniel van der Schuur
-- Purpose:
-- . MMS-wrapper that adds registers and multi-instance support to st_histogram.
-- . MMP-wrapper that adds MM clock domain RAM readout and and multi-instance
-- support to st_histogram.
-- Description:
-- . st_histogram_reg implements the registers to control all g_nof_instances
-- . This MMS wrapper contains logic to fill a local RAM with the contents of
-- a selected st_histogram instance.
-- Usage (see st_histogram_reg.vhd for the register map):
-- . Reading RAM contents:
-- 1) User writes instance to read (0..g_nof_instances-1) to ram_fill_inst
-- register via reg_mosi
-- 2) Users writes to bit 0 of fill_ram register via reg_mosi
-- . ram_filling status will go high
-- 3) User reads ram_filling status until it reads zero via reg_mosi
-- 4) User reads freshly filled RAM contents via ram_mosi
-- . Clearing the RAMs:
-- . The inactive RAM is cleared automatically just before the next input sync.
-- . ram_clearing status will go high during this time.
-- . Adds logic to move st_histogram RAM contents into the dual clock RAM for
-- readout in MM clock domain.
-- . Per instance there are at least (or more dependent on g_nof_bins) two
-- block RAM:
-- . one dual page block RAM in st_histogram in the dp_clk domain that
-- accumulate or hold the bin values for every sync interval,
-- . one dual clock block RAM here to provide the read access to the
-- page with the hold bin values via the mm_clk domain.
LIBRARY IEEE, common_lib, mm_lib, technology_lib, dp_lib;
USE IEEE.std_logic_1164.ALL;
......@@ -45,7 +41,7 @@ USE common_lib.common_mem_pkg.ALL;
USE dp_lib.dp_stream_pkg.ALL;
USE technology_lib.technology_select_pkg.ALL;
ENTITY mms_st_histogram IS
ENTITY mmp_st_histogram IS
GENERIC (
g_nof_instances : NATURAL;
g_data_w : NATURAL;
......@@ -61,19 +57,25 @@ ENTITY mms_st_histogram IS
mm_clk : IN STD_LOGIC;
mm_rst : IN STD_LOGIC;
reg_mosi : IN t_mem_mosi;
reg_miso : OUT t_mem_miso;
ram_mosi : IN t_mem_mosi;
ram_miso : OUT t_mem_miso
ram_copi : IN t_mem_copi;
ram_cipo : OUT t_mem_cipo
);
END mms_st_histogram;
END mmp_st_histogram;
ARCHITECTURE str OF mms_st_histogram IS
ARCHITECTURE str OF mmp_st_histogram IS
-------------------------------------------------------------------------------
-- st_histogram instances
-------------------------------------------------------------------------------
SIGNAL st_histogram_ram_copi_arr : t_mem_copi_arr(g_nof_instances-1 DOWNTO 0);
SIGNAL st_histogram_ram_cipo_arr : t_mem_cipo_arr(g_nof_instances-1 DOWNTO 0);
-------------------------------------------------------------------------------
-- Dual clock RAM
-------------------------------------------------------------------------------
CONSTANT c_reg_adr_w : NATURAL := 1;
CONSTANT c_ram_adr_w : NATURAL := ceil_log2(g_nof_bins);
CONSTANT c_ram_dat_w : NATURAL := ceil_log2(g_nof_data_per_sync);
CONSTANT c_ram_dat_w : NATURAL := ceil_log2(g_nof_data_per_sync+1);
CONSTANT c_ram : t_c_mem := (latency => 1,
adr_w => c_ram_adr_w,
......@@ -83,30 +85,31 @@ ARCHITECTURE str OF mms_st_histogram IS
CONSTANT c_addr_high : NATURAL := g_nof_bins-1;
SIGNAL common_ram_cr_cw_wr_mosi : t_mem_mosi;
SIGNAL nxt_common_ram_cr_cw_wr_mosi : t_mem_mosi;
SIGNAL common_ram_cr_cw_rd_mosi : t_mem_mosi;
SIGNAL common_ram_cr_cw_rd_miso : t_mem_miso;
SIGNAL ram_mosi_arr : t_mem_mosi_arr(g_nof_instances-1 DOWNTO 0);
SIGNAL ram_miso_arr : t_mem_miso_arr(g_nof_instances-1 DOWNTO 0);
SIGNAL ram_clearing_arr : STD_LOGIC_VECTOR(g_nof_instances-1 DOWNTO 0);
SIGNAL wr_copi_arr : t_mem_copi_arr(g_nof_instances-1 DOWNTO 0);
-------------------------------------------------------------------------------
-- Logic to move st_histogram RAM contents into the dual clock RAM
-------------------------------------------------------------------------------
SIGNAL ram_fill_arr : STD_LOGIC_VECTOR(g_nof_instances-1 DOWNTO 0);
SIGNAL ram_fill_inst : STD_LOGIC_VECTOR(ceil_log2(g_nof_instances)-1 DOWNTO 0);
SIGNAL ram_fill_inst_int : NATURAL;
SIGNAL ram_fill : STD_LOGIC;
SIGNAL ram_filling : STD_LOGIC;
SIGNAL nxt_ram_filling : STD_LOGIC;
SIGNAL address : STD_LOGIC_VECTOR(c_ram_adr_w-1 DOWNTO 0);
SIGNAL nxt_address : STD_LOGIC_VECTOR(c_ram_adr_w-1 DOWNTO 0);
SIGNAL ram_address : STD_LOGIC_VECTOR(c_ram_adr_w-1 DOWNTO 0);
SIGNAL nxt_ram_address : STD_LOGIC_VECTOR(c_ram_adr_w-1 DOWNTO 0);
-------------------------------------------------------------------------------
-- MM multiplexing
-------------------------------------------------------------------------------
SIGNAL ram_copi_arr : t_mem_copi_arr(g_nof_instances-1 DOWNTO 0);
SIGNAL ram_cipo_arr : t_mem_cipo_arr(g_nof_instances-1 DOWNTO 0);
BEGIN
-------------------------------------------------------------------------------
-- st_histogram instances and their registers
-- st_histogram instances
-------------------------------------------------------------------------------
gen_st_histogram : FOR i IN 0 TO g_nof_instances-1 GENERATE
u_st_histogram : ENTITY work.st_histogram
......@@ -121,38 +124,17 @@ BEGIN
snk_in => snk_in_arr(i),
ram_clearing => ram_clearing_arr(i),
ram_mosi => ram_mosi_arr(i),
ram_miso => ram_miso_arr(i)
ram_mosi => st_histogram_ram_copi_arr(i),
ram_miso => st_histogram_ram_cipo_arr(i)
);
END GENERATE;
u_st_histogram_reg : ENTITY work.st_histogram_reg
GENERIC MAP (
g_nof_instances => g_nof_instances
)
PORT MAP (
dp_clk => dp_clk,
dp_rst => dp_rst,
ram_clearing => ram_clearing_arr(0),
ram_filling => ram_filling,
mm_clk => mm_clk,
mm_rst => mm_rst,
ram_fill_inst => ram_fill_inst,
ram_fill => ram_fill,
reg_mosi => reg_mosi,
reg_miso => reg_miso
);
-------------------------------------------------------------------------------
-- Dual clock RAM: DP write side, MM read side
-- . How do we get the st_histogram RAM contents into the RAMs below?
-- . DPRAM -> read>write process -> MM RAM
-------------------------------------------------------------------------------
gen_common_ram_cr_cw : FOR i IN 0 TO g_nof_instances-1 GENERATE
u_common_ram_cr_cw : ENTITY common_lib.common_ram_cr_cw
GENERIC MAP (
g_technology => c_tech_select_default,
......@@ -163,71 +145,71 @@ BEGIN
wr_clk => dp_clk,
wr_rst => dp_rst,
wr_clken => '1',
wr_en => common_ram_cr_cw_wr_mosi.wr,
wr_adr => common_ram_cr_cw_wr_mosi.address(c_ram_adr_w-1 DOWNTO 0),
wr_dat => common_ram_cr_cw_wr_mosi.wrdata(c_ram_dat_w-1 DOWNTO 0),
wr_en => wr_copi_arr(i).wr,
wr_adr => wr_copi_arr(i).address(c_ram_adr_w-1 DOWNTO 0),
wr_dat => wr_copi_arr(i).wrdata(c_ram_dat_w-1 DOWNTO 0),
rd_clk => mm_clk,
rd_rst => mm_rst,
rd_clken => '1',
rd_en => common_ram_cr_cw_rd_mosi.rd,
rd_adr => common_ram_cr_cw_rd_mosi.address(c_ram_adr_w-1 DOWNTO 0),
rd_dat => common_ram_cr_cw_rd_miso.rddata(c_ram_dat_w-1 DOWNTO 0),
rd_val => common_ram_cr_cw_rd_miso.rdval
rd_en => ram_copi_arr(i).rd,
rd_adr => ram_copi_arr(i).address(c_ram_adr_w-1 DOWNTO 0),
rd_dat => ram_cipo_arr(i).rddata(c_ram_dat_w-1 DOWNTO 0),
rd_val => ram_cipo_arr(i).rdval
);
-- User side MM bus for histogram readout
common_ram_cr_cw_rd_mosi <= ram_mosi;
ram_miso <= common_ram_cr_cw_rd_miso;
END GENERATE;
-------------------------------------------------------------------------------
-- Logic to move st_histogram RAM contents into the dual clock RAM above
-------------------------------------------------------------------------------
-- Use only the status signal of st_histogram instance 0
ram_fill <= snk_in_arr(0).sync;
-- Keep track of ram_filling status and ram_address (used for reading and writing)
nxt_ram_filling <= '0' WHEN TO_UINT(ram_address)=c_addr_high ELSE '1' WHEN ram_fill='1' ELSE ram_filling;
nxt_ram_address <= (OTHERS=>'0') WHEN ram_filling='0' ELSE INCR_UVEC(ram_address, 1) WHEN ram_filling='1' ELSE ram_address;
-- Do read request on ram_copi when ram_filling
gen_copi_arr: FOR i IN 0 TO g_nof_instances-1 GENERATE
st_histogram_ram_copi_arr(i).wr <= '0';
st_histogram_ram_copi_arr(i).wrdata <= (OTHERS=>'0');
st_histogram_ram_copi_arr(i).rd <= ram_filling;
st_histogram_ram_copi_arr(i).address(c_ram_adr_w-1 DOWNTO 0) <= ram_address;
END GENERATE;
-- Keep track of ram_filling status and address
nxt_ram_filling <= '0' WHEN TO_UINT(address)=c_addr_high ELSE '1' WHEN ram_fill='1' ELSE ram_filling;
nxt_address <= (OTHERS=>'0') WHEN ram_filling='0' ELSE INCR_UVEC(address, 1) WHEN ram_filling='1' ELSE address;
-- Help signal for bus selection
ram_fill_inst_int <= TO_UINT(ram_fill_inst);
-- Do read request on ram_mosi when ram_filling
p_mosi_arr: PROCESS (ram_filling, address, ram_fill_inst_int)
BEGIN
FOR i IN 0 TO g_nof_instances-1 LOOP
ram_mosi_arr(i) <= c_mem_mosi_rst;
IF i = ram_fill_inst_int THEN
ram_mosi_arr(i).rd <= ram_filling;
ram_mosi_arr(i).address(c_ram_adr_w-1 DOWNTO 0) <= address;
END IF;
END LOOP;
END PROCESS;
-- Forward the read histogram data from ram_miso into write mosi of dual clock RAM
p_rd_miso_to_wr_mosi : PROCESS(ram_miso_arr, ram_fill_inst_int, address)
BEGIN
nxt_common_ram_cr_cw_wr_mosi <= common_ram_cr_cw_wr_mosi;
FOR i IN 0 TO g_nof_instances-1 LOOP
IF i = ram_fill_inst_int THEN
nxt_common_ram_cr_cw_wr_mosi.wr <= ram_miso_arr(i).rdval;
nxt_common_ram_cr_cw_wr_mosi.wrdata(c_ram_dat_w-1 DOWNTO 0) <= ram_miso_arr(i).rddata(c_ram_dat_w-1 DOWNTO 0);
nxt_common_ram_cr_cw_wr_mosi.address(c_ram_adr_w-1 DOWNTO 0) <= address;
END IF;
END LOOP;
END PROCESS;
-- Forward the read histogram data from ram_cipo into write copi of dual clock RAM
gen_rd_cipo_to_wr_copi: FOR i IN 0 TO g_nof_instances-1 GENERATE
wr_copi_arr(i).wr <= st_histogram_ram_cipo_arr(i).rdval;
wr_copi_arr(i).wrdata(c_ram_dat_w-1 DOWNTO 0) <= st_histogram_ram_cipo_arr(i).rddata(c_ram_dat_w-1 DOWNTO 0);
wr_copi_arr(i).address(c_ram_adr_w-1 DOWNTO 0) <= ram_address;
END GENERATE;
-- Registers
p_clk : PROCESS(dp_clk, dp_rst) IS
BEGIN
IF dp_rst = '1' THEN
common_ram_cr_cw_wr_mosi <= c_mem_mosi_rst;
address <= (OTHERS=>'0');
ram_address <= (OTHERS=>'0');
ram_filling <= '0';
ELSIF RISING_EDGE(dp_clk) THEN
common_ram_cr_cw_wr_mosi <= nxt_common_ram_cr_cw_wr_mosi;
address <= nxt_address;
ram_address <= nxt_ram_address;
ram_filling <= nxt_ram_filling;
END IF;
END PROCESS;
-------------------------------------------------------------------------------
-- MM multiplexing
-------------------------------------------------------------------------------
u_common_mem_mux : ENTITY common_lib.common_mem_mux
GENERIC MAP (
g_nof_mosi => g_nof_instances,
g_mult_addr_w => c_ram_adr_w
)
PORT MAP (
mosi => ram_copi,
miso => ram_cipo,
mosi_arr => ram_copi_arr,
miso_arr => ram_cipo_arr
);
END str;
This diff is collapsed.
-------------------------------------------------------------------------------
--
-- Copyright 2020
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-------------------------------------------------------------------------------
-- Author:
-- . Daniel van der Schuur
-- Purpose:
-- . Provide MM registers for st_histogram
-- Description:
-- . Address 0, bit 0 = RAM clear
-- . Read : 'ram_clearing' status output of st_histogram.vhd. '1' when RAM is clearing.
-- . Address 1 = select RAM instance to fill (read out)
-- . Read : read back selected instance
-- . Write: select RAM instance to fill
-- . Address 2, bit 0 = RAM fill
-- . Read : 'ram_filling' status. '1' right after write of ram_fill. '0' when not filling RAM (anymore).
-- . Write: 'ram_fill ' control. '1' to fill RAM on write event.
LIBRARY IEEE, common_lib;
USE IEEE.std_logic_1164.ALL;
USE common_lib.common_pkg.ALL;
USE common_lib.common_mem_pkg.ALL;
ENTITY st_histogram_reg IS
GENERIC (
g_nof_instances : NATURAL
);
PORT (
dp_clk : IN STD_LOGIC;
dp_rst : IN STD_LOGIC;
ram_clearing : IN STD_LOGIC;
ram_fill_inst : OUT STD_LOGIC_VECTOR(ceil_log2(g_nof_instances)-1 DOWNTO 0);
ram_fill : OUT STD_LOGIC;
ram_filling : IN STD_LOGIC;
mm_clk : IN STD_LOGIC;
mm_rst : IN STD_LOGIC;
reg_mosi : IN t_mem_mosi;
reg_miso : OUT t_mem_miso
);
END st_histogram_reg;
ARCHITECTURE rtl OF st_histogram_reg IS
CONSTANT c_nof_addresses : NATURAL := 3;
CONSTANT c_mm_reg : t_c_mem := (latency => 1,
adr_w => ceil_log2(c_nof_addresses),
dat_w => c_word_w, -- Use MM bus data width = c_word_w = 32 for all MM registers
nof_dat => c_nof_addresses,
init_sl => '0');
SIGNAL mm_ram_clearing : STD_LOGIC;
SIGNAL mm_ram_fill_inst : STD_LOGIC_VECTOR(ceil_log2(g_nof_instances)-1 DOWNTO 0);
SIGNAL mm_ram_fill : STD_LOGIC;
SIGNAL mm_ram_filling : STD_LOGIC;
BEGIN
------------------------------------------------------------------------------
-- MM register access in the mm_clk domain
-- . Hardcode the shared MM slave register directly in RTL instead of using
-- the common_reg_r_w instance. Directly using RTL is easier when the large
-- MM register has multiple different fields and with different read and
-- write options per field in one MM register.
------------------------------------------------------------------------------
p_mm_reg : PROCESS (mm_clk, mm_rst)
BEGIN
IF mm_rst = '1' THEN
-- Read access
reg_miso <= c_mem_miso_rst;
-- Access event, register values
mm_ram_fill <= '0';
mm_ram_fill_inst <= (OTHERS=>'0');
ELSIF rising_edge(mm_clk) THEN
-- Read access defaults
reg_miso.rdval <= '0';
-- Access event defaults
mm_ram_fill <= '0';
-- Write access: set register value
IF reg_mosi.wr = '1' THEN
CASE TO_UINT(reg_mosi.address(c_mm_reg.adr_w-1 DOWNTO 0)) IS
WHEN 1 =>
mm_ram_fill_inst <= reg_mosi.wrdata(ceil_log2(g_nof_instances)-1 DOWNTO 0);
WHEN 2 =>
mm_ram_fill <= '1';
WHEN OTHERS => NULL; -- unused MM addresses
END CASE;
-- Read access: get register value
ELSIF reg_mosi.rd = '1' THEN
reg_miso <= c_mem_miso_rst; -- set unused rddata bits to '0' when read
reg_miso.rdval <= '1'; -- c_mm_reg.latency = 1
CASE TO_UINT(reg_mosi.address(c_mm_reg.adr_w-1 DOWNTO 0)) IS
WHEN 0 =>
-- Read RAM clearing status
reg_miso.rddata(0) <= mm_ram_clearing;
WHEN 1 =>
-- Read selected RAM instance to fill
reg_miso.rddata(ceil_log2(g_nof_instances)-1 DOWNTO 0) <= mm_ram_fill_inst;
WHEN 2 =>
-- Read RAM filling status
reg_miso.rddata(0) <= mm_ram_filling;
WHEN OTHERS => NULL; -- unused MM addresses
END CASE;
END IF;
END IF;
END PROCESS;
------------------------------------------------------------------------------
-- Transfer register value between mm_clk and st_clk domain.
-- If the function of the register ensures that the value will not be used
-- immediately when it was set, then the transfer between the clock domains
-- can be done by wires only. Otherwise if the change in register value can
-- have an immediate effect then the bit or word value needs to be transfered
-- using:
--
-- . common_async --> for single-bit level signal
-- . common_spulse --> for single-bit pulse signal
-- . common_reg_cross_domain --> for a multi-bit (a word) signal
--
-- Typically always use a crossing component for the single bit signals (to
-- be on the save side) and only use a crossing component for the word
-- signals if it is necessary (to avoid using more logic than necessary).
------------------------------------------------------------------------------
-- ST --> MM
u_common_async_clear : ENTITY common_lib.common_async
GENERIC MAP (
g_rst_level => '0'
)
PORT MAP (
clk => mm_clk,
rst => mm_rst,
din => ram_clearing,
dout => mm_ram_clearing
);
u_common_async_fill : ENTITY common_lib.common_async
GENERIC MAP (
g_rst_level => '0'
)
PORT MAP (
clk => mm_clk,
rst => mm_rst,
din => ram_filling,
dout => mm_ram_filling
);
u_common_spulse_fill : ENTITY common_lib.common_spulse
PORT MAP (
in_clk => mm_clk,
in_rst => mm_rst,
in_pulse => mm_ram_fill,
in_busy => OPEN,
out_clk => dp_clk,
out_rst => dp_rst,
out_pulse => ram_fill
);
u_common_reg_cross_domain : ENTITY common_lib.common_reg_cross_domain
PORT MAP (
in_clk => mm_clk,
in_rst => mm_rst,
in_dat => mm_ram_fill_inst,
in_done => OPEN,
out_clk => dp_clk,
out_rst => dp_rst,
out_dat => ram_fill_inst,
out_new => OPEN
);
END rtl;
-------------------------------------------------------------------------------
--
-- Copyright 2020
-- Copyright 2021
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
......@@ -23,14 +23,17 @@
-- Author:
-- . Daniel van der Schuur
-- Purpose:
-- .
-- . Read and verify histogram RAM of instance 0
-- ModelSim usage:
-- . (open project, compile)
-- . (load simulation config)
-- . as 8
-- . run -a
-- Description:
-- .
-- . This TB is self checking and stops after g_nof_sync test iterations.
-- . This TB only checks the MM aspects of mmp_st_histogram with limited (counter
-- data) stimuli and verification. Details of st_histogram are thoroughly
-- checked in tb_tb_st_histogram.
-------------------------------------------------------------------------------
LIBRARY IEEE, common_lib, mm_lib, dp_lib;
......@@ -43,18 +46,18 @@ USE common_lib.tb_common_pkg.ALL;
USE dp_lib.dp_stream_pkg.ALL;
USE dp_lib.tb_dp_pkg.ALL;
ENTITY tb_mms_st_histogram IS
ENTITY tb_mmp_st_histogram IS
GENERIC(
g_nof_sync : NATURAL := 4;
g_nof_instances : NATURAL := 12;
g_data_w : NATURAL := 14;
g_nof_bins : NATURAL := 512;
g_nof_data_per_sync : NATURAL := 40000
);
END tb_mms_st_histogram;
g_nof_data_per_sync : NATURAL := 16384 -- g_nof_data_per_sync/g_nof_bins should be integer so
); -- counter data yields the same histogram in each bin
END tb_mmp_st_histogram;
ARCHITECTURE tb OF tb_mms_st_histogram IS
ARCHITECTURE tb OF tb_mmp_st_histogram IS
---------------------------------------------------------------------------
-- Clocks and resets
......@@ -64,45 +67,37 @@ ARCHITECTURE tb OF tb_mms_st_histogram IS
SIGNAL dp_clk : STD_LOGIC := '1';
SIGNAL dp_rst : STD_LOGIC;
SIGNAL mm_clk : STD_LOGIC := '1';
SIGNAL mm_rst : STD_LOGIC;
SIGNAL tb_end : STD_LOGIC := '0';
----------------------------------------------------------------------------
-- stimuli
----------------------------------------------------------------------------
SIGNAL stimuli_en : STD_LOGIC := '1';
SIGNAL stimuli_src_out : t_dp_sosi;
SIGNAL stimuli_src_in : t_dp_siso;
SIGNAL stimuli_done : STD_LOGIC;
----------------------------------------------------------------------------
-- st_histogram
----------------------------------------------------------------------------
SIGNAL st_histogram_snk_in_arr : t_dp_sosi_arr(g_nof_instances-1 DOWNTO 0);
SIGNAL st_histogram_reg_mosi : t_mem_mosi;
SIGNAL st_histogram_reg_miso : t_mem_miso;
SIGNAL st_histogram_ram_mosi : t_mem_mosi;
SIGNAL st_histogram_ram_miso : t_mem_miso;
SIGNAL st_histogram_ram_copi : t_mem_copi;
SIGNAL st_histogram_ram_cipo : t_mem_cipo;
----------------------------------------------------------------------------
-- Readout & verification
----------------------------------------------------------------------------
CONSTANT c_ram_dat_w : NATURAL := ceil_log2(g_nof_data_per_sync)+1;
CONSTANT c_ram_dat_w : NATURAL := ceil_log2(g_nof_data_per_sync+1);
CONSTANT c_expected_ram_content : NATURAL := g_nof_data_per_sync/g_nof_bins;
SIGNAL ram_filling : STD_LOGIC;
SIGNAL ram_rd_word : STD_LOGIC_VECTOR(c_ram_dat_w-1 DOWNTO 0);
SIGNAL ram_rd_word_int : NATURAL;
SIGNAL ram_rd_word_valid : STD_LOGIC;
SIGNAL nxt_ram_rd_word_valid : STD_LOGIC;
SIGNAL verification_done : STD_LOGIC;
BEGIN
......@@ -117,7 +112,7 @@ BEGIN
----------------------------------------------------------------------------
-- DP Stimuli: generate st_histogram input data
-- DP Stimuli: generate st_histogram input (counter) data
----------------------------------------------------------------------------
stimuli_src_in <= c_dp_siso_rdy;
......@@ -125,6 +120,7 @@ BEGIN
p_generate_packets : PROCESS
VARIABLE v_sosi : t_dp_sosi := c_dp_sosi_rst;
BEGIN
stimuli_done <= '0';
stimuli_src_out <= c_dp_sosi_rst;
proc_common_wait_until_low(dp_clk, dp_rst);
proc_common_wait_some_cycles(dp_clk, 5);
......@@ -132,22 +128,25 @@ BEGIN
FOR I IN 0 TO g_nof_sync-1 LOOP
v_sosi.sync := '1';
v_sosi.data := RESIZE_DP_DATA(v_sosi.data(g_data_w-1 DOWNTO 0)); -- wrap when >= 2**g_data_w
-- Generate a block of counter data
proc_dp_gen_block_data(g_data_w, TO_UINT(v_sosi.data), g_nof_data_per_sync, TO_UINT(v_sosi.channel), TO_UINT(v_sosi.err), v_sosi.sync, v_sosi.bsn, dp_clk, stimuli_en, stimuli_src_in, stimuli_src_out);
END LOOP;
stimuli_done <= '1';
proc_common_wait_some_cycles(dp_clk, 50);
tb_end <= '1';
WAIT;
END PROCESS;
----------------------------------------------------------------------------
-- mms_st_histogram
-- mmp_st_histogram
----------------------------------------------------------------------------
gen_snk_in_arr: FOR i IN 0 TO g_nof_instances-1 GENERATE
st_histogram_snk_in_arr(i) <= stimuli_src_out;
END GENERATE;
u_mms_st_histogram : ENTITY work.mms_st_histogram
u_mmp_st_histogram : ENTITY work.mmp_st_histogram
GENERIC MAP(
g_nof_instances => g_nof_instances,
g_data_w => g_data_w,
......@@ -163,11 +162,8 @@ BEGIN
snk_in_arr => st_histogram_snk_in_arr,
reg_mosi => st_histogram_reg_mosi,
reg_miso => st_histogram_reg_miso,
ram_mosi => st_histogram_ram_mosi,
ram_miso => st_histogram_ram_miso
ram_copi => st_histogram_ram_copi,
ram_cipo => st_histogram_ram_cipo
);
......@@ -176,48 +172,25 @@ BEGIN
----------------------------------------------------------------------------
p_ram_clear : PROCESS
BEGIN
st_histogram_ram_mosi <= c_mem_mosi_rst;
st_histogram_reg_mosi <= c_mem_mosi_rst;
ram_filling <= '0';
st_histogram_ram_copi <= c_mem_copi_rst;
ram_rd_word <= (OTHERS=>'0');
-- The first sync indicates start of incoming data - let it pass
proc_common_wait_until_high(dp_clk, stimuli_src_out.sync);
proc_common_wait_some_cycles(mm_clk, 10);
FOR i IN 0 TO g_nof_sync-2 LOOP
-- Wiat for a full sync period of data
-- Wait for a full sync period of data
proc_common_wait_until_high(dp_clk, stimuli_src_out.sync);
-- The sync has passed, we can start reading the resulting histogram
FOR j IN 0 TO g_nof_instances-1 LOOP
-- Select st_histogram instance to read out
proc_mem_mm_bus_wr(1, j, mm_clk, st_histogram_reg_mosi);
proc_common_wait_some_cycles(mm_clk, 2);
-- Enable RAM filling
proc_mem_mm_bus_wr(2, 1, mm_clk, st_histogram_reg_mosi);
proc_common_wait_some_cycles(mm_clk, 10);
-- Wait until RAM filling is done
proc_mem_mm_bus_rd(2, mm_clk, st_histogram_reg_mosi);
ram_filling <= st_histogram_reg_miso.rddata(0);
proc_common_wait_some_cycles(mm_clk, 2);
WHILE ram_filling='1' LOOP
-- Read filling status
proc_mem_mm_bus_rd(2, mm_clk, st_histogram_reg_mosi);
ram_filling <= st_histogram_reg_miso.rddata(0);
proc_common_wait_some_cycles(mm_clk, 1);
END LOOP;
-- Read out the RAM contents
FOR k IN 0 TO g_nof_bins-1 LOOP
proc_mem_mm_bus_rd(k, mm_clk, st_histogram_ram_mosi);
ram_rd_word <= st_histogram_ram_miso.rddata(c_ram_dat_w-1 DOWNTO 0);
proc_mem_mm_bus_rd(k, mm_clk, st_histogram_ram_copi);
ram_rd_word <= st_histogram_ram_cipo.rddata(c_ram_dat_w-1 DOWNTO 0);
ram_rd_word_int <= TO_UINT(ram_rd_word);
END LOOP;
END LOOP;
END LOOP;
END PROCESS;
-- Register st_histogram_ram_miso.rdval so we read only valid data
-- Register st_histogram_ram_cipo.rdval so we read only valid data
p_nxt_ram_rd_word_valid : PROCESS(mm_rst, mm_clk)
BEGIN
IF mm_rst = '1' THEN
......@@ -226,7 +199,7 @@ BEGIN
ram_rd_word_valid <= nxt_ram_rd_word_valid;
END IF;
END PROCESS;
nxt_ram_rd_word_valid <= st_histogram_ram_miso.rdval;
nxt_ram_rd_word_valid <= st_histogram_ram_cipo.rdval;
----------------------------------------------------------------------------
......@@ -234,6 +207,7 @@ BEGIN
----------------------------------------------------------------------------
p_verify_assert : PROCESS
BEGIN
verification_done <= '0';
FOR i IN 0 TO g_nof_sync-1 LOOP
proc_common_wait_until_high(dp_clk, stimuli_src_out.sync);
proc_common_wait_until_high(dp_clk, ram_rd_word_valid);
......@@ -244,6 +218,16 @@ BEGIN
END IF;
END LOOP;
WAIT FOR 5 ns;
verification_done <= '1'; --We have blocking proc_common_wait_until_high procedures above so we need to know if we make it here.
END PROCESS;
-- Check if verification was done at all
p_check_verification_done : PROCESS
BEGIN
proc_common_wait_until_high(dp_clk, stimuli_done);
proc_common_wait_some_cycles(dp_clk, 50);
ASSERT verification_done='1' REPORT "Verification failed" SEVERITY ERROR;
WAIT;
END PROCESS;
......
-------------------------------------------------------------------------------
--
-- Copyright 2020
-- Copyright 2021
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
......@@ -29,8 +29,16 @@
-- . (load simulation config)
-- . as 8
-- . run -a
-- . For signals 'stimuli_data' and 'histogram' select Format->Analog(automatic)
-- . set Radix to 'decimal' for signed input data.
-- Description:
-- . Verification be eye (wave window) - observe that:
-- . tb_st_histogram generates and visualizes an input sine wave and the
-- resulting histogram in the wave window.
-- . Verification be eye (wave window):
-- . For the sine input (default), observe input 'stimuli_data' and output
-- 'histogram' signals. Set Radix->Decimal and Format->Analog (automatic)
-- in QuestaSim.
-- . For counter data, observe that:
-- . There are 4 sync periods in which 3 packets of 1024 words are generated;
-- . histogram_snk_in.data = 0..1023, 3 times per sync
-- . st_histogram has 256 bins so uses the 8 MS bits of snk_in.data
......@@ -39,15 +47,23 @@
-- . bin_writer_mosi writes bin counts 1..12 per sync interval;
-- . Both RAMs are used twice: RAM 0, RAM 1, RAM 0, RAM 1;
-- . RAM clearing completes just before the end of each sync interval.
-- . Automatic verification:
-- . In each sync period the RAM contents are read out via ram_mosi/miso and
-- compared to the expected bin counts.
-- . Automatic verification - in each sync period:
-- . the RAM contents are read out via ram_mosi/miso and compared to the
-- expected bin counts. This is done only for g_stimuli_mode = counter
-- and dc because that is sufficient and easily done automatically.
-- . The counter mode yields the same value in all bins
-- . DC mode yields max value in one bin and zero in other bins.
-- . the sum of all bins is checked against the expected g_nof_data_per_sync.
-- . this is done for all modes 'counter', 'dc', 'random' and 'sine'.
-------------------------------------------------------------------------------
LIBRARY IEEE, common_lib, mm_lib, dp_lib;
USE IEEE.std_logic_1164.ALL;
USE IEEE.numeric_std.ALL;
USE IEEE.math_real.ALL;
USE common_lib.common_pkg.ALL;
USE common_lib.common_lfsr_sequences_pkg.ALL;
USE common_lib.common_str_pkg.ALL;
USE common_lib.common_mem_pkg.ALL;
USE common_lib.tb_common_mem_pkg.ALL;
USE common_lib.tb_common_pkg.ALL;
......@@ -57,10 +73,13 @@ USE dp_lib.tb_dp_pkg.ALL;
ENTITY tb_st_histogram IS
GENERIC(
g_nof_sync : NATURAL := 4; -- We're simulating at least 4 g_nof_sync so both RAMs are written and cleared twice.
g_data_w : NATURAL := 8; -- Determines maximum number of bins (2^g_data_w)
g_nof_bins : NATURAL := 256; -- Lower than or equal to 2^g_data_w. Higher is allowed but makes no sense.
g_nof_data_per_sync : NATURAL := 1024 -- Determines max required RAM data width. e.g. 11b to store max bin count '1024'.
);
g_data_w : NATURAL := 3; -- Determines maximum number of bins (2^g_data_w)
g_nof_bins : NATURAL := 8; -- Lower than or equal to 2^g_data_w. Higher is allowed but makes no sense.
g_nof_data_per_sync : NATURAL := 20; -- >= g_nof_bins. Determines max required RAM data width. e.g. 11b to store max bin count '1024'.
g_stimuli_mode : STRING := "sine"; -- "counter", "dc", "sine" or "random"
g_data_type : STRING := "signed"; -- use "signed" if g_stimuli_mode="sine"
g_lock_sine : BOOLEAN := TRUE -- TRUE to lock the sine wave to Sync - produces sparse histogram with low number of non-zero samples (occuring 2*c_sine_nof_periods)
); -- FALSE produces a dense histogram as the drifting sine wave hits more levels.
END tb_st_histogram;
......@@ -69,9 +88,10 @@ ARCHITECTURE tb OF tb_st_histogram IS
---------------------------------------------------------------------------
-- Constants derived from generics
---------------------------------------------------------------------------
CONSTANT c_expected_ram_content : NATURAL := g_nof_data_per_sync/g_nof_bins;
CONSTANT c_ram_dat_w : NATURAL := ceil_log2(g_nof_data_per_sync)+1;
CONSTANT c_expected_ram_content_counter : NATURAL := g_nof_data_per_sync/g_nof_bins;
CONSTANT c_nof_levels_per_bin : NATURAL := (2**g_data_w)/g_nof_bins; --e.g. 2 values per bin if g_data_w=9 (512 levels) and g_nof_bins=256
CONSTANT c_ram_dat_w : NATURAL := ceil_log2(g_nof_data_per_sync+1);
CONSTANT c_ram_adr_w : NATURAL := ceil_log2(g_nof_bins);
---------------------------------------------------------------------------
-- Clocks and resets
......@@ -86,25 +106,41 @@ ARCHITECTURE tb OF tb_st_histogram IS
----------------------------------------------------------------------------
-- stimuli
----------------------------------------------------------------------------
SIGNAL stimuli_en : STD_LOGIC := '1';
CONSTANT c_sine_amplitude : REAL := real((2**g_data_w)/2-1);
CONSTANT c_sine_nof_periods : REAL := 1.0;
CONSTANT c_sine_nof_samples_per_period : REAL := real(g_nof_data_per_sync)/c_sine_nof_periods;
CONSTANT c_sine_time_step_denom : REAL := sel_a_b(g_lock_sine, MATH_2_PI, 5.0); -- Use 5 instead of 2 pi to create unlocked, drifting sine wave
CONSTANT c_sine_time_step : REAL := c_sine_time_step_denom / c_sine_nof_samples_per_period;
SIGNAL stimuli_en : STD_LOGIC := '1';
SIGNAL stimuli_src_out : t_dp_sosi;
SIGNAL nxt_stimuli_src_out : t_dp_sosi;
SIGNAL stimuli_src_in : t_dp_siso;
SIGNAL stimuli_count : REAL;
SIGNAL stimuli_data : STD_LOGIC_VECTOR(g_data_w-1 DOWNTO 0); -- QuestaSim: Format->Analog, Radix->Decimal
SIGNAL random_data : STD_LOGIC_VECTOR(g_data_w-1 DOWNTO 0);
SIGNAL stimuli_done : STD_LOGIC;
----------------------------------------------------------------------------
-- st_histogram
----------------------------------------------------------------------------
SIGNAL st_histogram_snk_in : t_dp_sosi;
SIGNAL st_histogram_ram_mosi : t_mem_mosi;
SIGNAL prv_st_histogram_ram_mosi : t_mem_mosi;
SIGNAL st_histogram_ram_miso : t_mem_miso;
----------------------------------------------------------------------------
-- Automatic verification of RAM readout
----------------------------------------------------------------------------
SIGNAL ram_rd_word : STD_LOGIC_VECTOR(c_ram_dat_w-1 DOWNTO 0);
SIGNAL ram_rd_word_int : NATURAL;
SIGNAL ram_rd_word_valid : STD_LOGIC;
SIGNAL nxt_ram_rd_word_valid : STD_LOGIC;
-- Use these 4 signals to verify histogram by eye in the wave window
SIGNAL histogram_data : NATURAL; -- QuestaSim: Format->Analog
SIGNAL histogram_bin_unsigned : NATURAL;
SIGNAL histogram_bin_signed : INTEGER; -- QuestaSim: Radix->Decimal
SIGNAL histogram_valid : STD_LOGIC;
SIGNAL sum_of_bins : NATURAL;
SIGNAL verification_done : STD_LOGIC;
BEGIN
......@@ -116,7 +152,7 @@ BEGIN
----------------------------------------------------------------------------
-- Stimuli: generate st_histogram input data and clear the RAM
-- Stimuli: generate st_histogram input data
----------------------------------------------------------------------------
stimuli_src_in <= c_dp_siso_rdy;
......@@ -124,21 +160,85 @@ BEGIN
p_generate_packets : PROCESS
VARIABLE v_sosi : t_dp_sosi := c_dp_sosi_rst;
BEGIN
stimuli_src_out <= c_dp_sosi_rst;
nxt_stimuli_src_out <= c_dp_sosi_rst;
stimuli_done <= '0';
proc_common_wait_until_low(dp_clk, dp_rst);
proc_common_wait_some_cycles(dp_clk, 5);
-- Generate a block of counter data every sync
IF g_stimuli_mode="counter" THEN
FOR I IN 0 TO g_nof_sync-1 LOOP
v_sosi.sync := '1';
v_sosi.data := RESIZE_DP_DATA(v_sosi.data(g_data_w-1 DOWNTO 0)); -- wrap when >= 2**g_data_w
proc_dp_gen_block_data(g_data_w, TO_UINT(v_sosi.data), g_nof_data_per_sync, TO_UINT(v_sosi.channel), TO_UINT(v_sosi.err), v_sosi.sync, v_sosi.bsn, dp_clk, stimuli_en, stimuli_src_in, stimuli_src_out);
proc_dp_gen_block_data(g_data_w, TO_UINT(v_sosi.data), g_nof_data_per_sync, TO_UINT(v_sosi.channel), TO_UINT(v_sosi.err), v_sosi.sync, v_sosi.bsn, dp_clk, stimuli_en, stimuli_src_in, nxt_stimuli_src_out);
END LOOP;
END IF;
-- Generate a DC level that increments every sync
IF g_stimuli_mode="dc" THEN
nxt_stimuli_src_out.valid <= '1';
FOR I IN 0 TO g_nof_sync-1 LOOP
nxt_stimuli_src_out.data <= INCR_UVEC(stimuli_src_out.data, 1); --all g_nof_data_per_sync cycles
nxt_stimuli_src_out.sync <= '1'; -- cycle 0
WAIT FOR 5 ns;
FOR j IN 1 TO g_nof_data_per_sync-1 LOOP --cycles 1..g_nof_data_per_sync-1
nxt_stimuli_src_out.sync <= '0';
WAIT FOR 5 ns;
END LOOP;
END LOOP;
END IF;
-- Generate a sine wave
IF g_stimuli_mode="sine" THEN
nxt_stimuli_src_out <= stimuli_src_out;
nxt_stimuli_src_out.valid <= '1';
stimuli_count <= 0.0;
FOR I IN 0 TO g_nof_sync-1 LOOP
nxt_stimuli_src_out.sync <= '1'; -- cycle 0
WAIT FOR 5 ns;
FOR j IN 1 TO g_nof_data_per_sync-1 LOOP --cycles 1..g_nof_data_per_sync-1
nxt_stimuli_src_out.sync <= '0';
nxt_stimuli_src_out.data(g_data_w-1 DOWNTO 0) <= TO_SVEC( integer(round( c_sine_amplitude * sin(stimuli_count) )), g_data_w);
stimuli_count<=stimuli_count+c_sine_time_step;
WAIT FOR 5 ns;
END LOOP;
END LOOP;
END IF;
-- Generate pseudo random noise
IF g_stimuli_mode="random" THEN
nxt_stimuli_src_out.valid <= '1';
FOR I IN 0 TO g_nof_sync-1 LOOP
random_data <= (OTHERS=>'0');
nxt_stimuli_src_out.sync <= '1'; -- cycle 0
WAIT FOR 5 ns;
FOR j IN 1 TO g_nof_data_per_sync-1 LOOP
nxt_stimuli_src_out.sync <= '0';
random_data <= func_common_random(random_data);
nxt_stimuli_src_out.data(g_data_w-1 DOWNTO 0) <= random_data; --all g_nof_data_per_sync cycles
WAIT FOR 5 ns;
END LOOP;
END LOOP;
END IF;
stimuli_done <= '1';
proc_common_wait_some_cycles(dp_clk, 50);
tb_end <= '1';
WAIT;
END PROCESS;
p_stimuli_src_out: PROCESS(dp_rst, dp_clk) IS
BEGIN
IF dp_rst='1' THEN
stimuli_src_out <= c_dp_sosi_rst;
ELSIF RISING_EDGE(dp_clk) THEN
stimuli_src_out <= nxt_stimuli_src_out;
END IF;
END PROCESS;
-- signal to verify histogram by eye in the wave window
stimuli_data <= stimuli_src_out.data(g_data_w-1 DOWNTO 0);
----------------------------------------------------------------------------
-- st_histogram
......@@ -149,7 +249,8 @@ BEGIN
GENERIC MAP(
g_data_w => g_data_w,
g_nof_bins => g_nof_bins,
g_nof_data_per_sync => g_nof_data_per_sync
g_nof_data_per_sync => g_nof_data_per_sync,
g_data_type => g_data_type
)
PORT MAP (
dp_clk => dp_clk,
......@@ -166,55 +267,103 @@ BEGIN
-- . The table below shows what RAM we are reading here ('RAM read') via the
-- ram_mosi/miso interface, and what the expected RAM contents are.
--
---+-------------+-------------+----------+--------------+
-- Counter data (the same every sync excl. sync 0):
---+-------------+-------------+----------+-----------------------+
-- | Sync period | RAM written | RAM read | RAM contents |
-- +-------------+-------------+----------+--------------+
-- | 0 | 0 | 1 | 256 * 0 |
-- | 1 | 1 | 0 | 256 * 12 |
-- | 2 | 0 | 1 | 256 * 12 |
-- | 3 | 1 | 0 | 256 * 12 |
-- +-------------+-------------+----------+--------------+
-- +-------------+-------------+----------+-----------------------+
-- | 0 | 0 | 1 | 256 addresses * 0 |
-- | 1 | 1 | 0 | 256 addresses * 12 |
-- | 2 | 0 | 1 | 256 addresses * 12 |
-- | 3 | 1 | 0 | 256 addresses * 12 |
-- +-------------+-------------+----------+-----------------------+
--
-- DC data (increments level every sync: 0, 1, 2, 3, ..):
---+-------------+-------------+----------+-----------------------+
-- | Sync period | RAM written | RAM read | RAM contents |
-- +-------------+-------------+----------+-----------------------+
-- | 0 | 0 | 1 | 256 addresses * 0 |
-- | 1 | 1 | 0 | Addr 1: 1024, others 0|
-- | 2 | 0 | 1 | Addr 2: 1024, others 0|
-- | 3 | 1 | 0 | Addr 3: 1024, others 0|
-- +-------------+-------------+----------+-----------------------+
----------------------------------------------------------------------------
-- Perform MM read and put result in ram_rd_word
p_verify_mm_read : PROCESS
BEGIN
st_histogram_ram_mosi.wr <= '0';
FOR i IN 0 TO g_nof_sync-1 LOOP
proc_common_wait_until_high(dp_clk, stimuli_src_out.sync); -- Wait for sync
proc_common_wait_some_cycles(dp_clk, 10); -- give it a couple of more cycles
proc_common_wait_until_high(dp_clk, stimuli_src_out.sync);
proc_common_wait_some_cycles(dp_clk, 10);
FOR j IN 0 TO g_nof_bins-1 LOOP
proc_mem_mm_bus_rd(j, dp_clk, st_histogram_ram_mosi);
ram_rd_word <= st_histogram_ram_miso.rddata(c_ram_dat_w-1 DOWNTO 0);
ram_rd_word_int <= TO_UINT(ram_rd_word);
END LOOP;
END LOOP;
WAIT;
END PROCESS;
-- Register st_histogram_ram_miso.rdval so we read only valid ram_rd_word
p_nxt_ram_rd_word_valid : PROCESS(dp_rst, dp_clk)
BEGIN
IF dp_rst = '1' THEN
ram_rd_word_valid <= '0';
ELSIF RISING_EDGE(dp_clk) THEN
ram_rd_word_valid <= nxt_ram_rd_word_valid;
END IF;
END PROCESS;
nxt_ram_rd_word_valid <= st_histogram_ram_miso.rdval;
-- Help signals that contain the histogram bins+data
histogram_bin_unsigned <= TO_UINT( prv_st_histogram_ram_mosi.address(c_ram_adr_w-1 DOWNTO 0));
histogram_bin_signed <= TO_SINT(offset_binary(prv_st_histogram_ram_mosi.address(c_ram_adr_w-1 DOWNTO 0)));
histogram_data <= TO_UINT(st_histogram_ram_miso.rddata(c_ram_dat_w-1 DOWNTO 0)) WHEN st_histogram_ram_miso.rdval='1'ELSE 0;
histogram_valid <= st_histogram_ram_miso.rdval;
-- Perform verification of ram_rd_word when ram_rd_word_valid
p_verify_assert : PROCESS
BEGIN
verification_done <= '0';
FOR i IN 0 TO g_nof_sync-1 LOOP
sum_of_bins <= 0;
proc_common_wait_until_high(dp_clk, stimuli_src_out.sync);
proc_common_wait_until_high(dp_clk, ram_rd_word_valid);
FOR j IN 0 TO g_nof_bins-1 LOOP
proc_common_wait_until_high(dp_clk, histogram_valid);
IF i=0 THEN -- Sync period 0: we expect RAM to contain zeros
ASSERT ram_rd_word_int=0 REPORT "RAM contains wrong bin count (expected 0, actual " & INTEGER'IMAGE(ram_rd_word_int) & ")" SEVERITY ERROR;
ASSERT histogram_data=0 REPORT "RAM contains wrong bin count (expected 0, actual " & INTEGER'IMAGE(histogram_data) & ")" SEVERITY ERROR;
ELSE -- Sync period 1 onwards
ASSERT ram_rd_word_int=c_expected_ram_content REPORT "RAM contains wrong bin count (expected " & INTEGER'IMAGE(c_expected_ram_content) & ", actual " & INTEGER'IMAGE(ram_rd_word_int) & ")" SEVERITY ERROR;
IF g_stimuli_mode="counter" THEN
-- Counter data: bin values remain the same every sync
ASSERT histogram_data=c_expected_ram_content_counter REPORT "RAM contains wrong bin count (expected " & INTEGER'IMAGE(c_expected_ram_content_counter) & ", actual " & INTEGER'IMAGE(histogram_data) & ")" SEVERITY ERROR;
ELSIF g_stimuli_mode="dc" THEN
-- DC data: DC level increments every sync
IF j=(i/c_nof_levels_per_bin) THEN -- Check bin address and account for multiple levels per bin
-- this address (j) should contain the DC level total count of this sync period (i)
ASSERT histogram_data=g_nof_data_per_sync REPORT "RAM contains wrong bin count (expected " & INTEGER'IMAGE(g_nof_data_per_sync) & ", actual " & INTEGER'IMAGE(histogram_data) & ")" SEVERITY ERROR;
ELSE
-- this address should contain zero
ASSERT histogram_data=0 REPORT "RAM contains wrong bin count (expected 0, actual " & INTEGER'IMAGE(histogram_data) & ")" SEVERITY ERROR;
END IF;
END LOOP;
END IF;
END IF;
sum_of_bins<=sum_of_bins+histogram_data; -- Keep the sum of all bins
WAIT FOR 5 ns;
END LOOP;
-- Check the sum of all bins
IF i>0 THEN -- Skip sync 0 (histogram still all zeros)
ASSERT sum_of_bins=g_nof_data_per_sync REPORT "Sum of bins not equal to g_nof_data_per_sync (expected " & INTEGER'IMAGE(g_nof_data_per_sync) & ", actual " & INTEGER'IMAGE(sum_of_bins) & ")" SEVERITY ERROR;
END IF;
END LOOP;
verification_done <= '1'; --We have blocking proc_common_wait_until_high procedures above so we need to know if we make it here.
WAIT;
END PROCESS;
-- Check if verification was done at all
p_check_verification_done : PROCESS
BEGIN
proc_common_wait_until_high(dp_clk, stimuli_done);
proc_common_wait_some_cycles(dp_clk, 50);
ASSERT verification_done='1' REPORT "Verification failed" SEVERITY ERROR;
WAIT;
END PROCESS;
-- Register MOSI to store the read address
p_clk: PROCESS(dp_rst, dp_clk) IS
BEGIN
IF dp_rst = '1' THEN
prv_st_histogram_ram_mosi <= c_mem_mosi_rst;
ELSIF RISING_EDGE(dp_clk) THEN
prv_st_histogram_ram_mosi <= st_histogram_ram_mosi;
END IF;
END PROCESS;
END tb;
......@@ -25,7 +25,9 @@
-- Usage
-- . as 8
-- . run -all
-- . Testbenches are self-checking
-- . Testbenches are self-checking.
-- . The sine wave test benches are best for verification by eye in the wave window.
-- . tb_st_histogram uses a sine wave as input by default
LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
......@@ -41,12 +43,43 @@ BEGIN
-- g_data_w : NATURAL := 8;
-- g_nof_bins : NATURAL := 256;
-- g_nof_data : NATURAL := 1024;
-- g_stimuli_mode : STRING := "dc";
-- g_data_type : STRING := "unsigned";
-- g_lock_sine : BOOLEAN := TRUE
u_tb_st_histogram_0 : ENTITY work.tb_st_histogram GENERIC MAP ( 7, 8, 256, 1024); -- Incoming data wraps (repeats) 1024/ 256= 4 times: Bin count = 4
u_tb_st_histogram_1 : ENTITY work.tb_st_histogram GENERIC MAP ( 6, 10, 256, 4096); -- Incoming data wraps (repeats) 4096/ 256=16 times: Bin count = 16
u_tb_st_histogram_2 : ENTITY work.tb_st_histogram GENERIC MAP ( 5, 12, 512, 4096); -- Incoming data wraps (repeats) 4096/ 512= 8 times: Bin count = 8
u_tb_st_histogram_3 : ENTITY work.tb_st_histogram GENERIC MAP ( 4, 13, 1024, 8192); -- Incoming data wraps (repeats) 8192/1024= 8 times: Bin count = 8
u_tb_st_histogram_4 : ENTITY work.tb_st_histogram GENERIC MAP (40, 6, 64, 128); -- Incoming data wraps (repeats) 128/ 64= 2 times: Bin count = 2
-- Counter data
u_tb_st_histogram_0 : ENTITY work.tb_st_histogram GENERIC MAP ( 7, 8, 256, 1024, "counter", "unsigned"); -- Incoming data repeats 1024/ 256= 4 times: Bin count = 4
u_tb_st_histogram_1 : ENTITY work.tb_st_histogram GENERIC MAP ( 6, 10, 256, 4096, "counter", "unsigned"); -- Incoming data repeats 4096/ 256=16 times: Bin count = 16
u_tb_st_histogram_2 : ENTITY work.tb_st_histogram GENERIC MAP ( 5, 12, 512, 4096, "counter", "unsigned"); -- Incoming data repeats 4096/ 512= 8 times: Bin count = 8
u_tb_st_histogram_3 : ENTITY work.tb_st_histogram GENERIC MAP ( 4, 13, 1024, 8192, "counter", "unsigned"); -- Incoming data repeats 8192/1024= 8 times: Bin count = 8
u_tb_st_histogram_4 : ENTITY work.tb_st_histogram GENERIC MAP (20, 6, 64, 128, "counter", "unsigned"); -- Incoming data repeats 128/ 64= 2 times: Bin count = 2
-- DC signal
u_tb_st_histogram_5 : ENTITY work.tb_st_histogram GENERIC MAP ( 2, 8, 256, 1000, "dc", "unsigned");
u_tb_st_histogram_6 : ENTITY work.tb_st_histogram GENERIC MAP ( 6, 10, 256, 4000, "dc", "unsigned");
u_tb_st_histogram_7 : ENTITY work.tb_st_histogram GENERIC MAP ( 5, 12, 512, 4000, "dc", "unsigned");
u_tb_st_histogram_8 : ENTITY work.tb_st_histogram GENERIC MAP ( 4, 13, 1024, 8000, "dc", "unsigned");
u_tb_st_histogram_9 : ENTITY work.tb_st_histogram GENERIC MAP (11, 6, 64, 100, "dc", "unsigned");
-- Locked Sine wave
u_tb_st_histogram_10: ENTITY work.tb_st_histogram GENERIC MAP ( 4, 3, 8, 20, "sine", "signed");
u_tb_st_histogram_11: ENTITY work.tb_st_histogram GENERIC MAP ( 8, 6, 64, 200, "sine", "signed");
u_tb_st_histogram_12: ENTITY work.tb_st_histogram GENERIC MAP (12, 8, 256, 2000, "sine", "signed");
u_tb_st_histogram_13: ENTITY work.tb_st_histogram GENERIC MAP (17, 10, 256, 3455, "sine", "signed");
u_tb_st_histogram_14: ENTITY work.tb_st_histogram GENERIC MAP (21, 14, 1024, 8111, "sine", "signed");
-- Drifting Sine wave
u_tb_st_histogram_15: ENTITY work.tb_st_histogram GENERIC MAP ( 4, 3, 8, 20, "sine", "signed", FALSE);
u_tb_st_histogram_16: ENTITY work.tb_st_histogram GENERIC MAP ( 8, 6, 64, 200, "sine", "signed", FALSE);
u_tb_st_histogram_17: ENTITY work.tb_st_histogram GENERIC MAP (12, 8, 256, 2000, "sine", "signed", FALSE);
u_tb_st_histogram_18: ENTITY work.tb_st_histogram GENERIC MAP (17, 10, 256, 3455, "sine", "signed", FALSE);
u_tb_st_histogram_19: ENTITY work.tb_st_histogram GENERIC MAP (21, 14, 1024, 8111, "sine", "signed", FALSE);
-- Random
u_tb_st_histogram_20: ENTITY work.tb_st_histogram GENERIC MAP ( 4, 3, 8, 20, "random", "signed");
u_tb_st_histogram_21: ENTITY work.tb_st_histogram GENERIC MAP ( 6, 6, 64, 200, "random", "signed");
u_tb_st_histogram_22: ENTITY work.tb_st_histogram GENERIC MAP ( 9, 8, 256, 2000, "random", "signed");
u_tb_st_histogram_23: ENTITY work.tb_st_histogram GENERIC MAP (17, 10, 256, 3455, "random", "signed");
u_tb_st_histogram_24: ENTITY work.tb_st_histogram GENERIC MAP (13, 14, 1024, 8111, "random", "signed");
END tb;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment