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

-Added reg + MMS wrapper for common_pulse_delay;

-Added test bench for common_pulse_delay.
parent 161c6395
No related branches found
No related tags found
No related merge requests found
......@@ -129,6 +129,9 @@ synth_files =
src/vhdl/mms_common_reg.vhd
src/vhdl/mms_common_stable_monitor.vhd
src/vhdl/common_pulse_delay_reg.vhd
src/vhdl/mms_common_pulse_delay.vhd
src/vhdl/avs_common_mm.vhd
src/vhdl/avs_common_mm_irq.vhd
......@@ -163,6 +166,7 @@ test_bench_files =
tb/vhdl/tb_common_paged_ram_crw_crw.vhd
tb/vhdl/tb_common_paged_ram_ww_rr.vhd
tb/vhdl/tb_common_pulse_extend.vhd
tb/vhdl/tb_common_pulse_delay.vhd
tb/vhdl/tb_common_pulser.vhd
tb/vhdl/tb_common_pulser_us_ms_s.vhd
tb/vhdl/tb_common_reg_cross_domain.vhd
......
......@@ -22,6 +22,8 @@
-- . Daniel van der Schuur
-- Purpose:
-- . Produce pulse_out pulse_delay clk cycles after pulse_in
-- Description:
-- . Note: pulse_out must have occurured before the next pulse_in can be delayed.
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
......@@ -45,6 +47,9 @@ ARCHITECTURE str OF common_pulse_delay IS
CONSTANT c_pulse_delay_max_width : NATURAL := ceil_log2(g_pulse_delay_max);
SIGNAL pulse_delay_reg : STD_LOGIC_VECTOR(ceil_log2(g_pulse_delay_max)-1 DOWNTO 0);
SIGNAL nxt_pulse_delay_reg : STD_LOGIC_VECTOR(ceil_log2(g_pulse_delay_max)-1 DOWNTO 0);
SIGNAL common_counter_cnt_en : STD_LOGIC;
SIGNAL common_counter_count : STD_LOGIC_VECTOR(c_pulse_delay_max_width-1 DOWNTO 0);
......@@ -91,8 +96,11 @@ BEGIN
-------------------------------------------------------------------------------
-- Assign nxt_pulse_out
-------------------------------------------------------------------------------
nxt_pulse_out <= pulse_in WHEN pulse_delay=TO_UVEC(0, c_pulse_delay_max_width) ELSE -- 0 cycles delay
'1' WHEN common_counter_count=pulse_delay ELSE '0'; -- >=1 cycles delay
-- Store the control setting
nxt_pulse_delay_reg <= pulse_delay WHEN pulse_in='1' ELSE pulse_delay_reg;
nxt_pulse_out <= pulse_in WHEN pulse_delay=TO_UVEC(0, c_pulse_delay_max_width) ELSE -- 0 cycles delay (pulse_delay_reg not valid yet; using pulse_delay)
'1' WHEN common_counter_count=pulse_delay_reg ELSE '0'; -- >=1 cycles delay (so pulse_delay_reg will contain registered pulse_delay)
-------------------------------------------------------------------------------
-- Optional output register
......@@ -101,9 +109,9 @@ BEGIN
p_clk : PROCESS (rst, clk)
BEGIN
IF rst = '1' THEN
pulse_out <= '0';
pulse_out <= '0';
ELSIF rising_edge(clk) THEN
pulse_out <= nxt_pulse_out;
pulse_out <= nxt_pulse_out;
END IF;
END PROCESS;
END GENERATE;
......@@ -111,5 +119,17 @@ BEGIN
no_register : IF g_register_out=FALSE GENERATE
pulse_out <= nxt_pulse_out;
END GENERATE;
-------------------------------------------------------------------------------
-- Registers
-------------------------------------------------------------------------------
p_clk : PROCESS (rst, clk)
BEGIN
IF rst = '1' THEN
pulse_delay_reg <= (OTHERS=>'0');
ELSIF rising_edge(clk) THEN
pulse_delay_reg <= nxt_pulse_delay_reg;
END IF;
END PROCESS;
END str;
-------------------------------------------------------------------------------
--
-- Copyright (C) 2017
-- 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/>.
--
-------------------------------------------------------------------------------
-- Author:
-- . Daniel van der Schuur
-- Purpose:
-- . Provide MM slave register for common_pulse_delay
-- Description:
-- Set pulse_delay between incoming and outgoing pulse, in units of dp_clk cycles (5ns)
LIBRARY IEEE, common_lib;
USE IEEE.STD_LOGIC_1164.ALL;
USE common_lib.common_pkg.ALL;
USE common_lib.common_mem_pkg.ALL;
ENTITY common_pulse_delay_reg IS
GENERIC (
g_cross_clock_domain : BOOLEAN := TRUE; -- use FALSE when mm_clk and pulse_clk are the same, else use TRUE to cross the clock domain
g_pulse_delay_max : NATURAL := 0 -- Maximum number of clk cycles that pulse can be delayed
);
PORT (
pulse_clk : IN STD_LOGIC;
pulse_rst : IN STD_LOGIC;
pulse_delay : OUT STD_LOGIC_VECTOR(ceil_log2(g_pulse_delay_max)-1 DOWNTO 0);
mm_clk : IN STD_LOGIC;
mm_rst : IN STD_LOGIC;
sla_in : IN t_mem_mosi;
sla_out : OUT t_mem_miso
);
END common_pulse_delay_reg;
ARCHITECTURE rtl OF common_pulse_delay_reg IS
CONSTANT c_nof_mm_regs : NATURAL := 1;
CONSTANT c_mm_reg : t_c_mem := (latency => 1,
adr_w => ceil_log2(c_nof_mm_regs),
dat_w => c_word_w,
nof_dat => c_nof_mm_regs,
init_sl => '0');
SIGNAL mm_pulse_delay : STD_LOGIC_VECTOR(ceil_log2(g_pulse_delay_max)-1 DOWNTO 0);
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_rst, mm_clk)
BEGIN
IF mm_rst = '1' THEN
-- Read access
sla_out <= c_mem_miso_rst;
-- Access event, register values
mm_pulse_delay <= (OTHERS=>'0');
ELSIF rising_edge(mm_clk) THEN
-- Read access defaults
sla_out.rdval <= '0';
-- Write access: set register value
IF sla_in.wr = '1' THEN
CASE TO_UINT(sla_in.address(c_mm_reg.adr_w-1 DOWNTO 0)) IS
WHEN 0 =>
-- Write pulse_delay
mm_pulse_delay <= sla_in.wrdata(ceil_log2(g_pulse_delay_max)-1 DOWNTO 0);
WHEN OTHERS => NULL; -- not used MM addresses
END CASE;
-- Read access: get register value
ELSIF sla_in.rd = '1' THEN
sla_out <= c_mem_miso_rst; -- set unused rddata bits to '0' when read
sla_out.rdval <= '1'; -- c_mm_reg.latency = 1
CASE TO_UINT(sla_in.address(c_mm_reg.adr_w-1 DOWNTO 0)) IS
WHEN 0 =>
-- Read back pulse_delay
sla_out.rddata(ceil_log2(g_pulse_delay_max)-1 DOWNTO 0) <= mm_pulse_delay;
WHEN OTHERS => NULL; -- not used MM addresses
END CASE;
END IF;
END IF;
END PROCESS;
------------------------------------------------------------------------------
-- Transfer register value between mm_clk and pulse_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).
------------------------------------------------------------------------------
no_common_reg_cross_domain : IF g_cross_clock_domain = FALSE GENERATE -- so mm_clk = pulse_clk
pulse_delay <= mm_pulse_delay;
END GENERATE; -- common_reg_cross_domain
gen_common_reg_cross_domain : IF g_cross_clock_domain = TRUE GENERATE
u_common_reg_cross_domain : ENTITY work.common_reg_cross_domain
PORT MAP (
in_rst => mm_rst,
in_clk => mm_clk,
in_dat => mm_pulse_delay,
in_done => OPEN,
out_rst => pulse_rst,
out_clk => pulse_clk,
out_dat => pulse_delay,
out_new => OPEN
);
END GENERATE; -- gen_common_reg_cross_domain
END rtl;
-------------------------------------------------------------------------------
--
-- Copyright (C) 2017
-- 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/>.
--
-------------------------------------------------------------------------------
-- Author:
-- . Daniel van der Schuur
-- Purpose:
-- . MM wrapper for common_pulse_delay.vhd
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 technology_lib.technology_select_pkg.ALL;
ENTITY mms_common_pulse_delay IS
GENERIC (
g_pulse_delay_max : NATURAL := 0 -- Maximum number of clk cycles that pulse can be delayed
);
PORT (
pulse_clk : IN STD_LOGIC;
pulse_rst : IN STD_LOGIC;
pulse_in : IN STD_LOGIC;
pulse_out : OUT STD_LOGIC;
mm_clk : IN STD_LOGIC;
mm_rst : IN STD_LOGIC;
reg_mosi : IN t_mem_mosi := c_mem_mosi_rst;
reg_miso : OUT t_mem_miso := c_mem_miso_rst
);
END mms_common_pulse_delay;
ARCHITECTURE str OF mms_common_pulse_delay IS
SIGNAL pulse_delay : STD_LOGIC_VECTOR(ceil_log2(g_pulse_delay_max)-1 DOWNTO 0);
BEGIN
------------------------------------------------------------------------------
-- common_pulse_delay
------------------------------------------------------------------------------
u_common_pulse_delay : ENTITY common_lib.common_pulse_delay
GENERIC MAP (
g_pulse_delay_max => g_pulse_delay_max,
g_register_out => TRUE
)
PORT MAP (
clk => pulse_clk,
rst => pulse_rst,
pulse_in => pulse_in,
pulse_delay => pulse_delay,
pulse_out => pulse_out
);
------------------------------------------------------------------------------
-- New MM interface via avs_common_mm
------------------------------------------------------------------------------
u_common_pulse_delay_reg : ENTITY work.common_pulse_delay_reg
GENERIC MAP (
g_cross_clock_domain => TRUE,
g_pulse_delay_max => g_pulse_delay_max
)
PORT MAP (
pulse_clk => pulse_clk,
pulse_rst => pulse_rst,
pulse_delay => pulse_delay,
mm_clk => mm_clk,
mm_rst => mm_rst,
sla_in => reg_mosi,
sla_out => reg_miso
);
END str;
-------------------------------------------------------------------------------
--
-- Copyright (C) 2017
-- 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/>.
--
-------------------------------------------------------------------------------
-- Author:
-- . Daniel van der Schuur
-- Purpose:
-- . Feed different pulse_delay control settings to common_pulse_delay,
-- verify correct pulse_out
LIBRARY IEEE, common_lib;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
USE common_lib.common_pkg.ALL;
ENTITY tb_common_pulse_delay IS
END tb_common_pulse_delay;
ARCHITECTURE tb OF tb_common_pulse_delay IS
CONSTANT c_clk_period : TIME := 5 ns;
CONSTANT c_pulse_delay_max : NATURAL := 10;
CONSTANT c_pulse_delay_max_w : NATURAL := ceil_log2(c_pulse_delay_max);
SIGNAL tb_end : STD_LOGIC := '0';
SIGNAL clk : STD_LOGIC := '1';
SIGNAL rst : STD_LOGIC := '1';
SIGNAL pulse_in : STD_LOGIC;
SIGNAL nxt_pulse_in : STD_LOGIC;
SIGNAL pulse_delay : STD_LOGIC_VECTOR(c_pulse_delay_max_w-1 DOWNTO 0);
SIGNAL nxt_pulse_delay : STD_LOGIC_VECTOR(c_pulse_delay_max_w-1 DOWNTO 0);
SIGNAL pulse_out : STD_LOGIC;
BEGIN
-----------------------------------------------------------------------------
-- Clock & reset
-----------------------------------------------------------------------------
rst <= '1', '0' AFTER 7*c_clk_period;
clk <= NOT clk OR tb_end AFTER c_clk_period/2;
-----------------------------------------------------------------------------
-- Stimuli
-----------------------------------------------------------------------------
-- Create the first pulse here, then feed pulse_out to pulse
nxt_pulse_in <= '1'; --FIXME
nxt_pulse_delay <= INCR_UVEC(pulse_delay, 1) WHEN pulse_in='1' ELSE pulse_delay;
-----------------------------------------------------------------------------
-- common_pulse_delay
-----------------------------------------------------------------------------
u_common_pulse_delay : ENTITY work.common_pulse_delay
GENERIC MAP (
g_pulse_delay_max => c_pulse_delay_max,
g_register_out => FALSE
)
PORT MAP (
clk => clk,
rst => rst,
pulse_in => pulse_in,
pulse_delay => pulse_delay,
pulse_out => pulse_out
);
-------------------------------------------------------------------------------
-- Registers
-------------------------------------------------------------------------------
p_clk : PROCESS (rst, clk)
BEGIN
IF rst = '1' THEN
pulse_delay <= (OTHERS=>'0');
pulse_in <= '0';
ELSIF rising_edge(clk) THEN
pulse_delay <= nxt_pulse_delay;
pulse_in <= nxt_pulse_in;
END IF;
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