--------------------------------------------------------------------------------
--  File Name: sram16k1.vhd
--------------------------------------------------------------------------------
--  Copyright (C) 1999 Free Model Foundry
-- 
--  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     R. Steele   99 JAN 09   Initial release
-- 
--------------------------------------------------------------------------------
--  PART DESCRIPTION:
-- 
--  Library:     MEM
--  Technology:  not ECL
--  Part:        SRAM16K1
-- 
--  Description: 16K X 1 SRAM
--------------------------------------------------------------------------------

LIBRARY IEEE;   USE IEEE.std_logic_1164.ALL;
                USE IEEE.numeric_std.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 sram16k1 IS
    GENERIC (
        -- tipd delays: interconnect path delays
        tipd_OENeg          : VitalDelayType01 := VitalZeroDelay01;
        tipd_WENeg          : VitalDelayType01 := VitalZeroDelay01;
        tipd_CENeg          : VitalDelayType01 := VitalZeroDelay01;
        tipd_CE             : VitalDelayType01 := VitalZeroDelay01;
        tipd_D0             : VitalDelayType01 := VitalZeroDelay01;
        tipd_A0             : VitalDelayType01 := VitalZeroDelay01;
        tipd_A1             : VitalDelayType01 := VitalZeroDelay01;
        tipd_A2             : VitalDelayType01 := VitalZeroDelay01;
        tipd_A3             : VitalDelayType01 := VitalZeroDelay01;
        tipd_A4             : VitalDelayType01 := VitalZeroDelay01;
        tipd_A5             : VitalDelayType01 := VitalZeroDelay01;
        tipd_A6             : VitalDelayType01 := VitalZeroDelay01;
        tipd_A7             : VitalDelayType01 := VitalZeroDelay01;
        tipd_A8             : VitalDelayType01 := VitalZeroDelay01;
        tipd_A9             : VitalDelayType01 := VitalZeroDelay01;
        tipd_A10            : VitalDelayType01 := VitalZeroDelay01;
        tipd_A11            : VitalDelayType01 := VitalZeroDelay01;
        tipd_A12            : VitalDelayType01 := VitalZeroDelay01;
        tipd_A13            : VitalDelayType01 := VitalZeroDelay01;
        -- tpd delays
        tpd_OENeg_D0                    : VitalDelayType01Z := UnitDelay01Z;
        tpd_CENeg_D0                    : VitalDelayType01Z := UnitDelay01Z;
        tpd_A0_D0                       : VitalDelayType01  := UnitDelay01;
        -- tpw values: pulse widths
        tpw_WENeg_negedge               : VitalDelayType    := UnitDelay;
        tpw_WENeg_posedge               : VitalDelayType    := UnitDelay;
        -- tsetup values: setup times
        tsetup_D0_WENeg                 : VitalDelayType    := UnitDelay;
        tsetup_D0_CENeg                 : VitalDelayType    := UnitDelay;
        -- thold values: hold times
        thold_D0_WENeg                  : VitalDelayType    := UnitDelay;
        thold_D0_CENeg                  : VitalDelayType    := UnitDelay;
        -- 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 (
        A0              : IN    std_logic := 'X';
        A1              : IN    std_logic := 'X';
        A2              : IN    std_logic := 'X';
        A3              : IN    std_logic := 'X';
        A4              : IN    std_logic := 'X';
        A5              : IN    std_logic := 'X';
        A6              : IN    std_logic := 'X';
        A7              : IN    std_logic := 'X';
        A8              : IN    std_logic := 'X';
        A9              : IN    std_logic := 'X';
        A10             : IN    std_logic := 'X';
        A11             : IN    std_logic := 'X';
        A12             : IN    std_logic := 'X';
        A13             : IN    std_logic := 'X';

        D0              : INOUT std_logic := 'X';

        OENeg           : IN    std_logic := 'X';
        WENeg           : IN    std_logic := 'X';
        CENeg           : IN    std_logic := 'X';
        CE              : IN    std_logic := 'X'
    );
    ATTRIBUTE VITAL_LEVEL0 of sram16k1 : ENTITY IS TRUE;
END sram16k1;

--------------------------------------------------------------------------------
-- ARCHITECTURE DECLARATION
--------------------------------------------------------------------------------
ARCHITECTURE vhdl_behavioral of sram16k1 IS
    ATTRIBUTE VITAL_LEVEL0 of vhdl_behavioral : ARCHITECTURE IS TRUE;

    ----------------------------------------------------------------------------
    -- Note that this style of model departs significantly from the original
    -- intent of the VITAL spec.  The timing checks section does not generate
    -- any 'X' values for output results since the array only stores integer
    -- values.  So, to check for timing errors one will have to monitor the
    -- warning messages closely.  Also, the path delay procedures are included
    -- in their own processes which are generated as a function of data width.
    -- This method together with the behavior block aids in reducing coding
    -- by converting the address bus and data bus to vectors.  Scalars on the
    -- input ports is necessary for backannotation of wire delays.
    ----------------------------------------------------------------------------

    CONSTANT partID         : STRING := "SRAM 16K X 1";
    CONSTANT MaxData        : NATURAL := 1;
    CONSTANT TotalLOC       : NATURAL := 16383;
    CONSTANT HiAbit         : NATURAL := 13;
    CONSTANT HiDbit         : NATURAL := 0;
    CONSTANT DataWidth      : NATURAL := 1;

    SIGNAL D0_ipd           : std_ulogic := 'X';

    SIGNAL A0_ipd           : std_ulogic := 'X';
    SIGNAL A1_ipd           : std_ulogic := 'X';
    SIGNAL A2_ipd           : std_ulogic := 'X';
    SIGNAL A3_ipd           : std_ulogic := 'X';
    SIGNAL A4_ipd           : std_ulogic := 'X';
    SIGNAL A5_ipd           : std_ulogic := 'X';
    SIGNAL A6_ipd           : std_ulogic := 'X';
    SIGNAL A7_ipd           : std_ulogic := 'X';
    SIGNAL A8_ipd           : std_ulogic := 'X';
    SIGNAL A9_ipd           : std_ulogic := 'X';
    SIGNAL A10_ipd          : std_ulogic := 'X';
    SIGNAL A11_ipd          : std_ulogic := 'X';
    SIGNAL A12_ipd          : std_ulogic := 'X';
    SIGNAL A13_ipd          : std_ulogic := 'X';

    SIGNAL OENeg_ipd        : std_ulogic := 'X';
    SIGNAL WENeg_ipd        : std_ulogic := 'X';
    SIGNAL CENeg_ipd        : std_ulogic := 'X';
    SIGNAL CE_ipd           : std_ulogic := 'X';


BEGIN
    ----------------------------------------------------------------------------
    -- Wire Delays
    ----------------------------------------------------------------------------
    WireDelay : BLOCK
    BEGIN

        w_1: VitalWireDelay (OENeg_ipd, OENeg, tipd_OENeg);
        w_2: VitalWireDelay (WENeg_ipd, WENeg, tipd_WENeg);
        w_3: VitalWireDelay (CENeg_ipd, CENeg, tipd_CENeg);
        w_4: VitalWireDelay (CE_ipd, CE, tipd_CE);
        w_5: VitalWireDelay (D0_ipd, D0, tipd_D0);
        w_13: VitalWireDelay (A0_ipd, A0, tipd_A0);
        w_14: VitalWireDelay (A1_ipd, A1, tipd_A1);
        w_15: VitalWireDelay (A2_ipd, A2, tipd_A2);
        w_16: VitalWireDelay (A3_ipd, A3, tipd_A3);
        w_17: VitalWireDelay (A4_ipd, A4, tipd_A4);
        w_18: VitalWireDelay (A5_ipd, A5, tipd_A5);
        w_19: VitalWireDelay (A6_ipd, A6, tipd_A6);
        w_20: VitalWireDelay (A7_ipd, A7, tipd_A7);
        w_21: VitalWireDelay (A8_ipd, A8, tipd_A8);
        w_22: VitalWireDelay (A9_ipd, A9, tipd_A9);
        w_23: VitalWireDelay (A10_ipd, A10, tipd_A10);
        w_24: VitalWireDelay (A11_ipd, A11, tipd_A11);
        w_25: VitalWireDelay (A12_ipd, A12, tipd_A12);
        w_26: VitalWireDelay (A13_ipd, A13, tipd_A13);

    END BLOCK;

    ----------------------------------------------------------------------------
    -- Main Behavior Block
    ----------------------------------------------------------------------------
    Behavior: BLOCK

        PORT (
            AddressIn       : IN    std_logic_vector(HiAbit downto 0);
            DataIn          : IN    std_logic_vector(HiDbit downto 0);
            DataOut         : OUT   std_logic_vector(HiDbit downto 0);
            OENegIn         : IN    std_ulogic := 'X';
            WENegIn         : IN    std_ulogic := 'X';
            CENegIn         : IN    std_ulogic := 'X';
            CEIn            : IN    std_ulogic := 'X'
        );
        PORT MAP (
            DataOut(0) =>  D0,
            DataIn(0) =>  D0_ipd,
            AddressIn(0) => A0_ipd,
            AddressIn(1) => A1_ipd,
            AddressIn(2) => A2_ipd,
            AddressIn(3) => A3_ipd,
            AddressIn(4) => A4_ipd,
            AddressIn(5) => A5_ipd,
            AddressIn(6) => A6_ipd,
            AddressIn(7) => A7_ipd,
            AddressIn(8) => A8_ipd,
            AddressIn(9) => A9_ipd,
            AddressIn(10) => A10_ipd,
            AddressIn(11) => A11_ipd,
            AddressIn(12) => A12_ipd,
            AddressIn(13) => A13_ipd,
            OENegIn => OENeg_ipd,
            WENegIn => WENeg_ipd,
            CENegIn => CENeg_ipd,
            CEIn    => CE_ipd
--          CEIn    => OPEN
        );

        SIGNAL D_zd     : std_logic_vector(HiDbit DOWNTO 0); 

    BEGIN 
        ------------------------------------------------------------------------
        -- Behavior Process
        ------------------------------------------------------------------------
        Behavior : PROCESS (OENegIn, WENegIn, CENegIn, CEIn, AddressIn, DataIn)
                         
            -- Timing Check Variables
            VARIABLE Tviol_D0_WENeg: X01 := '0';
            VARIABLE TD_D0_WENeg   : VitalTimingDataType;

            VARIABLE Tviol_D0_CENeg: X01 := '0';
            VARIABLE TD_D0_CENeg   : VitalTimingDataType;

            VARIABLE Pviol_WENeg   : X01 := '0';
            VARIABLE PD_WENeg      : VitalPeriodDataType := VitalPeriodDataInit;

            -- Memory array declaration
            TYPE MemStore IS ARRAY (0 to TotalLOC) OF NATURAL 
                             RANGE  0 TO MaxData;

            -- Functionality Results Variables
            VARIABLE Violation  : X01 := '0';
            VARIABLE DataDrive  : std_logic_vector(HiDbit DOWNTO 0)
                                   := (OTHERS => 'X');
            VARIABLE DataTemp   : NATURAL RANGE 0 TO MaxData  := 0;
            VARIABLE Location   : NATURAL RANGE 0 TO TotalLOC := 0;
            VARIABLE MemData    : MemStore;

            -- No Weak Values Variables
            VARIABLE OENeg_nwv   : UX01 := 'X';
            VARIABLE WENeg_nwv   : UX01 := 'X';
            VARIABLE CENeg_nwv   : UX01 := 'X';
            VARIABLE CE_nwv      : UX01 := 'X';

        BEGIN 
            OENeg_nwv   := To_UX01 (s => OENegIn);
            WENeg_nwv   := To_UX01 (s => WENegIn);
            CENeg_nwv   := To_UX01 (s => CENegIn);
            CE_nwv      := To_UX01 (s => CEIn);
--          CE_nwv      := '1';

            --------------------------------------------------------------------
            -- Timing Check Section
            --------------------------------------------------------------------
            IF (TimingChecksOn) THEN

                VitalSetupHoldCheck (
                    TestSignal      => DataIn,
                    TestSignalName  => "Data",
                    RefSignal       => WENeg,
                    RefSignalName   => "WENeg",
                    SetupHigh       => tsetup_D0_WENeg,
                    SetupLow        => tsetup_D0_WENeg,
                    HoldHigh        => thold_D0_WENeg,
                    HoldLow         => thold_D0_WENeg,
                    CheckEnabled    => (CENeg ='0' and CE ='1'and OENeg ='1'),
                    RefTransition   => '/',
                    HeaderMsg       => InstancePath & PartID,
                    TimingData      => TD_D0_WENeg,
                    XOn             => XOn,
                    MsgOn           => MsgOn,
                    Violation       => Tviol_D0_WENeg );

                VitalSetupHoldCheck (
                    TestSignal      => DataIn,
                    TestSignalName  => "Data",
                    RefSignal       => CENeg,
                    RefSignalName   => "CENeg",
                    SetupHigh       => tsetup_D0_CENeg,
                    SetupLow        => tsetup_D0_CENeg,
                    HoldHigh        => thold_D0_CENeg,
                    HoldLow         => thold_D0_CENeg,
                    CheckEnabled    => (WENeg ='0' and OENeg ='1'),
                    RefTransition   => '/',
                    HeaderMsg       => InstancePath & PartID,
                    TimingData      => TD_D0_CENeg,
                    XOn             => XOn,
                    MsgOn           => MsgOn,
                    Violation       => Tviol_D0_CENeg );


                VitalPeriodPulseCheck (
                    TestSignal      =>  WENegIn,
                    TestSignalName  =>  "WENeg",
                    PulseWidthLow   =>  tpw_WENeg_negedge,
                    PeriodData      =>  PD_WENeg,
                    XOn             =>  XOn,
                    MsgOn           =>  MsgOn,
                    Violation       =>  Pviol_WENeg,
                    HeaderMsg       =>  InstancePath & PartID,
                    CheckEnabled    =>  TRUE );

                Violation := Pviol_WENeg OR Tviol_D0_WENeg OR Tviol_D0_CENeg;

                ASSERT Violation = '0'
                    REPORT InstancePath & partID & ": simulation may be" &
                           " inaccurate due to timing violations"
                    SEVERITY SeverityMode;

            END IF; -- Timing Check Section

            --------------------------------------------------------------------
            -- Functional Section
            --------------------------------------------------------------------
            DataDrive := (OTHERS => 'Z');

            IF (CE_nwv = '1' AND CENeg_nwv = '0') THEN
                IF (OENeg_nwv = '0' OR WENeg_nwv = '0') THEN

                    Location := To_Nat(AddressIn);

                    IF (OENeg_nwv = '0' AND WENeg_nwv = '1') THEN
                        DataTemp  := MemData(Location);
                        DataDrive := To_slv(DataTemp, DataWidth);
                    ELSE
                        DataTemp := To_Nat(DataIn);
                        MemData(Location) := DataTemp;
                    END IF;
                END IF;
            END IF;

            --------------------------------------------------------------------
            -- Output Section
            --------------------------------------------------------------------
            D_zd <= DataDrive;

        END PROCESS;                           

        ------------------------------------------------------------------------
        -- Path Delay Processes generated as a function of data width
        ------------------------------------------------------------------------
        DataOut_Width : FOR i IN HiDbit DOWNTO 0 GENERATE
            DataOut_Delay : PROCESS (D_zd(i)) 
                VARIABLE D_GlitchData:VitalGlitchDataArrayType(HiDbit Downto 0);
            BEGIN
                VitalPathDelay01Z (
                    OutSignal       => DataOut(i),
                    OutSignalName   => "Data",
                    OutTemp         => D_zd(i),
                    Mode            => OnEvent, 
                    GlitchData      => D_GlitchData(i),
                    Paths           => (     
                        0 => (InputChangeTime => OENeg_ipd'LAST_EVENT,
                              PathDelay       => tpd_OENeg_D0,
                              PathCondition   => TRUE),   
                        1 => (InputChangeTime => CENeg_ipd'LAST_EVENT,
                              PathDelay       => tpd_CENeg_D0,
                              PathCondition   => TRUE),   
                        2 => (InputChangeTime => AddressIn(0)'LAST_EVENT,
                              PathDelay => VitalExtendToFillDelay(tpd_A0_D0),
                              PathCondition   => TRUE),
                        3 => (InputChangeTime => AddressIn(1)'LAST_EVENT,
                              PathDelay => VitalExtendToFillDelay(tpd_A0_D0),
                              PathCondition   => TRUE),
                        4 => (InputChangeTime => AddressIn(2)'LAST_EVENT,
                              PathDelay => VitalExtendToFillDelay(tpd_A0_D0),
                              PathCondition   => TRUE),
                        5 => (InputChangeTime => AddressIn(3)'LAST_EVENT,
                              PathDelay => VitalExtendToFillDelay(tpd_A0_D0),
                              PathCondition   => TRUE),
                        6 => (InputChangeTime => AddressIn(4)'LAST_EVENT,
                              PathDelay => VitalExtendToFillDelay(tpd_A0_D0),
                              PathCondition   => TRUE),
                        7 => (InputChangeTime => AddressIn(5)'LAST_EVENT,
                              PathDelay => VitalExtendToFillDelay(tpd_A0_D0),
                              PathCondition   => TRUE),
                        8 => (InputChangeTime => AddressIn(6)'LAST_EVENT,
                              PathDelay => VitalExtendToFillDelay(tpd_A0_D0),
                              PathCondition   => TRUE),
                        9 => (InputChangeTime => AddressIn(7)'LAST_EVENT,
                              PathDelay => VitalExtendToFillDelay(tpd_A0_D0),
                              PathCondition   => TRUE),
                       10 => (InputChangeTime => AddressIn(8)'LAST_EVENT,
                              PathDelay => VitalExtendToFillDelay(tpd_A0_D0),
                              PathCondition   => TRUE),
                       11 => (InputChangeTime => AddressIn(9)'LAST_EVENT,
                              PathDelay => VitalExtendToFillDelay(tpd_A0_D0),
                              PathCondition   => TRUE),
                       12 => (InputChangeTime => AddressIn(10)'LAST_EVENT,
                              PathDelay => VitalExtendToFillDelay(tpd_A0_D0),
                              PathCondition   => TRUE),
                       13 => (InputChangeTime => AddressIn(11)'LAST_EVENT,
                              PathDelay => VitalExtendToFillDelay(tpd_A0_D0),
                              PathCondition   => TRUE),
                       14 => (InputChangeTime => AddressIn(12)'LAST_EVENT,
                              PathDelay => VitalExtendToFillDelay(tpd_A0_D0),
                              PathCondition   => TRUE),
                       15 => (InputChangeTime => AddressIn(13)'LAST_EVENT,
                              PathDelay => VitalExtendToFillDelay(tpd_A0_D0),
                              PathCondition   => TRUE)
                    )
                );

            END PROCESS;                           
        END GENERATE;

    END BLOCK;
END vhdl_behavioral;