library ieee; use ieee.std_logic_1164.all; -- use ieee.std_logic_arith.all; use ieee.std_logic_unsigned.all; use ieee.numeric_std.all; entity ram_cnt is generic ( width_addr : integer := 7; width_ram : integer := 54; -- 3*18 width_fast : integer := 8 ); port ( clk : in std_logic; rst : in std_logic; capture : in std_logic; clear : in std_logic; inputs : in std_logic_vector(2**width_addr-1 downto 0); input_mask : in std_logic_vector(2**width_addr-1 downto 0); scsn_addr : in std_logic_vector(15 downto 0); -- addr(11) = 0/1 : running/captured -- addr(10) = 0/1 : lower/upper 32 bits scsn_dout : out std_logic_vector(31 downto 0); scsn_req : in std_logic; scsn_ack : out std_logic ); end ram_cnt; architecture behav of ram_cnt is component dp_sram_128x54 is generic (piper : boolean := false); -- pipelined read port( wclk : in std_logic; rclk : in std_logic; we : in std_logic; waddr : in std_logic_vector( 6 downto 0); raddr : in std_logic_vector( 6 downto 0); din : in std_logic_vector(53 downto 0); dout : out std_logic_vector(53 downto 0) ); end component; component ram_cnt_cnt is generic(N : Positive := 7); port( clk : in std_logic; srst : in std_logic; selected : in std_logic; cnt_ena : in std_logic; track : in std_logic; q_curr : out std_logic_vector(N-1 downto 0); cout : out std_logic; q_hold : out std_logic_vector(N-1 downto 0); cout_hold : out std_logic); end component; signal capture1 : std_logic; -- capturing is running signal clearing : std_logic; -- clearing is running constant Ncnt : Integer := 2**width_addr; type cnt_array is array(Ncnt-1 downto 0) of std_logic_vector(width_fast-1 downto 0); signal cnt_fast : cnt_array; -- fast counters signal cnt_fast_r : cnt_array; -- shadow of the fast counters constant cnt_fast_low_max : std_logic_vector(width_fast-2 downto 0) := (others => '1'); signal cnt_new : std_logic_vector(width_ram-1 downto 0); -- value to be written signal cnt_old : std_logic_vector(width_ram-1 downto 0); signal cnt_run : std_logic_vector(width_ram-1 downto 0); signal cnt_capt : std_logic_vector(width_ram-1 downto 0); -- to RAM signal inp : std_logic_vector(Ncnt-1 downto 0); signal ram_we : std_logic; signal req : std_logic; signal clr_capt_cnt : std_logic_vector(width_addr downto 0); signal req_addr : std_logic_vector(15 downto 0); signal req_ack_run : std_logic; signal selected : std_logic_vector(Ncnt-1 downto 0); signal clr_capt_cnt_max : std_logic_vector(clr_capt_cnt'range);-- := (0|1|clr_capt_cnt'high => '1', others => '0'); signal addr : std_logic_vector(width_addr-1 downto 0); signal addrM1 : std_logic_vector(width_addr-1 downto 0); signal addrM2 : std_logic_vector(width_addr-1 downto 0); signal scsn_dout_i : std_logic_vector(scsn_dout'range); signal cnt_run_fast : std_logic_vector(width_fast-2 downto 0); signal cnt_fast_l : std_logic_vector(width_fast-2 downto 0); signal srst_cnt : std_logic; signal scsn_req1 : std_logic; begin -- input masking inp <= inputs and input_mask; process(inp) begin clr_capt_cnt_max <= (others => '0'); clr_capt_cnt_max(0) <= '1'; clr_capt_cnt_max(clr_capt_cnt_max'high) <= '1'; end process; srst_cnt <= rst or clear; -- fast counters gen_cnt_fast : for i in 0 to Ncnt-1 generate process(clk) begin if rising_edge(clk) then if to_integer(unsigned(addr)) = i then selected(i) <= '1'; else selected(i) <= '0'; end if; end if; end process; cnt_i: ram_cnt_cnt generic map(N => width_fast-1) port map( clk => clk, srst => srst_cnt, selected => selected(i), cnt_ena => inp(i), track => capture, q_curr => cnt_fast(i)(width_fast-2 downto 0), cout => cnt_fast(i)(width_fast-1), q_hold => cnt_fast_r(i)(width_fast-2 downto 0), cout_hold => cnt_fast_r(i)(width_fast-1)); end generate; -- slow counters, new value to be stored in the memory process (clk, rst) begin if rst = '1' then cnt_new <= (others => '0'); cnt_fast_l <= (others => '0'); elsif rising_edge(clk) then if clearing = '1' then cnt_new <= (others => '0'); -- first clear all bits -- copy the MSBit of the fast counter to the LSBit cnt_new(0) <= cnt_fast(conv_integer(addrM1))(width_fast-1); cnt_fast_l <= cnt_fast(conv_integer(addrM1))(width_fast-2 downto 0); else cnt_new <= cnt_old + cnt_fast(conv_integer(addrM1))(width_fast-1); cnt_fast_l <= cnt_fast(conv_integer(addrM1))(width_fast-2 downto 0); end if; end if; end process; -- address counting process (clk, rst, clr_capt_cnt_max) begin if rst = '1' then addr <= (others => '0'); addrM1 <= (others => '0'); addrM2 <= (others => '0'); capture1 <= '1'; clearing <= '1'; clr_capt_cnt <= clr_capt_cnt_max; elsif rising_edge(clk) then addr <= addr + 1; addrM1 <= addr; addrM2 <= addrM1; capture1 <= capture; -- clear state if clear = '1' then clr_capt_cnt <= clr_capt_cnt_max; clearing <= clear; elsif clr_capt_cnt /= 0 then clr_capt_cnt <= clr_capt_cnt - 1; else clearing <= '0'; end if; end if; end process; -- memory reading process (clk, rst) begin if rst = '1' then ram_we <= '0'; req_ack_run <= '0'; req <= '0'; scsn_req1 <= '0'; req_addr <= (others => '0'); cnt_run <= (others => '0'); cnt_run_fast <= (others => '0'); elsif rising_edge(clk) then ram_we <= '1'; req_ack_run <= '0'; scsn_req1 <= scsn_req; if scsn_req = '1' and scsn_req1 = '0' then req <= not scsn_addr(11); -- activate only if no capture req_addr <= scsn_addr; end if; if req = '1' and req_addr(width_addr-1 downto 0) = addrM2 then cnt_run <= cnt_new; cnt_run_fast <= cnt_fast_l; req_ack_run <= '1'; req <= '0'; end if; end if; end process; -- BRAM instance bram_inst: dp_sram_128x54 port map( wclk => clk, rclk => clk, we => ram_we, waddr => addrM2, raddr => addr, din => cnt_new, dout => cnt_old); -- BRAM for capturing bram_inst_readout: dp_sram_128x54 port map( wclk => clk, rclk => clk, we => capture1, waddr => addrM2, raddr => scsn_addr(width_addr-1 downto 0), din => cnt_new, dout => cnt_capt); -- read mux process(cnt_capt, cnt_fast_r, req_addr, cnt_run, cnt_run_fast) variable dout_scsn_capt : std_logic_vector(63 downto 0); variable dout_scsn_curr : std_logic_vector(63 downto 0); variable scsn_cnt_addr : Integer range 0 to 2**width_addr-1; begin scsn_cnt_addr := conv_integer(req_addr(width_addr-1 downto 0)); dout_scsn_capt := (others => '0'); dout_scsn_capt(width_fast-2 downto 0) := cnt_fast_r(scsn_cnt_addr)(width_fast-2 downto 0); dout_scsn_capt(width_ram-1+width_fast-1 downto width_fast-1) := cnt_capt + cnt_fast_r(scsn_cnt_addr)(width_fast-1); dout_scsn_curr(width_ram-1+width_fast-1 downto 0) := cnt_run & cnt_run_fast; -- addr(11) = 0/1 : running/captured -- addr(10) = 0/1 : lower/upper 32 bits case req_addr(11 downto 10) is when "00" => scsn_dout_i <= dout_scsn_curr(31 downto 0); when "01" => scsn_dout_i <= dout_scsn_curr(63 downto 32); when "10" => scsn_dout_i <= dout_scsn_capt(31 downto 0); when "11" => scsn_dout_i <= dout_scsn_capt(63 downto 32); when others => scsn_dout_i <= (others => '-'); end case; end process; -- SCSN readout process (clk) begin if rising_edge(clk) then scsn_dout <= scsn_dout_i; if scsn_addr(11) = '1' then if scsn_req='0' then scsn_ack <= '0'; elsif scsn_req1='1' and capture='0' then scsn_ack <= '1'; end if; else scsn_ack <= req_ack_run; end if; end if; end process; end;