-- -- phase_shifter.vhd -- -- implements interface between w5300_modul.vhd -- and clock_generator_variable_PS_struct.vhd -- library ieee; use ieee.std_logic_1164.all; use IEEE.NUMERIC_STD.all; library FACT_FAD_lib; use FACT_FAD_lib.fad_definitions.all; ENTITY phase_shifter IS PORT( CLK : IN std_logic; rst : out std_logic := '0'; --asynch in of DCM -- interface to: clock_generator_variable_PS_struct.vhd PSCLK : OUT std_logic; PSEN : OUT std_logic := '0'; PSINCDEC : OUT std_logic := '1'; -- default is 'incrementing' PSDONE : IN std_logic; -- will pulse once, if phase shifting was done. LOCKED : IN std_logic; -- when is this going high? -- interface to: w5300_modul.vhd shift_phase : IN std_logic; direction : IN std_logic; -- corresponds to 'PSINCDEC' reset_DCM : in std_logic; -- asynch in: orders us, to reset the DCM -- status: shifting : OUT std_logic := '0'; ready : OUT std_logic := '0'; locked_status_o : OUT std_logic; ready_status_o : OUT std_logic; offset : OUT std_logic_vector (7 DOWNTO 0) := (OTHERS => '0') ); END phase_shifter; -- usage: -- w5300_modul will set 'direction' to desired direction and pulse 'shift_phase' once -- to initiate a phase shifting process. -- while phase shifting, 'shifting' will show '1' and further pulses will be discarded. -- 'offset' shows the number of phase_shift steps that have been performed. -- ready is high, when DCM is LOCKED and not phase_shifting. -- DCM_status is a copy, of the STATUS input. -- DCM_locked is a copy of LOCKED -- -- how it works internally: -- PSCLK is connected to clk, always. -- -- main FSM goes from init to ready, when LOCKED is high. -- main FSM goes from ready to shifting, when shift_phase goes high. -- when in shifting: -- PSINCDEC is set to 'direction' -- PSEN is set high -- shifting is set high -- next state waiting-for-done is entered -- -- when in waiting-for-done: -- PSEN is set low -- if PSDONE is found to be high. -- shifting is set low and state ready is entered. -- -- whenever LOCKED goes low FSM enters 'init' state -- when in init state: -- 'ready' is set low architecture first_behave of phase_shifter is constant OFFS_MIN : integer := -51; constant OFFS_MAX : integer := 51; type states is (INIT, READY_STATE, PRE_SHIFTING_STATE, SHIFTING_STATE, WAITINGFORDONE, RESET_STATE); signal state : states := INIT; signal local_direction : std_logic; signal offset_int : integer range OFFS_MIN to OFFS_MAX := 0; signal lower_limit_reached : std_logic := '0'; signal upper_limit_reached : std_logic := '0'; signal reset_dcm_sr : std_logic_vector(1 downto 0) := "00"; signal shift_phase_sr : std_logic_vector(1 downto 0) := "00"; signal ready_int : std_logic := '0'; begin -- concurrent statements: ready <= ready_int; PSCLK <= CLK; offset <= std_logic_vector(to_signed(offset_int,8)); locked_status_o <= LOCKED; ready_status_o <= ready_int; -- MAIN FSM FSM: process(CLK) begin if rising_edge(CLK) then reset_dcm_sr <= reset_dcm_sr(1) & reset_DCM; --synch in shift_phase_sr <= shift_phase_sr(1) & shift_phase; --synch in case state is -- INIT state: here the FSM is idling, when LOCKED is not HIGH. when INIT => rst <= '0'; ready_int <= '0'; shifting <= '0'; PSEN <= '0'; offset_int <= 0; if (LOCKED = '1') then state <= READY_STATE; else state <= INIT; end if; -- RESET state: when ordered to do so: DCM is reseted and FSM send back to INIT. when RESET_STATE => rst <= '1'; ready_int <= '0'; shifting <= '0'; PSEN <= '0'; state <= INIT; -- READY_STATE state: here FSM is waiting for the 'shift_phase' to go high, or -- if reset_DCM goes high, we will reset the DCM and go back to init. when READY_STATE => ready_int <= '1'; shifting <= '0'; PSEN <= '0'; lower_limit_reached <='0'; upper_limit_reached <='0'; if (offset_int = OFFS_MIN) then lower_limit_reached <= '1'; elsif (offset_int = OFFS_MAX) then upper_limit_reached <= '1'; end if; if (shift_phase_sr = "01") then local_direction <= direction; -- direction is sampled, once 'shift_phase' goes high state <= PRE_SHIFTING_STATE; else state <= READY_STATE; end if; if (reset_dcm_sr = "01") then state <= RESET_STATE; end if; -- checks if possible to shift in asked direction. If not ... back to READY. when PRE_SHIFTING_STATE => ready_int <= '0'; if (local_direction = '1' and upper_limit_reached = '1') or (local_direction = '0' and lower_limit_reached = '1') then state <= READY_STATE; else state <= SHIFTING_STATE; end if; -- SHIFTING_STATE state: PSENC is set HIGH here and set low in the next state. when SHIFTING_STATE => ready_int <= '0'; shifting <= '1'; PSEN <= '1'; PSINCDEC <= local_direction; -- this is the value of 'direction', when 'shift_phase' went up. state <= WAITINGFORDONE; -- WAITINGFORDONE state: PSENC is set LOW, ensuring that is was high only one clock cycle. when WAITINGFORDONE => ready_int <= '0'; shifting <= '1'; PSEN <= '0'; if (PSDONE = '1') then state <= READY_STATE; if (local_direction = '1') then offset_int <= offset_int + 1; else offset_int <= offset_int - 1; end if; else state <= WAITINGFORDONE; end if; -- does this work???? when others => state <= RESET_STATE; end case; end if; end process; end first_behave;