-------------------------------------------------------------------------------- --  File Name: max5236.vhd -------------------------------------------------------------------------------- --  Copyright (C) 2005 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 Dj.Tanasijevic 05 March 18 Initial release -- --  This model must be compiled without VITAL compliance checking -------------------------------------------------------------------------------- --  PART DESCRIPTION: -- --  Library: CONVERTER_VHDL --  Technology: CMOS --  Part: MAX5236/MAX5237 --  Description: Single-Supply 3V/5V, Voltage-Output, Dual, -- Precision 10-Bit DACs -------------------------------------------------------------------------------- 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 max5236 IS GENERIC ( -- tipd delays: interconnect path delays tipd_CSNeg : VitalDelayType01 := VitalZeroDelay01; tipd_SCLK : VitalDelayType01 := VitalZeroDelay01; tipd_DIN : VitalDelayType01 := VitalZeroDelay01; tipd_LDACNeg : VitalDelayType01 := VitalZeroDelay01; -- tpd delays -- tsetup values: setup times tsetup_CSNeg_SCLK : VitalDelayType := UnitDelay; tsetup_DIN_SCLK : VitalDelayType := UnitDelay; -- thold values: hold times thold_CSNeg_SCLK : VitalDelayType := UnitDelay; thold_DIN_SCLK : VitalDelayType := UnitDelay; thold_SCLK_CSNeg : VitalDelayType := UnitDelay; thold_LDACNeg_CSNeg : VitalDelayType := UnitDelay; -- tpw values: pulse widths tpw_SCLK_posedge : VitalDelayType := UnitDelay; tpw_SCLK_negedge : VitalDelayType := UnitDelay; tpw_CSNeg_posedge : VitalDelayType := UnitDelay; tpw_LDACNeg_negedge : VitalDelayType := UnitDelay; tperiod_SCLK : VitalDelayType := UnitDelay; -- analog generics: values of Vref inputs In Volts Vdd : natural RANGE 3 TO 5; --MAX5236 or MAX5237 -- 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 ( VrefA : IN real := 0.0; VrefB : IN real := 0.0; OUTA : OUT real := 0.0; OUTB : OUT real := 0.0; SCLK : IN std_ulogic := 'U'; CSNeg : IN std_ulogic := 'U'; DIN : IN std_ulogic := 'U'; LDACNeg : IN std_ulogic := 'U' ); ATTRIBUTE VITAL_LEVEL0 of max5236 : ENTITY IS TRUE; END max5236; -------------------------------------------------------------------------------- -- ARCHITECTURE DECLARATION -------------------------------------------------------------------------------- ARCHITECTURE vhdl_behavioral of max5236 IS ATTRIBUTE VITAL_LEVEL0 of vhdl_behavioral : ARCHITECTURE IS TRUE; CONSTANT partID : STRING := "max5236"; CONSTANT resolution : INTEGER := 10; SUBTYPE dacval_type IS NATURAL RANGE 0 TO (2**resolution-1); SIGNAL SCLK_ipd : std_ulogic := 'U'; SIGNAL CSNeg_ipd : std_ulogic := 'U'; SIGNAL DIN_ipd : std_ulogic := 'U'; SIGNAL LDACNeg_ipd : std_ulogic := 'U'; SIGNAL UPDATEA : std_ulogic := '0'; SIGNAL UPDATEB : std_ulogic := '0'; SIGNAL UPDATE_OUTA : std_ulogic := '0'; SIGNAL UPDATE_OUTB : std_ulogic := '0'; SIGNAL dacvalA : dacval_type; SIGNAL dacvalB : dacval_type; SIGNAL settlingA : std_ulogic := '0'; SIGNAL settlingB : std_ulogic := '0'; SHARED VARIABLE PowerDownA : BOOLEAN := FALSE; SHARED VARIABLE PowerDownB : BOOLEAN := FALSE; SHARED VARIABLE FullPowerDown : BOOLEAN := FALSE; SHARED VARIABLE PDA : BOOLEAN := FALSE; SHARED VARIABLE PDB : BOOLEAN := FALSE; SHARED VARIABLE FPD : BOOLEAN := FALSE; SHARED VARIABLE stepA : REAL := 0.0; SHARED VARIABLE stepB : REAL := 0.0; SHARED VARIABLE EndValueA : REAL := 0.0; SHARED VARIABLE EndValueB : REAL := 0.0; SHARED VARIABLE settling_end_time_A : TIME := 60 us; SHARED VARIABLE settling_end_time_B : TIME := 60 us; BEGIN ---------------------------------------------------------------------------- -- Wire Delays ---------------------------------------------------------------------------- WireDelay : BLOCK BEGIN w_1 : VitalWireDelay (SCLK_ipd, SCLK, tipd_SCLK); w_2 : VitalWireDelay (CSNeg_ipd, CSNeg, tipd_CSNeg); w_3 : VitalWireDelay (DIN_ipd, DIN, tipd_DIN); w_4 : VitalWireDelay (LDACNeg_ipd, LDACNeg, tipd_LDACNeg); END BLOCK; Behavior : BLOCK SIGNAL OUTA_zd : real := 0.0; SIGNAL OUTB_zd : real := 0.0; BEGIN ---------------------------------------------------------------------------- -- Ref Voltages Control Process ---------------------------------------------------------------------------- Vref_ctrl : PROCESS (VrefA, VrefB) VARIABLE Vref_max : real; BEGIN IF Vdd = 3 THEN Vref_max := 1.50; ELSE Vref_max := 2.60; END IF; ASSERT (VrefA > 0.25 AND VrefA < Vref_max) REPORT InstancePath & partID & ": simulation may be" & " inaccurate due to VrefA range exceeding violations" SEVERITY Warning; ASSERT (VrefB > 0.25 AND VrefB < Vref_max) REPORT InstancePath & partID & ": simulation may be" & " inaccurate due to VrefB range exceeding violations" SEVERITY Warning; END PROCESS Vref_ctrl; ---------------------------------------------------------------------------- -- Behavior Process ---------------------------------------------------------------------------- digital : PROCESS (SCLK_ipd, CSNeg_ipd, LDACNeg_ipd) -- Timing Check Variables VARIABLE Tviol_CSNeg_SCLK : X01 := '0'; VARIABLE TD_CSNeg_SCLK : VitalTimingDataType; VARIABLE Tviol_DIN_SCLK : X01 := '0'; VARIABLE TD_DIN_SCLK : VitalTimingDataType; VARIABLE Tviol_SCLK_CSNeg : X01 := '0'; VARIABLE TD_SCLK_CSNeg : VitalTimingDataType; VARIABLE Tviol_LDACNeg_CSNeg : X01 := '0'; VARIABLE TD_LDACNeg_CSNeg : VitalTimingDataType; VARIABLE PD_SCLK : VitalPeriodDataType := VitalPeriodDataInit; VARIABLE Pviol_SCLK : X01 := '0'; VARIABLE PD_CSNeg : VitalPeriodDataType := VitalPeriodDataInit; VARIABLE Pviol_CSNeg : X01 := '0'; VARIABLE PD_LDACNeg : VitalPeriodDataType := VitalPeriodDataInit; VARIABLE Pviol_LDACNeg : X01 := '0'; VARIABLE Violation : X01 := '0'; SUBTYPE dacreg_type IS std_logic_vector(resolution-1 DOWNTO 0); VARIABLE bit_cntr : INTEGER; VARIABLE shiftreg : std_logic_vector(15 DOWNTO 0); VARIABLE inregA : dacreg_type; VARIABLE inregB : dacreg_type; VARIABLE dacregA : dacreg_type; VARIABLE dacregB : dacreg_type; VARIABLE SCLK_nwv : X01; VARIABLE CSNeg_nwv : X01; VARIABLE DIN_nwv : X01; VARIABLE LDACNeg_nwv : X01; -- Output Glitch Detection Variables BEGIN SCLK_nwv := to_X01(SCLK_ipd); CSNeg_nwv := to_X01(CSNeg_ipd); DIN_nwv := to_X01(DIN_ipd); LDACNeg_nwv := to_X01(LDACNeg_ipd); ------------------------------------------------------------------------ -- Timing Check Section ------------------------------------------------------------------------ IF (TimingChecksOn) THEN VitalSetupHoldCheck ( TestSignal => CSNeg_ipd, TestSignalName => "CSNeg", RefSignal => SCLK_ipd, RefSignalName => "SCLK", SetupLow => tsetup_CSNeg_SCLK, HoldLow => thold_CSNeg_SCLK, CheckEnabled => true, RefTransition => '/', HeaderMsg => InstancePath & partID, TimingData => TD_CSNeg_SCLK, XOn => XOn, MsgOn => MsgOn, Violation => Tviol_CSNeg_SCLK ); VitalSetupHoldCheck ( TestSignal => DIN_ipd, TestSignalName => "DIN", RefSignal => SCLK_ipd, RefSignalName => "SCLK", SetupHigh => tsetup_DIN_SCLK, SetupLow => tsetup_DIN_SCLK, HoldHigh => thold_DIN_SCLK, HoldLow => thold_DIN_SCLK, CheckEnabled => true, RefTransition => '/', HeaderMsg => InstancePath & partID, TimingData => TD_DIN_SCLK, XOn => XOn, MsgOn => MsgOn, Violation => Tviol_DIN_SCLK ); VitalSetupHoldCheck ( TestSignal => SCLK_ipd, TestSignalName => "SCLK", RefSignal => CSNeg_ipd, RefSignalName => "CSNeg", HoldLow => thold_SCLK_CSNeg, CheckEnabled => true, RefTransition => '/', HeaderMsg => InstancePath & partID, TimingData => TD_SCLK_CSNeg, XOn => XOn, MsgOn => MsgOn, Violation => Tviol_SCLK_CSNeg ); VitalSetupHoldCheck ( TestSignal => LDACNeg_ipd, TestSignalName => "LDACNeg", RefSignal => CSNeg_ipd, RefSignalName => "CSNeg", HoldLow => thold_LDACNeg_CSNeg, CheckEnabled => true, RefTransition => '/', HeaderMsg => InstancePath & partID, TimingData => TD_LDACNeg_CSNeg, XOn => XOn, MsgOn => MsgOn, Violation => Tviol_LDACNeg_CSNeg ); VitalPeriodPulseCheck ( TestSignal => SCLK_ipd, TestSignalName => "SCLK_ipd", PulseWidthHigh => tpw_SCLK_posedge, PulseWidthLow => tpw_SCLK_negedge, Period => tperiod_SCLK, HeaderMsg => InstancePath & partID, CheckEnabled => TRUE, PeriodData => PD_SCLK, XOn => XOn, MsgOn => MsgOn, Violation => Pviol_SCLK ); VitalPeriodPulseCheck ( TestSignal => CSNeg_ipd, TestSignalName => "CSNeg", PulseWidthHigh => tpw_CSNeg_posedge, HeaderMsg => InstancePath & partID, CheckEnabled => TRUE, PeriodData => PD_CSNeg, XOn => XOn, MsgOn => MsgOn, Violation => Pviol_CSNeg ); VitalPeriodPulseCheck ( TestSignal => LDACNeg_ipd, TestSignalName => "LDACNeg", PulseWidthLow => tpw_LDACNeg_negedge, HeaderMsg => InstancePath & partID, CheckEnabled => TRUE, PeriodData => PD_LDACNeg, XOn => XOn, MsgOn => MsgOn, Violation => Pviol_LDACNeg ); Violation := Tviol_CSNeg_SCLK OR Tviol_DIN_SCLK OR Tviol_SCLK_CSNeg OR Tviol_LDACNeg_CSNeg OR Pviol_SCLK OR Pviol_CSNeg OR Pviol_LDACNeg; ASSERT Violation = '0' REPORT InstancePath & partID & ": simulation may be" & " inaccurate due to timing violations" SEVERITY Warning; END IF; ------------------------------------------------------------------------ -- Functionality Section ------------------------------------------------------------------------ IF falling_edge(CSNeg_ipd) THEN bit_cntr := 16; END IF; IF CSNeg_nwv = '0' AND rising_edge(SCLK_ipd) THEN IF bit_cntr > -1 THEN bit_cntr := bit_cntr -1; END IF; IF bit_cntr > -1 THEN shiftreg(bit_cntr) := DIN_nwv; END IF; END IF; IF rising_edge(CSNeg_ipd) AND bit_cntr = 0 AND shiftreg(2 downto 0) = "000" THEN CASE shiftreg(15 downto 13) IS WHEN "001" => inregA := shiftreg(12 downto 3); WHEN "010" => inregA := shiftreg(12 downto 3); dacregA := inregA; dacregB := inregB; dacvalA <= to_nat(dacregA); dacvalB <= to_nat(dacregB); UPDATEA <= not(UPDATEA); UPDATEB <= not(UPDATEB); PowerDownA := FALSE; PowerDownB := FALSE; FullPowerDown := FALSE; WHEN "011" => inregA := shiftreg(12 downto 3); inregB := shiftreg(12 downto 3); dacregA := shiftreg(12 downto 3); dacregB := shiftreg(12 downto 3); dacvalA <= to_nat(dacregA); dacvalB <= to_nat(dacregB); UPDATEA <= not(UPDATEA); UPDATEB <= not(UPDATEB); PowerDownA := FALSE; PowerDownB := FALSE; FullPowerDown := FALSE; WHEN "100" => dacregA := inregA; dacregB := inregB; dacvalA <= to_nat(dacregA); dacvalB <= to_nat(dacregB); UPDATEA <= not(UPDATEA); UPDATEB <= not(UPDATEB); PowerDownA := FALSE; PowerDownB := FALSE; FullPowerDown := FALSE; WHEN "101" => inregB := shiftreg(12 downto 3); WHEN "110" => inregB := shiftreg(12 downto 3); dacregA := inregA; dacregB := inregB; dacvalA <= to_nat(dacregA); dacvalB <= to_nat(dacregB); UPDATEA <= not(UPDATEA); UPDATEB <= not(UPDATEB); PowerDownB := FALSE; PowerDownA := FALSE; FullPowerDown := FALSE; WHEN "111" => PowerDownA := TRUE; PowerDownB := TRUE; UPDATEA <= not(UPDATEA); UPDATEB <= not(UPDATEB); WHEN "000" => CASE shiftreg(12 downto 10) IS WHEN "001" => dacregA := inregA; dacvalA <= to_nat(dacregA); UPDATEA <= not(UPDATEA); PowerDownA := FALSE; FullPowerDown := FALSE; WHEN "011" => PowerDownA := TRUE; PowerDownB := TRUE; FullPowerDown := TRUE; UPDATEA <= not(UPDATEA); UPDATEB <= not(UPDATEB); WHEN "101" => dacregB := inregB; dacvalB <= to_nat(dacregB); UPDATEB <= not(UPDATEB); PowerDownB := FALSE; FullPowerDown := FALSE; WHEN "110" => PowerDownA := TRUE; UPDATEA <= not(UPDATEA); WHEN "111" => PowerDownB := TRUE; UPDATEB <= not(UPDATEB); WHEN OTHERS => null; END CASE; WHEN OTHERS => null; END CASE; END IF; IF LDACNeg_nwv = '0' THEN dacregA := inregA; dacregB := inregB; dacvalA <= to_nat(dacregA); dacvalB <= to_nat(dacregB); UPDATEA <= not(UPDATEA); UPDATEB <= not(UPDATEB); PowerDownA := FALSE; PowerDownB := FALSE; FullPowerDown := FALSE; END IF; END PROCESS digital; dacA : PROCESS (UPDATEA) VARIABLE StartValueA : real; VARIABLE tsettle : time; BEGIN IF (FPD) THEN IF Vdd = 3 THEN tsettle := 60 us; ELSE tsettle := 70 us; END IF; ELSIF (PDA) THEN IF Vdd = 3 THEN tsettle := 50 us; ELSE tsettle := 60 us; END IF; ELSE tsettle := 10 us; END IF; IF (NOW + tsettle) < settling_end_time_A THEN tsettle := settling_end_time_A - NOW; ELSE settling_end_time_A := NOW + tsettle; END IF; FPD := FullPowerDown; PDA := PowerDownA; IF (FullPowerDown or PowerDownA) THEN EndValueA := 0.0; settling_end_time_A := NOW; settlingA <= '1', '0' AFTER 1 ns; ELSE StartValueA := OUTA_zd; EndValueA :=(REAL(dacvalA) * VrefA / REAL(2**resolution)) * 1.6384; stepA := (EndValueA - StartValueA) / REAL(tsettle / 10 ns); settlingA <= '1', '0' AFTER tsettle; END IF; END PROCESS dacA; dacB : PROCESS (UPDATEB) VARIABLE StartValueB : real; VARIABLE tsettle : time; BEGIN IF (FPD) THEN IF Vdd = 3 THEN tsettle := 60 us; ELSE tsettle := 70 us; END IF; ELSIF (PDB) THEN IF Vdd = 3 THEN tsettle := 50 us; ELSE tsettle := 60 us; END IF; ELSE tsettle := 10 us; END IF; IF (NOW + tsettle) < settling_end_time_A THEN tsettle := settling_end_time_A - NOW; ELSE settling_end_time_A := NOW + tsettle; END IF; FPD := FullPowerDown; PDB := PowerDownB; IF (FullPowerDown or PowerDownB) THEN EndValueB := 0.0; settling_end_time_B := NOW; settlingB <= '1', '0' AFTER 1 ns; ELSE StartValueB := OUTB_zd; EndValueB :=(REAL(dacvalB) * VrefB / REAL(2**resolution)) * 1.6384; stepB := (EndValueB - StartValueB) / REAL(tsettle / 10 ns); settlingB <= '1', '0' AFTER tsettle; END IF; END PROCESS dacB; out_A : PROCESS (UPDATE_OUTA, settlingA) BEGIN IF settlingA = '0' THEN OUTA_zd <= EndValueA; ELSE UPDATE_OUTA <= not(UPDATE_OUTA) AFTER 10 ns; IF UPDATE_OUTA'event THEN OUTA_zd <= OUTA_zd + stepA; END IF; END IF; END PROCESS out_A; out_B : PROCESS (UPDATE_OUTB, settlingB) BEGIN IF settlingB = '0' THEN OUTB_zd <= EndValueB; ELSE UPDATE_OUTB <= not(UPDATE_OUTB) AFTER 10 ns; IF UPDATE_OUTB'event THEN OUTB_zd <= OUTB_zd + stepB; END IF; END IF; END PROCESS out_B; OUTA <= OUTA_zd; OUTB <= OUTB_zd; END BLOCK; END vhdl_behavioral;