--============================================================================== -- CERN (BE-CO-HT) -- Burst mode control module -- Copyright CERN 2017 --============================================================================== -- -- author: Denia Bouhired (denia.bouhired@cern.ch) -- -- Date of creation: 19-09-2016 -- -- version: 1.0 -- -- Description: -- This module serves as a burst mode controller. When pulses of -- pre-defined length (250 ns or 1.2us) arrive, depending on the frequency, the -- module will allow the pulse to go through for a pre-defined amount of -- time, before going into pulse rejection mode. The rejection lasts for -- the time it takes for the "temperature" to reach the upper limit -- g_max_temp. For each frequency, the time of failure selected -- corresponds to the time it takes to reach g_max_temp for pulses of a given -- frequency. -- The array of values representing the thermal properties at the pulse level -- is given as the array of integers temp_decre_step. This array of values is -- generated in pre-processing via python script (*link to be added*). These -- values correspond to the thermal model of the board components. They are -- different for short 250ns pulses and long 1.2us pulses. -- Any modification to the board specification which would change the -- high frequency operation behaviour, would require changing the 3 -- parameters g_1_pulse_temp_rise, g_max_temp and t_temp_decre_step. These -- are generated using the Python file (*link to be added*). -- dependencies: -- --============================================================================== -- GNU LESSER GENERAL PUBLIC LICENSE --============================================================================== -- This source file is free software; you can redistribute it and/or modify it -- under the terms of the GNU Lesser General Public License as published by the -- Free Software Foundation; either version 2.1 of the License, or (at your -- option) any later version. This source 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 Lesser General Public License for more details. You should have -- received a copy of the GNU Lesser General Public License along with this -- source; if not, download it from http://www.gnu.org/licenses/lgpl-2.1.html --============================================================================== library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.gencores_pkg.all; use work.wishbone_pkg.all; use work.conv_common_gw_pkg.all; ---------------------------------------------------------------------------- -- ENTITY DECLARATION ---------------------------------------------------------------------------- entity conv_dyn_burst_ctrl is generic ( -- Fixed pulse width g_pwidth : natural range 2 to 40 := 5; -- Array of decrement values derived from the choses thermal model -- The following t_temp_decre_step values correspond to "1s, 6.5s, 10s, 26s, -- 36.66s and continuous" for pulsing for frequencies -- 2MHz, 1.33MHz, 1MHz, 800kHz, 667 kHz and 571kHz respectively. g_temp_decre_step : t_temp_decre_step := (0,0, 769, 31, 104, 14, 82, 0 ,0, 0, 0, 0, 0, 0, 0, 0); --Scaled temperature rise resulting from a single pulse. g_1_pulse_temp_rise :in unsigned (19 downto 0) := x"01388"; --5000 -- Scaled maximum temperature ceiling for pulse inhibition g_max_temp :in unsigned (39 downto 0) := x"02540BE400" --10^10 ); port ( -- Clock and active-low reset inputs clk_i : in std_logic; rst_n_i : in std_logic; -- Enable input, high frequency repetition is enabled when '1' en_i : in std_logic; -- Asynchronous input pulse with rising and falling edges pulse_burst_i : in std_logic; pulse_r_edge_p_i : in std_logic; pulse_f_edge_p_i : in std_logic; -- Temp_rise is output for external probing temp_rise_o : out unsigned (39 downto 0) ; -- Dynamic temperature-controlled ouput pulse train. pulse_burst_o : out std_logic; -- Burst error output, pulses high for one clock cycle when a pulse arrives -- within a burst rejection phase burst_err_p_o : out std_logic ); end entity conv_dyn_burst_ctrl; ---------------------------------------------------------------------------- -- ARCHITECTURE ---------------------------------------------------------------------------- architecture behav of conv_dyn_burst_ctrl is type t_state is ( IDLE, PULSE_REPEAT, PULSE_REJECT ); signal burst_ctrl_rst : std_logic; signal temp_rise : unsigned (39 downto 0) ; signal single_cycle_cnt : integer; signal n_cycle_cnt : integer range 1 to g_temp_decre_step'LENGTH; signal thermal_array_lgth :natural := 7; signal thermal_res : natural; -- thermal resolution in clock cycles signal state : t_state; signal nxt_state : t_state; signal s_pulse_reject, s_pulse_repeat : std_logic; begin thermal_array_lgth <= 7 when g_pwidth = 5 else 16; thermal_res <= g_pwidth; --Resolution depends on i/p pulse width -- Output from module depends on burst_ctrl_rst and en_i --------------------------------------------------------- pulse_burst_o <= '0' when burst_ctrl_rst = '1' else pulse_burst_i and en_i; temp_rise_o <= temp_rise; ----------------------------------------------------------------------------- -- Finite State Machine FSM ----------------------------------------------------------------------------- -- Finite State Machine to control pulse repetition as a function of rising -- board temperature. The FSM relies on temp_rise counter for state transitions ----------------------------------------------------------------------------- -- Process to trigger state transitions ---------------------------------------- p_fsm_transitions: process(clk_i) begin if rising_edge(clk_i) then if rst_n_i = '0' then state <= IDLE; elsif (en_i = '1') then state <= nxt_state; end if; end if; end process; -- Process to define FSM states -------------------------------- p_thermal_fsm_states : process (state, pulse_r_edge_p_i, pulse_f_edge_p_i, n_cycle_cnt, temp_rise, en_i ) begin case state is ------------------------------------------------------------------------- -- The FSM is IDLE, when the board is reset ------------------------------------------------------------------------- when IDLE => if en_i = '1' and pulse_r_edge_p_i = '1' then nxt_state <= PULSE_REPEAT; else nxt_state <= IDLE; end if; ------------------------------------------------------------------------- -- PULSE_REPEAT pulses are repeated as long as the temperature is below -- maximum g_max_temp. -- While the temperature counter temp_rise is above 0, the time between -- 2 pulses is used to decrement it, i.e. to cool down. ------------------------------------------------------------------------- when PULSE_REPEAT => if temp_rise <= g_max_temp then nxt_state <= PULSE_REPEAT; else nxt_state <= PULSE_REJECT; end if; -----------------------------------------------oo----------------------- -- PULSE_REJECT applies when a new pulse causes temperature to exceed -- maximum value -- i.e. temp_rise >= g_max_temp. ------------------------------------------------------------------------ when PULSE_REJECT => if (pulse_f_edge_p_i = '1' and temp_rise <= g_max_temp) OR temp_rise = 0 then nxt_state <= PULSE_REPEAT; else nxt_state <= PULSE_REJECT; end if; when others => nxt_state <= IDLE; end case; end process p_thermal_fsm_states; -- Process to define FSM outputs -------------------------------- p_thermal_fsm_outputs : process (state, pulse_r_edge_p_i) begin ------------------------------------------------------------------------- -- In the idle state all outputs are reset ------------------------------------------------------------------------- case state is when IDLE => burst_ctrl_rst <= '0'; burst_err_p_o <= '0'; s_pulse_reject <= '0'; s_pulse_repeat <= '0'; -------------------------------------------------------------------------- -- In PULSE_REPEAT pulses the input pulse is copied to the output and -- the state flag s_pulse_repeat is set -------------------------------------------------------------------------- when PULSE_REPEAT => burst_err_p_o <= '0'; burst_ctrl_rst <= '0'; s_pulse_repeat <= '1'; s_pulse_reject <= '0'; --------------------------------------------------------------------------- -- PULSE_REJECT sets burst_ctrl_rst to 1 to cutoff the output and sets the -- error pulse --------------------------------------------------------------------------- when PULSE_REJECT => burst_err_p_o <= pulse_r_edge_p_i; burst_ctrl_rst <= '1'; s_pulse_reject <= '1'; s_pulse_repeat <= '0'; when others => burst_ctrl_rst <= '0'; burst_err_p_o <= '0'; s_pulse_reject <= '0'; s_pulse_repeat <= '0'; end case; end process p_thermal_fsm_outputs; -- Process to count in n clk cycles steps -- single_cycle_cnt counts clock cycles. When it reaches the thermal resolution -- (pulse width dependent) it increments n_cycle_cnt by 1 and single_cycle_cnt -- is reset to 1 again. n_cycle_cnt is reset to 1 only when a new pulse arrives -- and pulse output inhibition is not active. --------------------------------------------------------------------------- p_n_cycle_cnt : process(clk_i) begin if rising_edge(clk_i) then if rst_n_i = '0' then single_cycle_cnt <= 1; n_cycle_cnt <= 1; else -- Reset counters in the event of a new pulse only -- when pulse rejection is not active if (pulse_r_edge_p_i = '1' and burst_ctrl_rst = '0') then --OR --(pulse_f_edge_p_i = '1' and n_cycle_cnt /= 1) then single_cycle_cnt <= 1; n_cycle_cnt <= 1; else --count clk cycles single_cycle_cnt <= single_cycle_cnt + 1; if single_cycle_cnt = thermal_res then if n_cycle_cnt < thermal_array_lgth then -- increment every n=thermal_res clk cycles n_cycle_cnt <= n_cycle_cnt + 1; end if; single_cycle_cnt <= 1; end if; end if; end if; end if; end process p_n_cycle_cnt; -- Process to output temperature rise. When a new pulse arrives, -- temp_rise rises at the falling edge. Between pulses, temp_rise is -- decremented according to the thermal model. ------------------------------------------------------------------------------ p_temp_rise : process(clk_i) begin if rising_edge(clk_i) then if rst_n_i = '0' then temp_rise <= (others => '0'); else if s_pulse_repeat = '1' then if pulse_f_edge_p_i ='1' then temp_rise <= temp_rise + g_1_pulse_temp_rise; else if temp_rise >= g_temp_decre_step(n_cycle_cnt-1) then temp_rise <= temp_rise - to_unsigned(g_temp_decre_step(n_cycle_cnt-1), 40); else temp_rise <= (others => '0'); end if; end if; elsif s_pulse_reject = '1' and temp_rise > 0 then if temp_rise >= g_temp_decre_step(n_cycle_cnt-1) then temp_rise <= temp_rise - to_unsigned(g_temp_decre_step(n_cycle_cnt-1), 40); else temp_rise <= (others => '0'); end if; end if; end if; end if; end process p_temp_rise; end architecture behav;