---------------------------------------------------------------------------
-- NDT Solutions Ltd. Proprietary Information
-- Company Confidential
-- Copyright 2004-7
--
-- Filename: LocalBusModelPkg.vhd
-- Language: VHDL '93
-- Project:  NDTS2100
--
-- Design Description:
-- Package for Local Bus Model
---------------------------------------------------------------------------


library IEEE;
use IEEE.Std_Logic_1164.all;
use IEEE.Std_Logic_Arith.all;
use std.textio.all;


package LocalBusModelPkg is


  type tBurstData is array (1 to 256) of integer;

  -- Type holding signals to Bus Model
  type tToBusModel is
    record
      ClkPeriod         : time;
      NoOfWords         : integer;
      Write_nRead       : std_logic;
      Addr              : std_logic_vector(31 downto 0);
      Data              : std_logic_vector(31 downto 0);
      BurstData         : tBurstData;
      BurstMode         : std_ulogic;
      Start             : std_logic;
    end record;

  -- Type holding signals from Bus Model
  type tFromBusModel is
    record
      nLRESET           : std_ulogic;
      LCLKA             : std_ulogic;
      Data              : std_logic_vector(31 downto 0);
      BurstData         : tBurstData;
      Done              : std_ulogic;
      nInt              : std_ulogic;
    end record;

  -- Procedure to initialise the Bus Model
  procedure BusInit(ClkPeriod:           in  time;
                    signal ToBusModel:   out tToBusModel;
                    signal FromBusModel: in  tFromBusModel);

  -- Procedure to do a 32-bit read
  procedure LBusRead (Addr:                in  integer;
                      Data:                out integer;
                      signal ToBusModel:   out tToBusModel;
                      signal FromBusModel: in  tFromBusModel);

  -- Procedure to do a 32-bit write
  procedure LBusWrite (Addr:                in  integer;
                       Data:                in  integer;
                       signal ToBusModel:   out tToBusModel;
                       signal FromBusModel: in  tFromBusModel);

  -- Procedure to do a burst write
  procedure LBusBurstWrite (Addr:                in  integer;
                            BurstData:           in  tBurstData;
                            NoOfWords:           in  integer;
                            signal ToBusModel:   out tToBusModel;
                            signal FromBusModel: in  tFromBusModel);

  -- Procedure to do a burst read
  procedure LBusBurstRead (Addr:                in  integer;
                           BurstData:           out tBurstData;
                           NoOfWords:           in  integer;
                           signal ToBusModel:   out tToBusModel;
                           signal FromBusModel: in  tFromBusModel);

  -- integer to Hex string
  function Int2HexString(IntIn, NibblesOut: integer) return string;

  -- integer and function
  function "and"(constant l, r :integer) return integer;

end package LocalBusModelPkg;



