-------------------------------------------------------------------------------- -- File Name: cdc5801.vhd -------------------------------------------------------------------------------- -- Copyright (C) 2004 Free Model Foundry; http://www.FreeModelFoundry.com/ -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License version 2 as -- published by the Free Software Foundation. -- -- MODIFICATION HISTORY: -- -- version: | author: | mod date: | changes made: -- V1.0 M.Radmanovic 04 July 25 Initial release -- -------------------------------------------------------------------------------- -- PART DESCRIPTION: -- -- Library: CLOCK -- Technology: LVTTL -- Part: CDC5801 -- -- Description: Clock Multiplier with Delay Control and Phase Alignment -- -- At the clock stop mode the value 'L' is assigned to outputs -- to represent V0, STOP -- -------------------------------------------------------------------------------- LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; USE IEEE.VITAL_timing.ALL; USE IEEE.VITAL_primitives.ALL; LIBRARY FMF; USE FMF.gen_utils.ALL; USE FMF.conversions.ALL; -------------------------------------------------------------------------------- -- ENTITY DECLARATION -------------------------------------------------------------------------------- ENTITY cdc5801 IS GENERIC ( -- tipd delays: interconnect path delays tipd_REFCLK : VitalDelayType01 := VitalZeroDelay01; tipd_DLYCTRL : VitalDelayType01 := VitalZeroDelay01; tipd_LEADLAG : VitalDelayType01 := VitalZeroDelay01; tipd_MULT1 : VitalDelayType01 := VitalZeroDelay01; tipd_MULT0 : VitalDelayType01 := VitalZeroDelay01; tipd_P2 : VitalDelayType01 := VitalZeroDelay01; tipd_P1 : VitalDelayType01 := VitalZeroDelay01; tipd_P0 : VitalDelayType01 := VitalZeroDelay01; tipd_STOPBNeg : VitalDelayType01 := VitalZeroDelay01; tipd_PWRDNBNeg : VitalDelayType01 := VitalZeroDelay01; -- tpd delays tpd_STOPBNeg_CLKOUT : VitalDelayType01 := UnitDelay01; tpd_STOPBNeg_CLKOUTB : VitalDelayType01 := UnitDelay01; tpd_PWRDNBNeg_CLKOUT : VitalDelayType01 := UnitDelay01; tpd_PWRDNBNeg_CLKOUTB : VitalDelayType01 := UnitDelay01; --tpw values: pulse width tpw_STOPBNeg_posedge : VitalDelayType := UnitDelay; tpw_STOPBNeg_negedge : VitalDelayType := UnitDelay; -- tperiod_min: minimum clock period = 1/max freq tperiod_REFCLK_posedge : VitalDelayType := UnitDelay; -- generic control parameters InstancePath : STRING := DefaultInstancePath; TimingChecksOn : BOOLEAN := DefaultTimingChecks; MsgOn : BOOLEAN := DefaultMsgOn; XOn : BOOLEAN := DefaultXon; -- For FMF SDF technology file usage TimingModel : STRING := DefaultTimingModel ); PORT ( CLKOUT : OUT std_ulogic := 'U'; CLKOUTB : OUT std_ulogic := 'U'; REFCLK : IN std_ulogic := 'U'; DLYCTRL : IN std_ulogic := 'U'; LEADLAG : IN std_ulogic := 'U'; MULT1 : IN std_ulogic := 'U'; MULT0 : IN std_ulogic := 'U'; P2 : IN std_ulogic := 'U'; P1 : IN std_ulogic := 'U'; P0 : IN std_ulogic := 'U'; STOPBNeg : IN std_ulogic := 'U'; PWRDNBNeg : IN std_ulogic := 'U' ); ATTRIBUTE VITAL_LEVEL0 of cdc5801 : ENTITY IS TRUE; END cdc5801; -------------------------------------------------------------------------------- -- ARCHITECTURE DECLARATION -------------------------------------------------------------------------------- ARCHITECTURE vhdl_behavioral of cdc5801 IS ATTRIBUTE VITAL_LEVEL0 of vhdl_behavioral : ARCHITECTURE IS TRUE; SIGNAL REFCLK_ipd : std_ulogic := 'U'; SIGNAL DLYCTRL_ipd : std_ulogic := 'U'; SIGNAL LEADLAG_ipd : std_ulogic := 'U'; SIGNAL MULT1_ipd : std_ulogic := '1'; SIGNAL MULT0_ipd : std_ulogic := '1'; SIGNAL P2_ipd : std_ulogic := '1'; SIGNAL P1_ipd : std_ulogic := '1'; SIGNAL P0_ipd : std_ulogic := 'U'; SIGNAL STOPBNeg_ipd : std_ulogic := 'U'; SIGNAL PWRDNBNeg_ipd : std_ulogic := 'U'; -- No Weak Values -- SIGNAL REFCLK_nwv : std_ulogic := 'U'; SIGNAL DLYCTRL_nwv : std_ulogic := 'U'; SIGNAL LEADLAG_nwv : std_ulogic := 'U'; SIGNAL MULT1_nwv : std_ulogic := '1'; SIGNAL MULT0_nwv : std_ulogic := '1'; SIGNAL P2_nwv : std_ulogic := '1'; SIGNAL P1_nwv : std_ulogic := '1'; SIGNAL P0_nwv : std_ulogic := 'U'; SIGNAL STOPBNeg_nwv : std_ulogic := 'U'; SIGNAL PWRDNBNeg_nwv : std_ulogic := 'U'; SIGNAL PLL_LOCK : boolean; SIGNAL MULT_OUT : std_ulogic := '0'; SIGNAL PLL_OUT : std_ulogic := '1'; SIGNAL DLY_OUT : std_ulogic := 'U'; SIGNAL C_int : std_ulogic := 'U'; SIGNAL C_zd : std_ulogic; SIGNAL COut_zd : std_ulogic; SIGNAL CNeg_zd : std_ulogic; SHARED VARIABLE C_PERIOD : TIME := 0 ns; SHARED VARIABLE PHASE_INC : TIME := 0 ps; BEGIN ---------------------------------------------------------------------------- -- Wire Delays ---------------------------------------------------------------------------- WireDelay : BLOCK BEGIN w_3 : VitalWireDelay (REFCLK_ipd, REFCLK, tipd_REFCLK); w_4 : VitalWireDelay (DLYCTRL_ipd, DLYCTRL, tipd_DLYCTRL); w_5 : VitalWireDelay (LEADLAG_ipd, LEADLAG, tipd_LEADLAG); w_6 : VitalWireDelay (MULT1_ipd, MULT1, tipd_MULT1); w_7 : VitalWireDelay (MULT0_ipd, MULT0, tipd_MULT0); w_8 : VitalWireDelay (P2_ipd, P2, tipd_P2); w_9 : VitalWireDelay (P1_ipd, P1, tipd_P1); w_10 : VitalWireDelay (P0_ipd, P0, tipd_P0); w_11 : VitalWireDelay (STOPBNeg_ipd, STOPBNeg, tipd_STOPBNeg); w_12 : VitalWireDelay (PWRDNBNeg_ipd, PWRDNBNeg, tipd_PWRDNBNeg); END BLOCK; REFCLK_nwv <= To_UX01 (s => REFCLK_ipd); DLYCTRL_nwv <= To_UX01 (s => DLYCTRL_ipd); LEADLAG_nwv <= To_UX01 (s => LEADLAG_ipd); MULT1_nwv <= To_UX01 (s => MULT1_ipd); MULT0_nwv <= To_UX01 (s => MULT0_ipd); P2_nwv <= To_UX01 (s => P2_ipd); P1_nwv <= To_UX01 (s => P1_ipd); P0_nwv <= To_UX01 (s => P0_ipd); STOPBNeg_nwv <= To_UX01 (s => STOPBNeg_ipd); PWRDNBNeg_nwv <= To_UX01 (s => PWRDNBNeg_ipd); ---------------------------------------------------------------------------- -- Concurrent procedure calls ---------------------------------------------------------------------------- COut_zd <= '0' WHEN PWRDNBNeg_nwv = '0' ELSE 'L' WHEN STOPBNeg_nwv = '0' ELSE 'Z' WHEN (P0_nwv = '1' AND P1_nwv = '0' AND P2_nwv = '0') ELSE 'H' WHEN (P0_nwv = '1' AND P1_nwv = '0' AND P2_nwv = '1') ELSE P2_nwv WHEN (P0_nwv = '1' AND P1_nwv = '1') ELSE C_zd; CNeg_zd <= '0' WHEN PWRDNBNeg_nwv = '0' ELSE 'L' WHEN STOPBNeg_nwv = '0' ELSE 'Z' WHEN (P0_nwv = '1' AND P1_nwv = '0' AND P2_nwv = '0') ELSE 'H' WHEN (P0_nwv = '1' AND P1_nwv = '0' AND P2_nwv = '1') ELSE not(P2_nwv) WHEN (P0_nwv = '1' AND P1_nwv = '1') ELSE not(C_zd); ---------------------------------------------------------------------------- -- PLL Process ---------------------------------------------------------------------------- PLL : PROCESS (REFCLK_nwv, MULT_OUT, PLL_OUT, STOPBNeg_nwv) VARIABLE clk_period : time := 0 ns; VARIABLE prev_clk : time := 0 ns; VARIABLE mult_period : time := 0 ns; VARIABLE prev_mult : time := 0 ns; VARIABLE half_per : time := 5 ns; VARIABLE counter : natural range 0 to 4; -- Timing Check Variables VARIABLE Pviol_STOPBNeg : X01 := '0'; VARIABLE PD_STOPBNeg : VitalPeriodDataType := VitalPeriodDataInit; VARIABLE Pviol_REFCLK : X01 := '0'; VARIABLE PD_REFCLK : VitalPeriodDataType := VitalPeriodDataInit; VARIABLE Violation : X01 := '0'; BEGIN ------------------------------------------------------------------------ -- Timing Check Section ------------------------------------------------------------------------ IF (TimingChecksOn) THEN -- PulseWidth Check for CENeg VitalPeriodPulseCheck ( TestSignal => STOPBNeg_ipd, TestSignalName => "STOBNeg", PulseWidthHigh => tpw_STOPBNeg_posedge, PulseWidthLow => tpw_STOPBNeg_negedge, CheckEnabled => TRUE, HeaderMsg => InstancePath & "PartID", PeriodData => PD_STOPBNeg, Violation => Pviol_STOPBNeg ); VitalPeriodPulseCheck ( TestSignal => REFCLK_ipd, TestSignalName => "REFCLK", Period => tperiod_REFCLK_posedge, CheckEnabled => TRUE, HeaderMsg => InstancePath & "PartID", PeriodData => PD_REFCLK, XOn => XOn, MsgOn => MsgOn, Violation => Pviol_REFCLK ); Violation := Pviol_REFCLK OR Pviol_STOPBNeg; ASSERT Violation = '0' REPORT InstancePath & "partID" & ": simulation may be" & " inaccurate due to timing violations" SEVERITY WARNING; END IF; ------------------------------------------------------------------------ -- Functionality Section ------------------------------------------------------------------------ IF rising_edge(REFCLK_nwv) THEN clk_period := NOW - prev_clk; prev_clk := NOW; END IF; IF rising_edge(MULT_OUT) THEN mult_period := NOW - prev_mult; prev_mult := NOW; IF counter = 4 THEN IF mult_period > clk_period THEN half_per := half_per - 60 ps; PLL_LOCK <= false; ELSIF mult_period < clk_period THEN half_per := half_per + 59 ps; PLL_LOCK <= false; ELSE PLL_LOCK <= true; END IF; counter := 0; ELSE counter := counter + 1; END IF; END IF; IF rising_edge(PLL_OUT) THEN PLL_OUT <= '0' AFTER half_per, '1' AFTER 2*half_per; ELSIF NOW = 0 ns THEN PLL_OUT <= '0' AFTER half_per, '1' AFTER 2*half_per; END IF; END PROCESS PLL; ---------------------------------------------------------------------------- -- Multiplier Process ---------------------------------------------------------------------------- -- The "Multiplier" actually divides the PLL_OUT signal MULT : PROCESS (PLL_OUT, MULT0_nwv, MULT1_nwv) VARIABLE mult_in : natural range 0 to 3; VARIABLE multvec : std_logic_vector(1 downto 0); VARIABLE mult_cnt : natural range 0 to 8; BEGIN multvec := (MULT0_nwv, MULT1_nwv); mult_in := to_nat(multvec); IF rising_edge(PLL_OUT) THEN CASE mult_in IS WHEN 0 => -- divide by 4 IF mult_cnt > 0 THEN MULT_OUT <= not MULT_OUT; mult_cnt := 0; ELSE mult_cnt := mult_cnt + 1; END IF; WHEN 1 => -- divide by 2 MULT_OUT <= not MULT_OUT; WHEN 2 => -- divide by 16 IF mult_cnt > 6 THEN MULT_OUT <= not MULT_OUT; mult_cnt := 0; ELSE mult_cnt := mult_cnt + 1; END IF; WHEN 3 => -- divide by 8 IF mult_cnt > 2 THEN MULT_OUT <= not MULT_OUT; mult_cnt := 0; ELSE mult_cnt := mult_cnt + 1; END IF; END CASE; ELSIF NOW = 0 ns THEN MULT_OUT <= not MULT_OUT; END IF; END PROCESS MULT; ---------------------------------------------------------------------------- -- Delay Process ---------------------------------------------------------------------------- -- The Delay process phase aligns the output to DLYCTRL DELAY : PROCESS (PLL_OUT, DLYCTRL_ipd, LEADLAG_ipd) VARIABLE phase_dly : time := 0 ns; VARIABLE phase_cnt : natural := 0; BEGIN IF PLL_LOCK THEN IF rising_edge(DLYCTRL_ipd) THEN IF phase_cnt < 31 THEN IF LEADLAG_ipd = '0' OR LEADLAG_ipd = 'L' THEN phase_dly := phase_dly + PHASE_INC; ELSE IF phase_dly > PHASE_INC THEN phase_dly := phase_dly - PHASE_INC; ELSE phase_dly := C_PERIOD - PHASE_INC; -- wrap END IF; END IF; phase_cnt := phase_cnt +1; ELSE phase_cnt := 0; END IF; END IF; ELSE phase_dly := 0 ps; END IF; DLY_OUT <= TRANSPORT PLL_OUT AFTER phase_dly; END PROCESS DELAY; ---------------------------------------------------------------------------- -- Divider Process ---------------------------------------------------------------------------- -- The Divider process divides the frequency of the phase aligner output, -- gates the result with STOPB, and drives the outputs. DIV : PROCESS (DLY_OUT, P1_nwv, P2_nwv, STOPBNeg_nwv, C_int) VARIABLE div_in : natural range 0 to 3; VARIABLE divvec : std_logic_vector(1 downto 0) := "00"; VARIABLE div_cnt : natural range 0 to 8; VARIABLE toggle_cnt : natural range 0 to 2; VARIABLE prev_lock : boolean := false; VARIABLE prev_c : time := 0 ns; BEGIN divvec := (P1_nwv, P2_nwv); div_in := to_nat(divvec); IF P1_nwv'EVENT OR P2_nwv'EVENT OR PLL_LOCK = false THEN prev_lock := false; END IF; IF rising_edge(C_int) THEN C_PERIOD := NOW - prev_c; prev_c := NOW; IF PLL_LOCK /= prev_lock THEN IF PLL_LOCK THEN IF toggle_cnt > 1 THEN CASE div_in IS WHEN 0 => -- special mode WHEN 1 => -- divide by 3072 PHASE_INC := C_PERIOD/3072; WHEN 2 => -- divide by 1536 PHASE_INC := C_PERIOD/1536; WHEN 3 => -- divide by 768 PHASE_INC := C_PERIOD/768; END CASE; toggle_cnt := 0; prev_lock := true; ELSE toggle_cnt := toggle_cnt +1; END IF; ELSE prev_lock := false; END IF; END IF; END IF; IF rising_edge(DLY_OUT) THEN CASE div_in IS WHEN 0 => -- special mode ASSERT (P0_nwv = '1') REPORT "cdc5801 model does not support this mode" SEVERITY error; WHEN 1 => -- divide by 8 IF div_cnt > 2 THEN C_zd <= not C_zd; div_cnt := 0; ELSE div_cnt := div_cnt + 1; END IF; WHEN 2 => -- divide by 4 IF div_cnt > 0 THEN C_zd <= not C_zd; div_cnt := 0; ELSE div_cnt := div_cnt + 1; END IF; WHEN 3 => -- divide by 2 C_zd <= not C_zd; END CASE; ELSIF NOW = 0 ns THEN C_zd <= DLY_OUT; END IF; C_int <= C_zd; END PROCESS DIV; ------------------------------------------------------------------------ -- Path Delay Section ------------------------------------------------------------------------ C_OUT: PROCESS(COut_zd) VARIABLE C_GlitchData : VitalGlitchDataType; BEGIN VitalPathDelay01 ( OutSignal => CLKOUT, OutSignalName => "CLKOUT", OutTemp => COut_zd, GlitchData => C_GlitchData, XOn => XOn, MsgOn => MsgOn, Paths => ( 0 => (InputChangeTime => DLY_OUT'LAST_EVENT, PathDelay => VitalZeroDelay01, PathCondition => TRUE), 1 => (InputChangeTime => STOPBNeg_ipd'LAST_EVENT, PathDelay => tpd_STOPBNeg_CLKOUT, PathCondition => STOPBNeg_nwv = '1'), 2 => (InputChangeTime => STOPBNeg_ipd'LAST_EVENT, PathDelay => tpd_STOPBNeg_CLKOUTB, PathCondition => STOPBNeg_nwv = '0'), 3 => (InputChangeTime => PWRDNBNeg_ipd'LAST_EVENT, PathDelay => tpd_PWRDNBNeg_CLKOUT, PathCondition => PWRDNBNeg_nwv = '1'), 4 => (InputChangeTime => PWRDNBNeg_ipd'LAST_EVENT, PathDelay => tpd_PWRDNBNeg_CLKOUTB, PathCondition => PWRDNBNeg_nwv = '0') ) ); END PROCESS C_OUT; CNeg_OUT: PROCESS(CNeg_zd) VARIABLE CNeg_GlitchData : VitalGlitchDataType; BEGIN VitalPathDelay01 ( OutSignal => CLKOUTB, OutSignalName => "CLKOUTB", OutTemp => CNeg_zd, GlitchData => CNeg_GlitchData, XOn => XOn, MsgOn => MsgOn, Paths => ( 0 => (InputChangeTime => DLY_OUT'LAST_EVENT, PathDelay => VitalZeroDelay01, PathCondition => TRUE), 1 => (InputChangeTime => STOPBNeg_ipd'LAST_EVENT, PathDelay => tpd_STOPBNeg_CLKOUT, PathCondition => STOPBNeg_nwv = '1'), 2 => (InputChangeTime => STOPBNeg_ipd'LAST_EVENT, PathDelay => tpd_STOPBNeg_CLKOUTB, PathCondition => STOPBNeg_nwv = '0'), 3 => (InputChangeTime => PWRDNBNeg_ipd'LAST_EVENT, PathDelay => tpd_PWRDNBNeg_CLKOUT, PathCondition => PWRDNBNeg_nwv = '1'), 4 => (InputChangeTime => PWRDNBNeg_ipd'LAST_EVENT, PathDelay => tpd_PWRDNBNeg_CLKOUTB, PathCondition => PWRDNBNeg_nwv = '0') ) ); END PROCESS CNeg_OUT; END vhdl_behavioral;