diff --git a/libraries/base/common/hdllib.cfg b/libraries/base/common/hdllib.cfg index 218544df29669ddbdd9485f27c0fa23edd62a69b..df021e4fe036598c4e0fb4f53038f4455fa8c1a3 100644 --- a/libraries/base/common/hdllib.cfg +++ b/libraries/base/common/hdllib.cfg @@ -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 diff --git a/libraries/base/common/src/vhdl/common_pulse_delay.vhd b/libraries/base/common/src/vhdl/common_pulse_delay.vhd index 9abbe074a6bac3f8adabdb6507a3663ce8389ce3..0fdc2489f538e52f7b82a3640ee0d97bf1c8b3da 100644 --- a/libraries/base/common/src/vhdl/common_pulse_delay.vhd +++ b/libraries/base/common/src/vhdl/common_pulse_delay.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; diff --git a/libraries/base/common/src/vhdl/common_pulse_delay_reg.vhd b/libraries/base/common/src/vhdl/common_pulse_delay_reg.vhd new file mode 100644 index 0000000000000000000000000000000000000000..8404f10456202b1545a3d5fded6e0c568beb63d6 --- /dev/null +++ b/libraries/base/common/src/vhdl/common_pulse_delay_reg.vhd @@ -0,0 +1,145 @@ +------------------------------------------------------------------------------- +-- +-- 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; + diff --git a/libraries/base/common/src/vhdl/mms_common_pulse_delay.vhd b/libraries/base/common/src/vhdl/mms_common_pulse_delay.vhd new file mode 100644 index 0000000000000000000000000000000000000000..831ca0fed0e90813a40c13967eeae71f8854a533 --- /dev/null +++ b/libraries/base/common/src/vhdl/mms_common_pulse_delay.vhd @@ -0,0 +1,94 @@ +------------------------------------------------------------------------------- +-- +-- 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; + diff --git a/libraries/base/common/tb/vhdl/tb_common_pulse_delay.vhd b/libraries/base/common/tb/vhdl/tb_common_pulse_delay.vhd new file mode 100644 index 0000000000000000000000000000000000000000..57451d455aed36bd7098770e8d15348c83ba9852 --- /dev/null +++ b/libraries/base/common/tb/vhdl/tb_common_pulse_delay.vhd @@ -0,0 +1,99 @@ +------------------------------------------------------------------------------- +-- +-- 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; +