-------------------------------------------------------------------------------- -- File Name: max7310.vhd -------------------------------------------------------------------------------- -- Copyright (C) 2003 Free Model Foundry; http://eda.org/fmf/ -- -- 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 03 Sep 03 Initial release -- -------------------------------------------------------------------------------- -- PART DESCRIPTION: -- -- Library: IF -- Technology: -- Part: MAX7310 -- -- Description: 2-Wire-Interfaced 8-Bit I/O Port Expander with Reset -------------------------------------------------------------------------------- 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 max7310 IS GENERIC ( -- tipd delays: interconnect path delays tipd_SCL : VitalDelayType01 := VitalZeroDelay01; tipd_SDA : VitalDelayType01 := VitalZeroDelay01; tipd_AD0 : VitalDelayType01 := VitalZeroDelay01; tipd_AD1 : VitalDelayType01 := VitalZeroDelay01; tipd_AD2 : VitalDelayType01 := VitalZeroDelay01; tipd_RESETNeg : VitalDelayType01 := VitalZeroDelay01; tipd_IO0 : VitalDelayType01 := VitalZeroDelay01; tipd_IO1 : VitalDelayType01 := VitalZeroDelay01; tipd_IO2 : VitalDelayType01 := VitalZeroDelay01; tipd_IO3 : VitalDelayType01 := VitalZeroDelay01; tipd_IO4 : VitalDelayType01 := VitalZeroDelay01; tipd_IO5 : VitalDelayType01 := VitalZeroDelay01; tipd_IO6 : VitalDelayType01 := VitalZeroDelay01; tipd_IO7 : VitalDelayType01 := VitalZeroDelay01; -- tpd delays tpd_SCL_IO0 : VitalDelayType01 := UnitDelay01; -- tsetup values: setup times tsetup_SDA_SCL : VitalDelayType := UnitDelay; tsetup_IO0_SCL : VitalDelayType := UnitDelay; tsetup_SCL_SDAS : VitalDelayType := UnitDelay; tsetup_SCL_SDAP : VitalDelayType := UnitDelay; -- thold values: hold times thold_SDA_SCL : VitalDelayType := UnitDelay; thold_IO0_SCL : VitalDelayType := UnitDelay; thold_SCL_SDAS : VitalDelayType := UnitDelay; -- tpw values: pulse widths tpw_SCL_posedge : VitalDelayType := UnitDelay; tpw_SCL_negedge : VitalDelayType := UnitDelay; tpw_RESETNeg_negedge : VitalDelayType := UnitDelay; -- tdevice values: values for internal delays tdevice_TBUF : VitalDelayType := 1.3 us; -- generic control parameters InstancePath : STRING := DefaultInstancePath; TimingChecksOn : BOOLEAN := DefaultTimingChecks; MsgOn : BOOLEAN := DefaultMsgOn; XOn : BOOLEAN := DefaultXon; SeverityMode : SEVERITY_LEVEL := WARNING; -- For FMF SDF technology file usage TimingModel : STRING := DefaultTimingModel ); PORT ( SCL : IN std_logic := 'U'; SDA : INOUT std_logic := 'U'; AD0 : IN std_logic := 'U'; AD1 : IN std_logic := 'U'; AD2 : IN std_logic := 'U'; IO0 : INOUT std_logic := 'U'; IO1 : INOUT std_logic := 'U'; IO2 : INOUT std_logic := 'U'; IO3 : INOUT std_logic := 'U'; IO4 : INOUT std_logic := 'U'; IO5 : INOUT std_logic := 'U'; IO6 : INOUT std_logic := 'U'; IO7 : INOUT std_logic := 'U'; RESETNeg : IN std_logic := 'U' ); ATTRIBUTE VITAL_LEVEL0 of max7310 : ENTITY IS TRUE; END max7310 ; -------------------------------------------------------------------------------- -- ARCHITECTURE DECLARATION -------------------------------------------------------------------------------- ARCHITECTURE vhdl_behavioral of max7310 IS ATTRIBUTE VITAL_LEVEL0 of vhdl_behavioral : ARCHITECTURE IS TRUE; CONSTANT partID : STRING := "max7310"; CONSTANT tbus_timeout : TIME := 30 ms; SIGNAL SCL_ipd : std_logic := 'U'; SIGNAL SDA_ipd : std_logic := 'U'; SIGNAL AD0_ipd : std_logic := 'U'; SIGNAL AD1_ipd : std_logic := 'U'; SIGNAL AD2_ipd : std_logic := 'U'; SIGNAL IO0_ipd : std_logic := 'U'; SIGNAL IO1_ipd : std_logic := 'U'; SIGNAL IO2_ipd : std_logic := 'U'; SIGNAL IO3_ipd : std_logic := 'U'; SIGNAL IO4_ipd : std_logic := 'U'; SIGNAL IO5_ipd : std_logic := 'U'; SIGNAL IO6_ipd : std_logic := 'U'; SIGNAL IO7_ipd : std_logic := 'U'; SIGNAL RESETNeg_ipd : std_logic := 'U'; SIGNAL buf_in : std_logic := '0'; SIGNAL buf_out : std_logic := '0'; BEGIN ---------------------------------------------------------------------------- -- Internal Delays ---------------------------------------------------------------------------- -- Artificial VITAL primitives to incorporate internal delays TBUF : VitalBuf (buf_out, buf_in, (VitalZeroDelay,tdevice_TBUF)); ---------------------------------------------------------------------------- -- Wire Delays ---------------------------------------------------------------------------- WireDelay : BLOCK BEGIN w_1 : VitalWireDelay (SCL_ipd, SCL, tipd_SCL); w_2 : VitalWireDelay (SDA_ipd, SDA, tipd_SDA); w_3 : VitalWireDelay (AD0_ipd, AD0, tipd_AD0); w_4 : VitalWireDelay (AD1_ipd, AD1, tipd_AD1); w_5 : VitalWireDelay (AD2_ipd, AD2, tipd_AD2); w_6 : VitalWireDelay (IO0_ipd, IO0, tipd_IO0); w_7 : VitalWireDelay (IO1_ipd, IO1, tipd_IO1); w_8 : VitalWireDelay (IO2_ipd, IO2, tipd_IO2); w_9 : VitalWireDelay (IO3_ipd, IO3, tipd_IO3); w_10 : VitalWireDelay (IO4_ipd, IO4, tipd_IO4); w_11 : VitalWireDelay (IO5_ipd, IO5, tipd_IO5); w_12 : VitalWireDelay (IO6_ipd, IO6, tipd_IO6); w_13 : VitalWireDelay (IO7_ipd, IO7, tipd_IO7); w_14 : VitalWireDelay (RESETNeg_ipd, RESETNeg, tipd_RESETNeg); END BLOCK; ---------------------------------------------------------------------------- -- Main Behavior Block ---------------------------------------------------------------------------- Behavior: BLOCK PORT ( SCLIn : IN std_logic := 'U'; SDAIn : IN std_logic := 'U'; SDAOut : OUT std_logic := 'Z'; AddressIn : IN std_logic_vector(2 downto 0) := (others => 'Z'); IOOut : OUT std_logic_vector(7 downto 0) := (others => 'Z'); IOIn : IN std_logic_vector(7 downto 0); RESETNegIn : IN std_logic := 'U' ); PORT MAP ( SCLIn => SCL_ipd, SDAIn => SDA_ipd, SDAOut => SDA, AddressIn(0) => AD0_ipd, AddressIn(1) => AD1_ipd, AddressIn(2) => AD2_ipd, IOOut(0) => IO0, IOOut(1) => IO1, IOOut(2) => IO2, IOOut(3) => IO3, IOOut(4) => IO4, IOOut(5) => IO5, IOOut(6) => IO6, IOOut(7) => IO7, IOIn(0) => IO0_ipd, IOIn(1) => IO1_ipd, IOIn(2) => IO2_ipd, IOIn(3) => IO3_ipd, IOIn(4) => IO4_ipd, IOIn(5) => IO5_ipd, IOIn(6) => IO6_ipd, IOIn(7) => IO7_ipd, RESETNegIn => RESETNeg_ipd ); SIGNAL D_zd : std_logic_vector(7 downto 0); SIGNAL TimeOut : BOOLEAN := false; SIGNAL Start : std_ulogic := 'U'; SIGNAL ControlSDA : std_ulogic := '0'; SIGNAL ControlSCL : std_ulogic := '0'; SIGNAL ControlSCLLow : std_ulogic := '0'; SIGNAL T0 : std_logic; BEGIN BUSTIMEOUT: PROCESS (SDAIn, SCLIn, ControlSDA, ControlSCL, T0, Start) VARIABLE SDALow : BOOLEAN := false; VARIABLE SCLLow : BOOLEAN := false; VARIABLE SCLOff : BOOLEAN := false; BEGIN IF rising_edge(Start) THEN ControlSDA <= '0', '1' AFTER tbus_timeout; ControlSCLLow <= '0', '1' AFTER tbus_timeout; SDALow := false; SCLLow := false; SCLOff := false; TimeOut <= false; ELSIF Start = '1' THEN IF rising_edge(ControlSCL) THEN SCLOff := true; END IF; IF rising_edge(SCLIn) THEN ControlSCL <= '0', '1' AFTER tbus_timeout; END IF; IF rising_edge(SDAIn) THEN ControlSDA <= '0'; END IF; IF rising_edge(SCLIn) THEN ControlSCLLow <= '0'; END IF; IF rising_edge(ControlSDA) THEN SDALow := true; END IF; IF rising_edge(ControlSCLLow) THEN SCLLow := true; END IF; IF ((T0 = '1' AND (SDALow = true OR SCLLow = true)) OR SCLOff = true) THEN TimeOut <= true; ELSE TimeOut <= false; END IF; END IF; END PROCESS BUSTIMEOUT; ---------------------------------------------------------------------------- -- Main Behavior Process ---------------------------------------------------------------------------- Behavior : PROCESS (SCLIn, SDAIn, AddressIn, IOIn, RESETNegIn, TimeOut) -- Type definition for commands TYPE command_type is (read_inreg, write_inreg, read_outreg, write_outreg, read_polreg, write_polreg, read_confreg, write_confreg, read_timeout, write_timeout, reserved ); -- Timing Check Variables VARIABLE Tviol_SDAS_SCL : X01 := '0'; VARIABLE TD_SDAS_SCL : VitalTimingDataType; VARIABLE Tviol_SDAH_SCL : X01 := '0'; VARIABLE TD_SDAH_SCL : VitalTimingDataType; VARIABLE Tviol_IO0_SCL : X01 := '0'; VARIABLE TD_IO0_SCL : VitalTimingDataType; VARIABLE Tviol_SCL_SDAS : X01 := '0'; VARIABLE TD_SCL_SDAS : VitalTimingDataType; VARIABLE Tviol_SCL_SDAP : X01 := '0'; VARIABLE TD_SCL_SDAP : VitalTimingDataType; VARIABLE Pviol_SCL : X01 := '0'; VARIABLE PD_SCL : VitalPeriodDataType := VitalPeriodDataInit; VARIABLE Pviol_RESETNeg : X01 := '0'; VARIABLE PD_RESETNeg : VitalPeriodDataType := VitalPeriodDataInit; VARIABLE Violation : X01 := '0'; VARIABLE command : command_type; VARIABLE InputReg : std_logic_vector(7 downto 0) := "00000000"; VARIABLE OutputReg : std_logic_vector(7 downto 0) := "00000000"; VARIABLE PolarReg : std_logic_vector(7 downto 0) := "11110000"; VARIABLE ConfigReg : std_logic_vector(7 downto 0) := "11111111"; VARIABLE TimeoutReg : std_logic_vector(7 downto 0) := "00000001"; VARIABLE AddressReg : std_logic_vector(6 downto 0); VARIABLE TmpReg : std_logic_vector(7 downto 0); VARIABLE TmpReg1 : std_logic_vector(8 downto 0) := "000000000"; VARIABLE ShiftReg : std_logic_vector(7 downto 0); VARIABLE ShiftReg1 : std_logic_vector(8 downto 0); VARIABLE RW : std_logic; VARIABLE counter : NATURAL RANGE 0 TO 8; VARIABLE Addreceived : BOOLEAN := false; VARIABLE Commreceived : BOOLEAN := false; VARIABLE ackslave : BOOLEAN := false; VARIABLE data : std_logic := '0'; BEGIN -------------------------------------------------------------------- -- Timing Check Section -------------------------------------------------------------------- IF (TimingChecksOn) THEN VitalSetupHoldCheck ( TestSignal => SDAIn, TestSignalName => "SDA", RefSignal => SCLIn, RefSignalName => "SCL", SetupHigh => tsetup_SDA_SCL, SetupLow => tsetup_SDA_SCL, CheckEnabled => (Start = '1'), RefTransition => '/', HeaderMsg => InstancePath & PartID, TimingData => TD_SDAS_SCL, XOn => XOn, MsgOn => MsgOn, Violation => Tviol_SDAS_SCL ); VitalSetupHoldCheck ( TestSignal => SDAIn, TestSignalName => "SDA", RefSignal => SCLIn, RefSignalName => "SCL", HoldHigh => thold_SDA_SCL, HoldLow => thold_SDA_SCL, CheckEnabled => true, RefTransition => '\', HeaderMsg => InstancePath & PartID, TimingData => TD_SDAH_SCL, XOn => XOn, MsgOn => MsgOn, Violation => Tviol_SDAH_SCL ); VitalSetupHoldCheck ( TestSignal => SCLIn, TestSignalName => "SCL", RefSignal => SDAIn, RefSignalName => "SDA", SetupHigh => tsetup_SCL_SDAS, HoldHigh => thold_SCL_SDAS, CheckEnabled => true, RefTransition => '\', HeaderMsg => InstancePath & PartID, TimingData => TD_SCL_SDAS, XOn => XOn, MsgOn => MsgOn, Violation => Tviol_SCL_SDAS ); VitalSetupHoldCheck ( TestSignal => SCLIn, TestSignalName => "SCL", RefSignal => SDAIn, RefSignalName => "SDA", SetupHigh => tsetup_SCL_SDAP, CheckEnabled => true, RefTransition => '/', HeaderMsg => InstancePath & PartID, TimingData => TD_SCL_SDAP, XOn => XOn, MsgOn => MsgOn, Violation => Tviol_SCL_SDAP ); VitalSetupHoldCheck ( TestSignal => IOIn, TestSignalName => "IO", RefSignal => SCLIn, RefSignalName => "SCL", SetupHigh => tsetup_IO0_SCL, SetupLow => tsetup_IO0_SCL, HoldHigh => thold_IO0_SCL, HoldLow => thold_IO0_SCL, CheckEnabled => true, RefTransition => '/', HeaderMsg => InstancePath & PartID, TimingData => TD_IO0_SCL, XOn => XOn, MsgOn => MsgOn, Violation => Tviol_IO0_SCL ); VitalPeriodPulseCheck ( TestSignal => SCLIn, TestSignalName => "SCL", PulseWidthLow => tpw_SCL_negedge, PulseWidthHigh => tpw_SCL_posedge, PeriodData => PD_SCL, XOn => XOn, MsgOn => MsgOn, Violation => Pviol_SCL, HeaderMsg => InstancePath & PartID, CheckEnabled => true ); VitalPeriodPulseCheck ( TestSignal => RESETNegIn, TestSignalName => "RESETNeg", PulseWidthLow => tpw_RESETNeg_negedge, PeriodData => PD_RESETNeg, XOn => XOn, MsgOn => MsgOn, Violation => Pviol_RESETNeg, HeaderMsg => InstancePath & PartID, CheckEnabled => true ); Violation := Tviol_SDAS_SCL OR Tviol_SDAH_SCL OR Tviol_IO0_SCL OR Tviol_SCL_SDAS OR Tviol_SCL_SDAP OR Pviol_SCL OR Pviol_RESETNeg; ASSERT Violation = '0' REPORT InstancePath & partID & ": simulation may be" & " inaccurate due to timing violations" SEVERITY SeverityMode; END IF; ---------------------------------------------------------------------------- -- Functional Section ---------------------------------------------------------------------------- IF SCLIn = '1'AND RESETNegIn = '1' AND TimeOut = false THEN IF falling_edge(SDAIn) THEN ASSERT buf_out = '0' REPORT InstancePath & partID & ": Bus free time beetwen STOP" & " and START condition " SEVERITY SeverityMode; Start <= '1'; counter := 0; Addreceived := false; Commreceived := false; ackslave := false; data := '0'; ELSIF rising_edge(SDAIn) THEN buf_in <= '1', '0' AFTER 1.3 us; Start <= '0'; END IF; END IF; IF RESETNegIn = '0' OR TimeOut = true THEN OutputReg := "00000000"; PolarReg := "11110000"; ConfigReg := "11111111"; TimeoutReg := "00000001"; Start <= '0'; ELSIF rising_edge(SCLIn) AND Start = '1' THEN IF Addreceived = false THEN IF counter < 7 THEN AddressReg(6 - counter) := SDAIn; counter := counter + 1; ELSIF counter = 7 THEN RW := SDAIn; counter := counter + 1; ELSIF counter = 8 THEN counter := 0; Addreceived := true; END IF; ELSIF Commreceived = false THEN IF counter < 8 THEN TmpReg1(8 - counter) := SDAIn; counter := counter + 1; ELSIF counter = 8 THEN counter := 0; Commreceived := true; TmpReg := TmpReg1(8 downto 1); CASE TmpReg IS WHEN "00000000" => IF RW = '1' THEN command := read_inreg; FOR I IN 0 TO 7 LOOP IF PolarReg(i) = '1' AND ConfigReg(i) = '1' THEN InputReg(i) := not(IOIn(i)); ELSE InputReg(i) := IOIn(i); END IF; END LOOP; ShiftReg := InputReg; ShiftReg1 := ShiftReg & '1'; ELSE command := write_inreg; END IF; WHEN "00000001" => IF RW = '1' THEN command := read_outreg; ShiftReg := OutputReg; ShiftReg1 := ShiftReg & '1'; ELSE command := write_outreg; END IF; WHEN "00000010" => IF RW = '1' THEN command := read_polreg; ShiftReg := PolarReg; ShiftReg1 := ShiftReg & '1'; ELSE command := write_polreg; END IF; WHEN "00000011" => IF RW = '1' THEN command := read_confreg; ShiftReg := ConfigReg; ShiftReg1 := ShiftReg & '1'; ELSE command := write_confreg; END IF; WHEN "00000100" => IF RW = '1' THEN command := read_timeout; ShiftReg := TimeoutReg; ShiftReg1 := ShiftReg & '1'; ELSE command := write_timeout; END IF; WHEN "11111111" => command := reserved; ASSERT false REPORT InstancePath & partID & ": Factory" & " reserved register. " SEVERITY SeverityMode; WHEN others => ASSERT false REPORT InstancePath & partID & ": Could not" & " decode command. " SEVERITY SeverityMode; END CASE; END IF; ELSIF RW = '0' AND counter < 8 THEN ShiftReg(counter) := SDAIn; counter := counter + 1; ELSIF RW = '1' AND counter < 8 THEN counter := counter + 1; ELSIF counter = 8 THEN data := '0'; counter := 0; CASE command IS WHEN write_outreg => OutputReg := ShiftReg; FOR I IN 0 TO 7 LOOP IF ConfigReg(i) = '0' THEN D_zd(i) <= OutputReg(i); ELSE D_zd(i) <= 'Z'; END IF; END LOOP; WHEN write_confreg => ConfigReg := ShiftReg; WHEN write_timeout => TimeoutReg := ShiftReg; WHEN write_polreg => PolarReg := ShiftReg; WHEN read_outreg => ShiftReg := OutputReg; ShiftReg1 := ShiftReg & '1'; WHEN read_polreg => ShiftReg := PolarReg; ShiftReg1 := ShiftReg & '1'; WHEN read_confreg => ShiftReg := ConfigReg; ShiftReg1 := ShiftReg & '1'; WHEN read_timeout => ShiftReg := TimeoutReg; ShiftReg1 := ShiftReg & '1'; WHEN read_inreg => FOR I IN 0 TO 7 LOOP IF PolarReg(i) = '1' AND ConfigReg(i) = '1' THEN InputReg(i) := not(IOIn(i)); ELSE InputReg(i) := IOIn(i); END IF; END LOOP; ShiftReg := InputReg; ShiftReg1 := ShiftReg & '1'; WHEN others => NULL; END CASE; END IF; ELSIF falling_edge(SCLIn) AND Start = '1' THEN IF RW = '0' THEN IF counter = 8 THEN ackslave := true; ELSIF counter = 0 THEN ackslave := false; END IF; ELSE IF counter = 8 AND Commreceived = false THEN ackslave := true; ELSIF counter = 0 THEN ackslave := false; END IF; IF counter < 8 AND Commreceived = true THEN data := '1'; ELSE data := '0'; END IF; END IF; END IF; T0 <= TimeoutReg(0); IF RESETNegIn = '0' OR TimeOut = true THEN SDAOut <= 'Z'; IOOut <= (others => 'Z'); ELSIF Start = '1' THEN IF ackslave = true THEN SDAOut <= '0'; ELSIF data = '1' AND falling_edge(SCLIn) THEN SDAOut <= 'Z', ShiftReg1(8 - counter) AFTER 1 us; ELSIF data = '0' THEN SDAOut <= 'Z'; END IF; END IF; END PROCESS; ------------------------------------------------------------------------ -- Path Delay Process ------------------------------------------------------------------------ DataOut : FOR i IN 7 DOWNTO 0 GENERATE DataOut_Delay : PROCESS (D_zd(i)) VARIABLE D_GlitchData:VitalGlitchDataArrayType(7 Downto 0); BEGIN VitalPathDelay01 ( OutSignal => IOOut(i), OutSignalName => "Data", OutTemp => D_zd(i), Mode => OnEvent, GlitchData => D_GlitchData(i), Paths => ( 1 => (InputChangeTime => SCLIn'LAST_EVENT, PathDelay => tpd_SCL_IO0, PathCondition => TRUE) ) ); END PROCESS; END GENERATE; END BLOCK; END vhdl_behavioral;