package body LocalBusModelPkg is

  -- Procedure to initialise the Bus Model
  procedure BusInit (ClkPeriod:              in  time;
                     signal ToBusModel:      out tToBusModel;
                     signal FromBusModel:    in  tFromBusModel) is
  begin
    ToBusModel.BurstMode   <= '0';
    ToBusModel.Write_nRead <= 'Z';
    ToBusModel.Addr        <= (others => 'Z');
    ToBusModel.Data        <= (others => 'Z');
    ToBusModel.ClkPeriod   <= ClkPeriod;
    ToBusModel.Start       <= 'L';
    ToBusModel.NoOfWords   <= 1;
    -- Wait until reset has completed + a couple of clock cycles
    wait on FromBusModel.nLRESET until rising_edge(FromBusModel.nLRESET);
    wait on FromBusModel.LCLKA until rising_edge(FromBusModel.LCLKA);
    wait on FromBusModel.LCLKA until rising_edge(FromBusModel.LCLKA);
  end procedure BusInit;


  -- Procedure to do a 32-bit read
  procedure LBusRead (Addr:                in  integer;
                      Data:                out integer;
                      signal ToBusModel:   out tToBusModel;
                      signal FromBusModel: in  tFromBusModel) is
  begin
    ToBusModel.BurstMode    <= '0';
    ToBusModel.NoOfWords    <= 1;
    ToBusModel.Write_nRead  <= '0';
    ToBusModel.Addr         <= conv_std_logic_vector(Addr, 32);
    ToBusModel.Start        <= '1';
    wait for 1 ns;
    ToBusModel.Start        <= 'L';
    wait until rising_edge(FromBusModel.Done);
    Data := conv_integer(unsigned(FromBusModel.Data));
    ToBusModel.Write_nRead  <= 'Z';
    ToBusModel.Addr         <= (others => 'Z');
  end procedure LBusRead;


  -- Procedure to do a 32-bit burst read
  procedure LBusBurstRead (Addr:                in  integer;
                           BurstData:           out tBurstData;
                           NoOfWords:           in  integer;
                           signal ToBusModel:   out tToBusModel;
                           signal FromBusModel: in  tFromBusModel) is
  begin
    ToBusModel.BurstMode    <= '1';
    ToBusModel.NoOfWords    <= NoOfWords;
    ToBusModel.Write_nRead  <= '0';
    ToBusModel.Addr         <= conv_std_logic_vector(Addr, 32);
    ToBusModel.Start        <= '1';
    wait for 1 ns;
    ToBusModel.Start        <= 'L';
    wait until rising_edge(FromBusModel.Done);
    BurstData := FromBusModel.BurstData;
    ToBusModel.Write_nRead  <= 'Z';
    ToBusModel.Addr         <= (others => 'Z');
  end procedure LBusBurstRead;


  -- Procedure to do a 32-bit write
  procedure LBusWrite (Addr:                in  integer;
                       Data:                in  integer;
                       signal ToBusModel:   out tToBusModel;
                       signal FromBusModel: in  tFromBusModel) is
  begin
    ToBusModel.BurstMode    <= '0';
    ToBusModel.NoOfWords    <= 1;
    ToBusModel.Write_nRead  <= '1';
    ToBusModel.Addr         <= conv_std_logic_vector(Addr, 32);
    ToBusModel.Data         <= conv_std_logic_vector(Data, 32);
    ToBusModel.Start        <= '1';
    wait for 1 ps;
    ToBusModel.Start        <= 'L';
    wait until rising_edge(FromBusModel.Done);
    ToBusModel.Write_nRead  <= 'Z';
    ToBusModel.Addr         <= (others => 'Z');
    ToBusModel.Data         <= (others => 'Z');
  end procedure LBusWrite;


  -- Procedure to do a 32-bit burst write
  procedure LBusBurstWrite (Addr:                in  integer;
                            BurstData:           in  tBurstData;
                            NoOfWords:           in  integer;
                            signal ToBusModel:   out tToBusModel;
                            signal FromBusModel: in  tFromBusModel) is
  begin
    ToBusModel.BurstMode    <= '1';
    ToBusModel.NoOfWords    <= NoOfWords;
    ToBusModel.Write_nRead  <= '1';
    ToBusModel.Addr         <= conv_std_logic_vector(Addr, 32);
    ToBusModel.BurstData    <= BurstData;
    ToBusModel.Start        <= '1';
    wait for 1 ps;
    ToBusModel.Start        <= 'L';
    wait until rising_edge(FromBusModel.Done);
    ToBusModel.Write_nRead  <= 'Z';
    ToBusModel.Addr         <= (others => 'Z');
    ToBusModel.Data         <= (others => 'Z');
  end procedure LBusBurstWrite;

  function Int2HexString(IntIn, NibblesOut: integer) return string is
    variable vUnsigned: unsigned(NibblesOut*4 - 1 downto 0);
    variable vHex: unsigned(3 downto 0);
    variable vHexOut: string(1 to NibblesOut + 2);
  begin
    vUnsigned := conv_unsigned(IntIn, NibblesOut*4);

    for count in NibblesOut downto 1 loop
      vHex := vUnsigned(Count*4 - 1 downto Count*4 - 4);
      case vHex is
        when "0000" => vHexOut(NibblesOut - Count + 3) := '0';
        when "0001" => vHexOut(NibblesOut - Count + 3) := '1';
        when "0010" => vHexOut(NibblesOut - Count + 3) := '2';
        when "0011" => vHexOut(NibblesOut - Count + 3) := '3';
        when "0100" => vHexOut(NibblesOut - Count + 3) := '4';
        when "0101" => vHexOut(NibblesOut - Count + 3) := '5';
        when "0110" => vHexOut(NibblesOut - Count + 3) := '6';
        when "0111" => vHexOut(NibblesOut - Count + 3) := '7';
        when "1000" => vHexOut(NibblesOut - Count + 3) := '8';
        when "1001" => vHexOut(NibblesOut - Count + 3) := '9';
        when "1010" => vHexOut(NibblesOut - Count + 3) := 'A';
        when "1011" => vHexOut(NibblesOut - Count + 3) := 'B';
        when "1100" => vHexOut(NibblesOut - Count + 3) := 'C';
        when "1101" => vHexOut(NibblesOut - Count + 3) := 'D';
        when "1110" => vHexOut(NibblesOut - Count + 3) := 'E';
        when others => vHexOut(NibblesOut - Count + 3) := 'F';
      end case;
    end loop;
    vHexOut(1 to 2) := "0x";
    return vHexOut;
  end function Int2HexString;

  -- integer and function
  function "and"(constant l, r : integer) return integer is
  begin
    return conv_integer(unsigned(std_logic_vector(conv_unsigned(l,32)) and
                                 std_logic_vector(conv_unsigned(r,32))));
  end function "and";

end package body LocalBusModelPkg;