--
-- 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;