Skip to content
Snippets Groups Projects
Commit 596a3b9d authored by Daniel van der Schuur's avatar Daniel van der Schuur
Browse files

-Added MM readout logic + registers;

-Added tb_mms_st_histogram.vhd.
parent a6434b2d
No related branches found
No related tags found
3 merge requests!101Merged sub-branch L2SDP-151 into L2SDP-143 (st_histogram rework),!99Cleaned/rewrote st_histogram.,!98Major rework on st_histogram.
......@@ -19,12 +19,14 @@ test_bench_files =
tb/vhdl/tb_st_acc.vhd
tb/vhdl/tb_st_calc.vhd
tb/vhdl/tb_mmf_st_sst.vhd
tb/vhdl/tb_mms_st_histogram.vhd
tb/vhdl/tb_st_histogram.vhd
tb/vhdl/tb_tb_st_histogram.vhd
regression_test_vhdl =
tb/vhdl/tb_st_acc.vhd
#tb/vhdl/tb_st_calc.vhd -- tb is not self checking yet
tb/vhdl/tb_tb_st_histogram.vhd
[modelsim_project_file]
......
......@@ -21,7 +21,23 @@
-- Author:
-- . Daniel van der Schuur
-- Purpose:
-- . MM-wrapper that adds registers and multi-instance support to st_histogram.
-- . MMS-wrapper that adds registers 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:
-- 1) User writes to bit 0 of ram_clear register to clear RAMs of all
-- g_nof_instances
-- . ram_clearing status will go high
LIBRARY IEEE, common_lib, mm_lib, technology_lib, dp_lib;
USE IEEE.std_logic_1164.ALL;
......@@ -58,19 +74,38 @@ ARCHITECTURE str OF mms_st_histogram IS
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 : t_c_mem := (latency => 1,
adr_w => c_ram_adr_w,
dat_w => c_ram_dat_w,
nof_dat => g_nof_bins,
init_sl => '0');
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 reg_mosi_arr : t_mem_mosi_arr(g_nof_instances-1 DOWNTO 0);
SIGNAL reg_miso_arr : t_mem_miso_arr(g_nof_instances-1 DOWNTO 0);
SIGNAL dp_ram_mosi : t_mem_mosi;
SIGNAL dp_ram_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_clear_arr : STD_LOGIC_VECTOR(g_nof_instances-1 DOWNTO 0);
SIGNAL ram_clear : STD_LOGIC;
SIGNAL ram_clearing_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 : 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);
BEGIN
-------------------------------------------------------------------------------
......@@ -89,33 +124,39 @@ BEGIN
snk_in => snk_in_arr(i),
ram_clear => ram_clear_arr(i),
ram_clear => ram_clear,
ram_clearing => ram_clearing_arr(i),
ram_mosi => ram_mosi_arr(i),
ram_miso => ram_miso_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(i),
ram_clearing => ram_clearing_arr(0),
ram_filling => ram_filling,
mm_clk => mm_clk,
mm_rst => mm_rst,
ram_clear => ram_clear_arr(i),
ram_clear => ram_clear,
ram_fill_inst => ram_fill_inst,
ram_fill => ram_fill,
reg_mosi => reg_mosi,
reg_miso => reg_miso
);
END GENERATE;
-------------------------------------------------------------------------------
-- reg_mosi/miso multiplexer from g_nof_instances to 1
-- MM multiplexer from g_nof_instances to 1
-------------------------------------------------------------------------------
u_common_mem_mux_reg : ENTITY common_lib.common_mem_mux
GENERIC MAP (
......@@ -131,22 +172,64 @@ BEGIN
-------------------------------------------------------------------------------
-- ram_mosi/miso multiplexer from g_nof_instances to 1
-- Dual clock RAM: DP write side, MM read side
-------------------------------------------------------------------------------
u_common_mem_mux_ram : ENTITY common_lib.common_mem_mux
u_common_ram_cr_cw : ENTITY common_lib.common_ram_cr_cw
GENERIC MAP (
g_nof_mosi => g_nof_instances,
g_mult_addr_w => c_ram_adr_w
g_technology => c_tech_select_default,
g_ram => c_ram,
g_init_file => "UNUSED"
)
PORT MAP (
mosi => dp_ram_mosi,
miso => dp_ram_miso,
mosi_arr => ram_mosi_arr,
miso_arr => ram_miso_arr
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),
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
);
-- Cross clock domain from DP clock to MM clock NOTE - work in progress
ram_miso <= dp_ram_miso;
dp_ram_mosi <= ram_mosi;
-- User side MM bus for histogram readout
common_ram_cr_cw_rd_mosi <= ram_mosi;
ram_miso <= common_ram_cr_cw_rd_miso;
-------------------------------------------------------------------------------
-- Logic to move st_histogram RAM contents into the dual clock RAM above
-------------------------------------------------------------------------------
-- 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;
-- Do read request on ram_mosi when ram_filling
ram_mosi_arr(TO_UINT(ram_fill_inst)).rd <= ram_filling;
ram_mosi_arr(TO_UINT(ram_fill_inst)).address(c_ram_adr_w-1 DOWNTO 0) <= address;
-- Forward the read histogram data from ram_miso into write mosi of dual clock RAM
nxt_common_ram_cr_cw_wr_mosi.wr <= ram_miso_arr(TO_UINT(ram_fill_inst)).rdval;
nxt_common_ram_cr_cw_wr_mosi.wrdata(c_ram_dat_w-1 DOWNTO 0) <= ram_miso_arr(TO_UINT(ram_fill_inst)).rddata(c_ram_dat_w-1 DOWNTO 0);
nxt_common_ram_cr_cw_wr_mosi.address(c_ram_adr_w-1 DOWNTO 0) <= address;
-- Registers
p_clk : PROCESS(dp_clk, dp_rst) IS
BEGIN
IF dp_rst = '0' THEN
common_ram_cr_cw_wr_mosi <= c_mem_mosi_rst;
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_filling <= nxt_ram_filling;
END IF;
END PROCESS;
END str;
......@@ -49,6 +49,22 @@
-- |__________| | |___________| | |___________|
-- | |
-- bin_writer_mosi bin_arbiter_wr_mosi
-- Usage:
-- . The ram_mosi and ram_clear inputs apply to the RAM page that is inactive (not
-- being written to from data path) *at that time*. The user should take care to
-- time these controls such that the active RAM page does not swap before these
-- operations (ram_mosi readout, ram_clear) have finished.
-- Remarks:
-- . common_ram_r_w
-- . Why common_ram_r_w was selected: it uses a single clock
-- . We need to read and write back bins in the dp_clk clock domain, so our RAM
-- block needs to have 2 separate address inputs - but in the same clock domain.
-- . The other, dual clock, RAM blocks (e.g. common_ram_cr_cw) are based on
-- common_ram_crw_crw and use 2 address inputs (adr_a,adr_b), each in
-- its own (clk_a,clk_b) clock domain, which is not what we need here.
-- . Downside of common_ram_r_w: it uses a single clock
-- . This st_histogram.vhd operates in dp_clk domain only, so we need to
-- provide MM access to the user, in the mm_clk domain, elsewhere.
LIBRARY IEEE, common_lib, mm_lib, technology_lib, dp_lib;
USE IEEE.std_logic_1164.ALL;
......@@ -67,12 +83,12 @@ ENTITY st_histogram IS
dp_clk : IN STD_LOGIC;
dp_rst : IN STD_LOGIC;
snk_in : IN t_dp_sosi;
snk_in : IN t_dp_sosi; -- Active RAM page swaps on snk_in.sync
ram_clear : IN STD_LOGIC;
ram_clearing : OUT STD_LOGIC;
ram_clear : IN STD_LOGIC; -- Control input: Pulse high to clear the inactive RAM page
ram_clearing : OUT STD_LOGIC; -- Status output: high while RAM is being cleared
ram_mosi : IN t_mem_mosi;
ram_mosi : IN t_mem_mosi; -- MM access to the inactive RAM page
ram_miso : OUT t_mem_miso
);
END st_histogram;
......@@ -338,6 +354,7 @@ BEGIN
);
END GENERATE;
-------------------------------------------------------------------------------
-- ram_clear control input - let user clear the RAM
-- 1) User waits for PPS
......
......@@ -26,6 +26,13 @@
-- . Address 0, bit 0 = RAM clear
-- . Read : 'ram_clearing' status. '1' right after write of ram_clear. '0' when not clearing RAM (anymore).
-- . Write: 'ram_clear ' control. '1' to clear RAM on write event.
-- . 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;
......@@ -33,7 +40,9 @@ 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;
......@@ -41,6 +50,10 @@ ENTITY st_histogram_reg IS
ram_clear : OUT 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;
......@@ -62,6 +75,10 @@ ARCHITECTURE rtl OF st_histogram_reg IS
SIGNAL mm_ram_clear : STD_LOGIC;
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
------------------------------------------------------------------------------
......@@ -79,6 +96,7 @@ BEGIN
-- Access event, register values
mm_ram_clear <= '0';
mm_ram_fill <= '0';
ELSIF rising_edge(mm_clk) THEN
-- Read access defaults
......@@ -86,12 +104,17 @@ BEGIN
-- Access event defaults
mm_ram_clear <= '0';
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 0 =>
mm_ram_clear <= '1';
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;
......@@ -103,6 +126,12 @@ BEGIN
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;
......@@ -127,7 +156,7 @@ BEGIN
------------------------------------------------------------------------------
-- ST --> MM
u_common_async : ENTITY common_lib.common_async
u_common_async_clear : ENTITY common_lib.common_async
GENERIC MAP (
g_rst_level => '0'
)
......@@ -139,8 +168,20 @@ BEGIN
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
);
-- MM --> ST
u_common_spulse : ENTITY common_lib.common_spulse
u_common_spulse_clear : ENTITY common_lib.common_spulse
PORT MAP (
in_clk => mm_clk,
in_rst => mm_rst,
......@@ -154,4 +195,30 @@ BEGIN
out_pulse => ram_clear
);
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
-- 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:
-- . TB to verify correct MM access across clock domain by eye.
-- ModelSim usage:
-- . (open project, compile)
-- . (load simulation config)
-- . as 8
-- . run -a
-- Description:
-- . reg_mosi/miso uses traditional _reg instance to cross clock domain and
-- therefor does not need additional checks.
-- . ram_mosi/miso uses several common_reg_cross_domain instances to let the
-- MM buses cross MM<->DP clock domain in both directions. Should work, but
-- is not a proven method - hence this TB.
-------------------------------------------------------------------------------
LIBRARY IEEE, common_lib, mm_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 common_lib.tb_common_mem_pkg.ALL;
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
END tb_mms_st_histogram;
ARCHITECTURE tb OF tb_mms_st_histogram IS
---------------------------------------------------------------------------
-- Clocks and resets
---------------------------------------------------------------------------
CONSTANT c_dp_clk_period : TIME := 5 ns;
CONSTANT c_mm_clk_period : TIME := 20 ns;
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';
----------------------------------------------------------------------------
-- st_histogram
----------------------------------------------------------------------------
SIGNAL st_histogram_snk_in : t_dp_sosi;
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;
BEGIN
----------------------------------------------------------------------------
-- Clock and reset generation
----------------------------------------------------------------------------
dp_clk <= NOT dp_clk OR tb_end AFTER c_dp_clk_period/2;
dp_rst <= '1', '0' AFTER c_dp_clk_period*10;
mm_clk <= NOT mm_clk OR tb_end AFTER c_mm_clk_period/2;
mm_rst <= '1', '0' AFTER c_mm_clk_period*10;
----------------------------------------------------------------------------
-- mms_st_histogram
----------------------------------------------------------------------------
u_mms_st_histogram : ENTITY work.mms_st_histogram
GENERIC MAP(
g_nof_instances => 1,
g_data_w => 8,
g_nof_bins => 256,
g_nof_data_per_sync => 1024
)
PORT MAP (
dp_clk => dp_clk,
dp_rst => dp_rst,
mm_clk => mm_clk,
mm_rst => mm_rst,
snk_in_arr(0)=> st_histogram_snk_in,
reg_mosi => st_histogram_reg_mosi,
reg_miso => st_histogram_reg_miso,
ram_mosi => st_histogram_ram_mosi,
ram_miso => st_histogram_ram_miso
);
----------------------------------------------------------------------------
-- Readout of RAM
----------------------------------------------------------------------------
-- Perform MM read
p_verify_mm_read : PROCESS
BEGIN
st_histogram_ram_mosi <= c_mem_mosi_rst;
proc_common_wait_until_low(mm_clk, mm_rst);
proc_common_wait_some_cycles(mm_clk, 10);
-- Read address 7 of the RAM
proc_mem_mm_bus_rd(7, mm_clk, st_histogram_ram_mosi);
proc_common_wait_some_cycles(mm_clk, 10);
tb_end <= '1';
WAIT;
END PROCESS;
END tb;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment