-- -- pllspu.vhd -- -- PLL and Signal Processing Unit for CERN TMS PUPE FPGA design -- -- Based on pll3.vhd provided by G. Kasprowicz (CERN) -- -- Version 1.0 4/1/06 A.McCormick (Alpha Data) -- -- Version 1.1 13/3/06 A.McCormick (Alpha Data) -- Added 2nd loop filter -- -- Version 1.2.4c, June 2011, Jeroen Belleman (JMB) -- Rearranging things and fixing bugs involving injection, C-timing, etc. -- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_signed.all; use ieee.std_logic_arith.all; use ieee.std_logic_misc.all; entity pllspu is port ( clk : in std_logic; rst : in std_logic; ten_mhz_clk : in std_logic; -- Timing Inputs (already edge detected) cycle_start : in std_logic; cycle_start_ten_mhz : in std_logic; cycle_stop : in std_logic; cal_start : in std_logic; cal_stop : in std_logic; injection : in std_logic; hchange : in std_logic; fref : in std_logic; frev_in : in std_Logic; -- (non edge detected) -- PLL Registers init : in std_logic; loop_ctrl : in std_logic; dds_freq_limit_en : in std_logic; blr_disable : in std_logic; pll_frequency : in std_logic_vector(31 downto 0); pll_freqdelay : in std_logic_vector(31 downto 0); pll_phasedelay : in std_logic_vector(31 downto 0); pll_gain : in std_logic_vector(31 downto 0); dds_freq_min : in std_logic_vector(31 downto 0); dds_freq_max : in std_logic_vector(31 downto 0); use_neighbour_pll : in std_logic_vector(3 downto 0); -- Cross connections to other pupes plls pll_mixed_sigma0_out : out std_logic_vector(13 downto 0); pll_mixed_sigma1_out : out std_logic_vector(13 downto 0); pll_mixed_sigma0a_in : in std_logic_vector(13 downto 0); pll_mixed_sigma1a_in : in std_logic_vector(13 downto 0); pll_mixed_sigma0b_in : in std_logic_vector(13 downto 0); pll_mixed_sigma1b_in : in std_logic_vector(13 downto 0); -- ADC Inputs sigma : in std_logic_vector(13 downto 0); deltax : in std_logic_vector(13 downto 0); deltay : in std_logic_vector(13 downto 0); -- Switch Table Read Only Interface switch_table_addr : out std_logic_vector(3 downto 0); switch_table_data : in std_logic_vector(31 downto 0); -- Phase Table Read Only Interface phase_table_addr : out std_logic_vector(12 downto 0); phase_table_data : in std_logic_vector(7 downto 0); -- Outputs to Data Logging Module result_valid : out std_logic; result_0 : out std_logic_vector (23 downto 0); result_1 : out std_logic_vector (23 downto 0); result_2 : out std_logic_vector (23 downto 0); acq : out std_logic; cycle : out std_logic_vector(31 downto 0); ctime : out std_logic_vector(31 downto 0); ms_pulse_out : out std_Logic; phase_table_sync : out std_Logic; hchange_sync : out std_logic; injection_sync : out std_logic; cal_start_sync : out std_logic; -- Output to IO phase_table_msb_out : out std_logic; -- State Machine PCI Control cycle_init_val : in std_logic_vector(31 downto 0); cycle_val_set : in std_logic; switch_state_reg : out std_logic_vector(3 downto 0); -- Diagnostics Output diagnostics : out std_logic_vector(255 downto 0) ); end pllspu; architecture rtl of pllspu is --BLR signal e0, e1, e2 : std_logic_vector(23 downto 0); signal b0, b1, b2 : std_logic_vector(23 downto 0); signal x0, x1, x2 : std_logic_vector(23 downto 0); signal y0, y1, y2 : std_logic_vector(23 downto 0); signal BLR_data_in_0 : std_logic_vector(23 downto 0); signal BLR_data_in_1 : std_logic_vector(23 downto 0); signal BLR_data_in_2 : std_logic_vector(23 downto 0); signal BLR_data_out_0 : std_logic_vector(23 downto 0); signal BLR_data_out_1 : std_logic_vector(23 downto 0); signal BLR_data_out_2 : std_logic_vector(23 downto 0); --DDS signal dds_ph : std_logic_vector(32 downto 0); -- JMB signal dds_ph_next : std_logic_vector(32 downto 0); -- JMB signal dds_ph_del : std_logic_vector(31 downto 23); -- JMB signal dds_of : std_logic; -- JMB signal dds_ph32_reg : std_logic; -- JMB signal dds_freq : std_logic_vector(31 downto 0); signal dds_freq_limit : std_logic_vector(31 downto 0); signal f_error_dds : std_logic_vector(31 downto 0); signal f_error,f_err : std_logic_vector(31 downto 0); signal Frev_num : std_logic_vector(13 downto 0); signal pll_init : std_logic; signal pll_init_count : std_logic_vector(15 downto 0); signal load_dds_freq, dds_freq_OVR, dds_freq_UR, clk62 : std_logic := '0'; signal over_ph : std_logic; -- JMB --multiplier signal mul_data_in1 : std_logic_vector (13 downto 0); signal mul_data_in2 : std_logic_vector (13 downto 0); signal mult_int1 : std_logic_vector (13 downto 0); signal mult_int2 : std_logic_vector (13 downto 0); signal mult_out1 : std_logic_vector (13 downto 0); signal mult_out2 : std_logic_vector (13 downto 0); signal mult_neg_data_in1 : std_logic_vector (13 downto 0); signal mult_neg_data_in2 : std_logic_vector (13 downto 0); --filter signal n1, n2, n3, n4 : std_logic_vector (31 downto 0); signal n5, n6, s3, s4 : std_logic_vector (31 downto 0); signal s5, s6 : std_logic_vector (31 downto 0); signal filter_data_out : std_logic_vector (31 downto 0); signal filter1_in : std_logic_vector (15 downto 0); signal nb1, nb2, nb3 : std_logic_vector (31 downto 0); signal nb4, nb5, nb6 : std_logic_vector (31 downto 0); signal sb3, sb4, sb5 : std_logic_vector (31 downto 0); signal sb6 : std_logic_vector (31 downto 0); signal filter2_in : std_logic_vector (15 downto 0); -- integrators type STATE_TYPE is (idle, integrate, ready, reset_acc); signal state : STATE_TYPE; signal accumulate_0 : std_logic_vector (23 downto 0) := (others => '0'); signal accumulate_1 : std_logic_vector (23 downto 0) := (others => '0'); signal accumulate_2 : std_logic_vector (23 downto 0) := (others => '0'); signal result0_tmp : std_logic_vector (23 downto 0) := (others => '0'); signal result1_tmp : std_logic_vector (23 downto 0) := (others => '0'); signal result2_tmp : std_logic_vector (23 downto 0) := (others => '0'); signal acc_reset : std_logic; signal result_Write_en : std_logic; type shifted_ferror_type is array (natural range <>) of std_logic_vector(31 downto 0); -- Timing event handling and delayed event generation signal cal_start_switch : std_logic; signal cal_start_reg : std_logic; signal injection_pending: std_logic; -- JMB signal injection_switch : std_logic; signal injection_reg : std_logic; signal hchange_pending : std_logic; -- JMB signal hchange_switch : std_logic; signal hchange_reg : std_logic; signal cycle_stop_reg : std_logic; -- JMB signal cycle_stop_switch: std_logic; -- JMB signal event_delayed_i : std_logic; signal event : std_logic; signal event_delay_count : std_logic_vector(3 downto 0); signal event_delayed_switch : std_logic; signal ps_event_pending : std_logic; -- JMB signal ps_event_switch : std_logic; -- JMB signal ps_event : std_logic; -- JMB signal ps_event_reg : std_logic; -- JMB -- Event state machine signal switch_state : std_logic_vector(3 downto 0); signal switch_reading : std_logic; signal phase_table_msb_falling : std_Logic; signal fsm0_transition : std_logic; -- JMB signal ph_crossed : std_logic; -- JMB -- Beam synchronous signal generation and routing signal rf_select1 : std_logic; signal rf_select2 : std_logic; signal use_pll_for_lo1 : std_logic; signal use_pll_for_lo2 : std_logic; signal sel_filter : std_logic; signal clear_pll_ph : std_logic; signal LO_pulse1 : std_logic; signal LO_pulse2 : std_logic; signal blr_pulse : std_logic; signal gate_pulse : std_logic; signal pll_msb : std_logic; signal phase_table_msb : std_logic; signal phase_table_msb_reg : std_logic; signal phase_table_addr_i : std_logic_vector(12 downto 0); -- Cycle counting and millisecond timing signal cycle_count : std_logic_vector(15 downto 0); signal ctime_count : std_logic_vector(15 downto 0); signal ctimer : std_logic_vector(16 downto 0); signal ms_pulse : std_logic; signal ms_new : std_logic; signal ms_pulse_reg : std_logic_vector(7 downto 0); -- Neighbour's phase detector signals signal other_plls1a,other_plls2a : std_logic_vector(13 downto 0); signal other_plls1b,other_plls2b : std_logic_vector(13 downto 0); begin -- rtl -- -- The millisecond timer. Divide the 10MHz clock by 10000 and count -- how often it rolls over. -- ctimer0: process (ten_mhz_clk, rst) begin -- process ctimer0 if rst = '1' then -- asynchronous reset ctime_count <= (others => '0'); ctimer <= CONV_STD_LOGIC_VECTOR(9999, 17); ms_pulse <= '0'; elsif ten_mhz_clk'event and ten_mhz_clk = '1' then -- rising clock edge ms_pulse <= not OR_reduce(ctimer); if cycle_start_ten_mhz = '1' then ctimer <= CONV_STD_LOGIC_VECTOR(9999, 17); ctime_count <= (others => '0'); else if OR_reduce(ctimer) = '0' then ctimer <= CONV_STD_LOGIC_VECTOR(9999, 17); ctime_count <= ctime_count+1; else ctimer <= ctimer-1; end if; end if; end if; end process ctimer0; -- -- Use the millisecond timer to generate ms_pulse_out events, -- post-synchronized to turn boundaries. -- JMB -- ctimesync: process(clk,rst) begin if rst = '1' then -- asynchronous reset ms_pulse_reg <= (others => '0'); ms_pulse_out <= '0'; ms_new <= '0'; -- JMB ctime <= (others => '0'); elsif rising_edge(clk) then -- Update CTIME 56ns after rising edge of MS Pulse -- to give plenty of time for ctime_count to settle -- (No idea why this should be needed... JMB) ms_pulse_reg <= ms_pulse_reg (6 downto 0) & ms_pulse; if ms_pulse_reg(7) = '0' and ms_pulse_reg(6) = '1' then ms_new <= '1'; -- JMB else ms_new <= ms_new; -- JMB end if; -- Update ctime only on revolution boundaries -- JMB if phase_table_msb_falling = '1' and ms_new = '1' then -- JMB ms_pulse_out <= '1'; ctime <= EXT(ctime_count, 32); ms_new <= '0'; -- JMB else ms_pulse_out <= '0'; end if; end if; end process ctimesync; -- -- Timing inputs actions are delayed to take effect only at frev boundaries, -- with the exception of injection, which *defines* the frev boundary. -- JMB -- ps_events: process(clk,rst) begin if rst = '1' then hchange_pending <= '0'; hchange_switch <= '0'; hchange_reg <= '0'; injection_pending <= '0'; injection_switch <= '0'; injection_reg <= '0'; cal_start_switch <= '0'; cal_start_reg <= '0'; cycle_stop_switch <= '0'; cycle_stop_reg <= '0'; elsif rising_edge(clk) then -- -- Calibration start -- if cycle_start = '1' then cal_start_switch <= '0'; else if cal_start = '1' and cal_start_reg = '0' then cal_start_switch <= '1'; elsif cal_start_switch = '1' and fsm0_transition = '1' then cal_start_switch <= '0'; end if; end if; cal_start_reg <= cal_start; -- -- Injection. Also defines start of Frev period in DDS process if clear_pll_ph is set. -- It clear_pll_ph=0, such as for 2nd injection, wait for the current Frev period to finish. -- Then propagate the effect around the ring. -- if cycle_start = '1' then injection_switch <= '0'; injection_pending <= '0'; else if injection = '1' and injection_reg = '0' and clear_pll_ph = '0' then injection_pending <= '1'; elsif injection = '1' and injection_reg = '0' and clear_pll_ph = '1' then injection_switch <= '1'; elsif injection_pending = '1' and dds_of = '1' then injection_switch <= '1'; elsif injection_switch = '1' and fsm0_transition = '1' then injection_switch <= '0'; injection_pending <= '0'; end if; end if; injection_reg <= injection; -- -- Harmonic change. Wait for the current Frev period to finish. -- Then propagate the effect around the ring. -- if cycle_start = '1' then hchange_switch <= '0'; hchange_pending <= '0'; else if hchange = '1' and hchange_reg = '0' then hchange_pending <= '1'; elsif hchange_pending = '1' and dds_of = '1' then hchange_switch <= '1'; elsif hchange_switch = '1' and fsm0_transition = '1' then hchange_switch <= '0'; hchange_pending <= '0'; end if; end if; hchange_reg <= hchange; -- -- Synchronize cycle_stop so that the number of turns acquired is integer. -- This is needed to be able to count backwards from the end. -- -- if cycle_start = '1' then -- cycle_stop_switch <= '0'; -- else -- if cycle_stop = '1' and cycle_stop_reg = '0' then -- cycle_stop_switch <= '1'; -- elsif fsm0_transition = '1' then -- cycle_stop_switch <= '0'; -- end if; -- end if; -- cycle_stop_reg <= cycle_stop; end if; end process ps_events; cal_start_sync <= cal_start_switch and fsm0_transition; injection_sync <= injection_switch and fsm0_transition; hchange_sync <= hchange_switch and fsm0_transition; -- ps_event_switch <= cal_start_switch or injection_switch or hchange_switch or event_delayed_switch; -- JMB ps_event_switch <= cal_start_switch or injection_switch or hchange_switch; -- JMB ps_event <= cal_start or injection or hchange; -- JMB ps_event_reg <= cal_start_reg or injection_reg or hchange_reg; -- JMB ps_event_pending <= injection_pending or hchange_pending; -- JMB -- -- Every external event is followed by an internally generated pseudo-event that -- may be used to cause further state transitions. The delayed event occurs -- 14 turns after an external event, about 30us for the PS. -- delay_event: process (clk, rst) begin -- process delay_event if rst = '1' then -- asynchronous reset event_delayed_i <= '0'; event <= '0'; event_delay_count <= (others => '0'); event_delayed_switch <= '0'; elsif clk'event and clk = '1' then -- rising clock edge event <= cycle_start or cycle_stop or cal_stop or cal_start or ((hchange_switch or injection_switch) and fsm0_transition); if OR_reduce(event_delay_count) = '0' then if event = '1' then event_delay_count <= CONV_STD_LOGIC_VECTOR(1,4); end if; else if phase_table_msb_falling = '1' then event_delay_count <= event_delay_count+1; end if; end if; event_delayed_i <= AND_reduce(event_delay_count); if event_delayed_i = '1' then event_delayed_switch <= '1'; elsif event_delayed_switch = '1' and fsm0_transition = '1' then event_delayed_switch <= '0'; end if; end if; end process delay_event; -- -- A state machine, driven by the PS timing events, controls signal generation -- and routing. State changes are delayed to occur on frev boundaries. -- switch_fsm0 : process (clk, rst) begin -- process switch_fsm0 if rst = '1' then -- asynchronous reset switch_state <= (others => '1'); switch_reading <= '0'; cycle_count <= (others => '0'); elsif rising_edge(clk) then if cycle_val_set = '1' then cycle_count <= cycle_init_val(15 downto 0); elsif cycle_stop = '1' then cycle_count <= cycle_count+1; end if; if init = '1' then switch_state <= (others => '1'); switch_reading <= '0'; else -- 1 cycle delay between switching states and next state switch table -- data being available if switch_reading = '1' then switch_reading <= '0'; else if switch_state = "1111" or switch_state = "1110" then if cycle_start = '1' then switch_state <= "0000"; switch_reading <= '1'; end if; else -- if cycle_stop_switch = '1' and fsm0_transition = '1' then -- JMB if cycle_stop = '1' then switch_state <= switch_table_data(11 downto 8); switch_reading <= '1'; elsif cal_stop = '1' then switch_state <= switch_table_data(15 downto 12); switch_reading <= '1'; elsif cal_start_switch = '1' and fsm0_transition = '1' then switch_state <= switch_table_data(19 downto 16); switch_reading <= '1'; elsif injection_switch = '1' and fsm0_transition = '1' then switch_state <= switch_table_data(23 downto 20); switch_reading <= '1'; elsif hchange_switch = '1' and fsm0_transition = '1' then switch_state <= switch_table_data(27 downto 24); switch_reading <= '1'; elsif event_delayed_switch = '1' and fsm0_transition = '1' then switch_state <= switch_table_data(31 downto 28); switch_reading <= '1'; end if; end if; end if; end if; clear_pll_ph <= switch_table_data(6); -- JMB use_pll_for_lo2 <= switch_table_data(5); use_pll_for_lo1 <= switch_table_data(4); sel_filter <= switch_table_data(3); rf_select2 <= switch_table_data(2); rf_select1 <= switch_table_data(1); acq <= switch_table_data(0); end if; end process switch_fsm0; cycle <= EXT(cycle_count, 32); switch_state_reg <= switch_state; switch_table_addr <= switch_state; phase_table_addr_i(12 downto 9) <= switch_state; phase_table_addr_i(8 downto 0) <= dds_ph_del(31 downto 23) - pll_phasedelay(8 downto 0); -- JMB phase_table_addr <= phase_table_addr_i; phase_table_msb <= phase_table_addr_i(8); LO_pulse1 <= phase_table_data(0) when use_pll_for_lo1 = '0' else not pll_msb; BLR_pulse <= phase_table_data(1); GATE_pulse <= phase_table_data(2); LO_pulse2 <= phase_table_data(3) when use_pll_for_lo2 = '0' else not pll_msb; -- -- Mark frev boundaries by detecting when the MSB of the phase table address -- falls. This was used to synchronize state machine transitions, but no more. -- See below. process (clk) begin -- process if clk'event and clk = '1' then -- rising clock edge phase_table_msb_reg <= phase_table_msb; -- falling edge of phase table phase_table_msb_falling <= (not phase_table_msb) and phase_table_msb_reg; phase_table_sync <= (not phase_table_msb) and phase_table_msb_reg; phase_table_msb_out <= phase_table_msb_reg; end if; end process; -- -- Another criterion for state changes: Switch when phase crosses -- a PU-specific value. -- This requires coverage of two turns, hence an extra MSB bit on the -- the DDS phase accumulator and the phasedelay. Fortunately, the software -- doesn't care, because it uses 32 bit values throughout. -- JMB -- --process (clk,rst) --begin -- if rst = '1' then -- ph_crossed <= '0'; -- fsm0_transition <= '0'; -- elsif rising_edge(clk) then -- if ps_event_switch = '1' then -- if over_ph = '1' then -- fsm0_transition <= '1'; -- ph_crossed <= '1'; -- end if; -- else -- ph_crossed <= '0'; -- fsm0_transition <= ph_crossed; -- end if; -- end if; --end process; -- The synchronous version is still one clock late. Try a combinatorial version. fsm0_transition <= ps_event_switch and over_ph; -- Whooo! -- -- Loop Gain Control -- purpose: Shifts f_error by number of bits specified by in "loop gain" -- loop_gain0 : process (pll_gain, f_error) variable shifted_ferror : shifted_ferror_type(0 to 15); variable loop_gain_int : integer; begin -- process loop_gain0 loop_gain_int := CONV_INTEGER(('0' & pll_gain(19 downto 16))); shifted_ferror(0) := f_error; for i in 1 to 15 loop shifted_ferror(i) := SXT(f_error(31 downto i), 32); end loop; -- i F_ERR <= shifted_ferror(loop_gain_int); end process loop_gain0; f_error_dds <= F_ERR; --*********************************************************************************************** --**************************** Input signal selection *************************************** --*********************************************************************************************** process(clk) begin if rising_edge(clk) then if rf_select1 = '1' then mul_data_in1 <= sigma; mult_neg_data_in1 <= (not sigma) +1; else if frev_in = '1' then mul_data_in1 <= pll_gain(13 downto 0); mult_neg_data_in1 <= (not pll_gain(13 downto 0)) +1; else mult_neg_data_in1 <= pll_gain(13 downto 0); mul_data_in1 <= (not pll_gain(13 downto 0)) +1; end if; end if; if rf_select2 = '1' then mul_data_in2 <= sigma; mult_neg_data_in2 <= (not sigma) +1; else if frev_in = '1' then mul_data_in2 <= pll_gain(13 downto 0); mult_neg_data_in2 <= (not pll_gain(13 downto 0)) +1; else mult_neg_data_in2 <= pll_gain(13 downto 0); mul_data_in2 <= (not pll_gain(13 downto 0)) +1; end if; end if; end if; end process; --*********************************************************************************************** --**************************** DDS *********************************** --*********************************************************************************************** -- The DDS is locked to the frev signal a few ms before injection, which gets us the -- right NCO frequency to a relative error of about 1e-3, but its phase is sacrificed -- at injection to accomodate beams where this phase is randomly switching between -- several different values from one cycle to the next. (This happens for some MD beams, -- like MD4.) This is ugly, but I see no other way. Yet, as it happens, this makes -- adjusting the TMS really easy. -- Two-turn phase range is needed to properly sequence events for all PUs. A super-MSB -- has been grafted on the dds_ph, which is cleared for every turn-synchronous event. -- The dds_ph_del signal exists to align zero phase with an fsm0 transition. -- -- JMB clk62 <= '1'; -- This used to be a half-rate local clock qualifier dds: process(clk,rst) begin if rst = '1' then dds_ph <= (others => '0'); dds_freq <= (others => '0'); dds_ph32_reg <= '0'; dds_freq_OVR <= '0'; dds_freq_UR <= '0'; pll_init_count <= (others => '0'); pll_init <= '0'; elsif rising_edge(clk) then if cycle_start = '1' then pll_init_count <= pll_freqdelay(15 downto 0); --pll_init <= not OR_reduce(pll_freqdelay(15 downto 0)); pll_init <= '1'; else if OR_reduce(pll_init_count) = '1' and ms_pulse_reg(7) = '0' and ms_pulse_reg(6) = '1' then pll_init_count <= pll_init_count-1; if pll_init_count = CONV_STD_LOGIC_VECTOR(1,16) then pll_init <= '1'; else pll_init <= '0'; end if; else pll_init <= '0'; end if; end if; if pll_init = '1' then dds_ph <= (others => '0'); dds_freq <= pll_frequency; dds_freq_OVR <= '0'; dds_freq_UR <= '0'; elsif injection = '1' and injection_reg = '0' and clear_pll_ph = '1' then -- JMB dds_ph <= (others => '0'); -- JMB elsif ps_event_pending = '1' and ps_event_switch = '0' then -- JMB dds_ph <= '0' & dds_ph_next(31 downto 0); -- JMB elsif clk62 = '1' then dds_ph <= dds_ph_next; -- JMB if dds_freq > dds_freq_max then dds_freq_OVR <= '1'; dds_freq_UR <= '0'; elsif dds_freq < dds_freq_min then dds_freq_OVR <= '0'; dds_freq_UR <= '1'; end if; if load_dds_freq = '1' then dds_freq <= dds_freq_limit; elsif loop_ctrl = '0' then dds_freq <= dds_freq + f_error_dds; dds_freq_OVR <= '0'; dds_freq_UR <= '0'; end if; end if; end if; dds_ph_del(31 downto 23) <= dds_ph(31 downto 23); -- JMB end process dds; pll_msb <= dds_ph(31); dds_freq_limit <= dds_freq_max when dds_freq_OVR = '1' else dds_freq_min; load_dds_freq <= dds_freq_limit_en and (dds_freq_OVR or dds_freq_UR); dds_ph_next <= dds_ph + ('0' & dds_freq); -- JMB dds_of <= dds_ph(31) and not dds_ph_next(31); -- JMB -- -- Event's effects are delayed until the phase of the DDS has reached the appropriate -- channel-specific value. This combinatorial signal is -alas- not always ready within -- one clock period. It's wise to keep gate boundaries away from turn boundaries to -- avoid single-clock glitches. -- JMB over_ph <= '1' when unsigned(dds_ph_next(32 downto 23)) > unsigned(pll_phasedelay(9 downto 0)) else '0'; --*********************************************************************************************** --**************************** multiplier *********************************** --*********************************************************************************************** -- The multiplier output is forced to 0 between the injection trigger and the associated -- fsm0 state transition to avoid upsetting the filters with a huge input transient caused -- by the clearing of dds_ph. -- JMB mult_int1 <= mul_data_in1 when LO_pulse1 = '0' else mult_neg_data_in1; mult_int2 <= mul_data_in2 when LO_pulse2 = '0' else mult_neg_data_in2; mult_out1 <= mult_int1 when injection_switch = '0' else (others => '0'); mult_out2 <= mult_int2 when injection_switch = '0' else (others => '0'); pll_mixed_sigma0_out <= mult_out1; pll_mixed_sigma1_out <= mult_out2; process(clk) begin if rising_edge(clk) then filter1_in <= SXT(mult_out1, 16); filter2_in <= SXT(mult_out2, 16); if use_neighbour_pll(0) = '0' then other_plls1a <= (others => '0'); else other_plls1a <= pll_mixed_sigma0a_in; end if; if use_neighbour_pll(1) = '0' then other_plls1b <= (others => '0'); else other_plls1b <= pll_mixed_sigma0b_in; end if; if use_neighbour_pll(2) = '0' then other_plls2a <= (others => '0'); else other_plls2a <= pll_mixed_sigma1a_in; end if; if use_neighbour_pll(3) = '0' then other_plls2b <= (others => '0'); else other_plls2b <= pll_mixed_sigma1b_in; end if; end if; end process; --*********************************************************************************************** --**************************** filter *********************************** --*********************************************************************************************** -- Filter input options, only use one combine_3_pupes: if false generate n1 <= SXT(filter1_in+ SXT(other_plls1a,16) + SXT(other_plls1b,16),32); nb1 <= SXT(filter2_in+ SXT(other_plls2a,16) + SXT(other_plls2b,16),32); end generate combine_3_pupes; independent_pupes: if false generate n1 <= SXT(filter1_in,32); nb1 <= SXT(filter2_in,32); end generate independent_pupes; combine_3_pupes_registered: if true generate process (clk) begin -- process if rising_edge(clk) then n1 <= SXT(filter1_in+ SXT(other_plls1a,16) + SXT(other_plls1b,16),32); nb1 <= SXT(filter2_in+ SXT(other_plls2a,16) + SXT(other_plls2b,16),32); end if; end process; end generate combine_3_pupes_registered; process(clk, init, rst) begin if rst = '1' then n2 <= x"00000000"; n3 <= x"00000000"; n4 <= x"00000000"; n5 <= x"00000000"; n6 <= x"00000000"; s4 <= x"00000000"; s6 <= x"00000000"; elsif rising_edge(clk) then if init = '1' then n2 <= x"00000000"; n3 <= x"00000000"; n4 <= x"00000000"; n5 <= x"00000000"; n6 <= x"00000000"; s4 <= x"00000000"; s6 <= x"00000000"; elsif clk62 = '1' then n2 <= n1 + n2 - SXT(n2(31 downto 8), 32); n3 <= n2 + n3 - SXT(n3(31 downto 8), 32); s4 <= n3 - SXT(n3(31 downto 10), 24); n4 <= n3 - s4; n5 <= n4 + n5 - SXT(n5(31 downto 8), 32); s6 <= n5 - SXT(n5(31 downto 10), 32); n6 <= n5 - s6; end if; end if; end process; process(clk, init, rst) begin if rst = '1' then nb2 <= x"00000000"; nb3 <= x"00000000"; nb4 <= x"00000000"; nb5 <= x"00000000"; nb6 <= x"00000000"; sb4 <= x"00000000"; sb6 <= x"00000000"; elsif rising_edge(clk) then if init = '1' then nb2 <= x"00000000"; nb3 <= x"00000000"; nb4 <= x"00000000"; nb5 <= x"00000000"; nb6 <= x"00000000"; sb4 <= x"00000000"; sb6 <= x"00000000"; elsif clk62 = '1' then nb2 <= nb1 + nb2 - SXT(nb2(31 downto 8), 32); nb3 <= nb2 + nb3 - SXT(nb3(31 downto 8), 32); sb4 <= nb3 - SXT(nb3(31 downto 10), 32); nb4 <= nb3 - sb4; nb5 <= nb4 + nb5 - SXT(nb5(31 downto 8), 32); sb6 <= nb5 - SXT(nb5(31 downto 10), 32); nb6 <= nb5 - sb6; end if; end if; end process; filter_data_out <= n6(31 downto 0) when sel_filter = '0' else nb6(31 downto 0); f_error <= filter_data_out; --*********************************************************************************************** --**************************** INTEGRATORS *********************************** --*********************************************************************************************** process(clk,rst) begin if rst = '1' then accumulate_0 <= x"000000"; accumulate_1 <= x"000000"; accumulate_2 <= x"000000"; elsif rising_edge(clk) then if acc_reset = '1' then accumulate_0 <= x"000000"; accumulate_1 <= x"000000"; accumulate_2 <= x"000000"; elsif GATE_PULSE = '1' then accumulate_0 <= accumulate_0 + BLR_data_out_0; accumulate_1 <= accumulate_1 + BLR_data_out_1; accumulate_2 <= accumulate_2 + BLR_data_out_2; end if; end if; end process; process (clk, init,rst) begin if init = '1' or rst = '1' then state <= idle; elsif rising_edge(clk) then case state is when idle => if GATE_PULSE = '1' then state <= integrate; else state <= idle; end if; when integrate => if GATE_PULSE = '1' then state <= integrate; else state <= ready; end if; when ready => state <= reset_acc; when reset_acc => state <= idle; end case; end if; end process; acc_reset <= '1' when state = reset_acc else '0'; result_valid <= '1' when state = reset_acc else '0'; process(clk) begin if rising_edge(clk) then if state = ready then result0_tmp <= accumulate_0; result1_tmp <= accumulate_1; result2_tmp <= accumulate_2; end if; end if; end process; result_0 <= result0_tmp; result_1 <= result1_tmp; result_2 <= result2_tmp; --*********************************************************************************************** --**************************** BASELINE RESTORATION *************************** --*********************************************************************************************** BLR_data_in_0 <= SXT(sigma, 24); BLR_data_in_1 <= SXT(deltax, 24); BLR_data_in_2 <= SXT(deltay, 24); --accumulate e process(clk, init) begin if init = '1' then e0 <= (others => '0'); e1 <= (others => '0'); e2 <= (others => '0'); b0 <= (others => '0'); b1 <= (others => '0'); b2 <= (others => '0'); y0 <= (others => '0'); y1 <= (others => '0'); y2 <= (others => '0'); x0 <= (others => '0'); x1 <= (others => '0'); x2 <= (others => '0'); elsif rising_edge(clk) then x0 <= BLR_data_in_0 - b0; x1 <= BLR_data_in_1 - b1; x2 <= BLR_data_in_2 - b2; e0 <= e0+x0; e1 <= e1+x1; e2 <= e2+x2; y0 <= x0 + SXT(e0(23 downto 7), 24); y1 <= x1 + SXT(e1(23 downto 7), 24); y2 <= x2 + SXT(e2(23 downto 7), 24); if BLR_pulse = '1' then b0 <= b0 + SXT(y0(23 downto 2), 24); b1 <= b1 + SXT(y1(23 downto 2), 24); b2 <= b2 + SXT(y2(23 downto 2), 24); end if; end if; end process; -- BLR_data_out_0 <= b0; -- BLR_data_out_1 <= b1; -- BLR_data_out_2 <= b2; BLR_data_out_0 <= y0 when blr_disable = '0' else BLR_data_in_0; BLR_data_out_1 <= y1 when blr_disable = '0' else BLR_data_in_1; BLR_data_out_2 <= y2 when blr_disable = '0' else BLR_data_in_2; -- Diagnostics -- Record 256 bits of signals process (clk) begin -- process if clk'event and clk = '1' then -- rising clock edge diagnostics(63 downto 56) <= frev_in & pll_msb & phase_table_msb & phase_table_data(0) & event_delayed_switch & injection_switch & hchange_switch & LO_pulse2; diagnostics(55 downto 48) <= (hchange_switch and phase_table_msb_falling) & sel_filter & rf_select2 & rf_select1 & phase_table_data(7 downto 6) & GATE_pulse & BLR_pulse; diagnostics(47 downto 32) <= switch_state & sigma(13 downto 2); diagnostics(31 downto 26) <= hchange & injection & cal_stop & cal_start & cycle_stop & cycle_start; diagnostics(25 downto 0) <= dds_freq(31 downto 6); diagnostics(127 downto 120) <= frev_in & pll_msb & phase_table_msb & LO_pulse1 & sigma(13 downto 11) & LO_pulse2; diagnostics(115 downto 102) <= mult_out1; diagnostics(101 downto 88) <= mult_out2; diagnostics(87 downto 64) <= f_error(23 downto 0); diagnostics(191 downto 184) <= frev_in & pll_msb & phase_table_msb & LO_pulse1 & sigma(13 downto 11) & LO_pulse2; diagnostics(183) <= GATE_pulse; diagnostics(182 downto 160) <= b0(22 downto 0); diagnostics(159 downto 128) <= SXT(result0_tmp,32); diagnostics(255 downto 248) <= frev_in & pll_msb & phase_table_msb & LO_pulse1 & BLR_data_out_0(23) & BLR_data_out_0(12 downto 11)& LO_pulse2; diagnostics(247) <= BLR_pulse; diagnostics(246) <= GATE_pulse; diagnostics(245 downto 232) <= sigma; diagnostics(231 downto 218) <= deltax; diagnostics(217 downto 204) <= deltay; diagnostics(198 downto 193) <= hchange & injection & cal_stop & cal_start & cycle_stop & cycle_start; -- diagnostics(239 downto 224) <= y0(15 downto 0); -- diagnostics(223 downto 208) <= e0(15 downto 0); -- diagnostics(207 downto 192) <= x0(15 downto 0); end if; end process; end rtl;