--
-- Simulation Package for Hardware Abstrat Interface Layer  
--
-- (C) 2006 Alpha Data
--
-- 

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_misc.all;

library work;
use work.common_interface.all;


package hail_simulation is

  type interrupt_wbus_type is record
    ier : std_logic_vector(reg_width-1 downto 0);
    isr : std_logic_vector(reg_width-1 downto 0);
    ier_wstb : std_logic;
  end record;

  type extmem_in_type is record
    data : std_logic_vector(extmem_width-1 downto 0);
    addr : integer;
    bank : integer;
    wstb : std_logic;
    rstb : std_logic;
    gnt  : std_logic;
    clrgnt : std_logic;
  end record;

  type extmem_out_type is record
    data : std_logic_vector(extmem_width-1 downto 0);
    req  : std_logic;
  end record;
  
  type host_in_type is record
    clk : std_logic;
    ctrl_bus : ctrl_bus_type;
    status_bus : status_bus_type;
    interrupt_bus : interrupt_wbus_type;
    bram_bus : bram_bus_type;
    extmem_bus : extmem_in_type;
  end record;
  
  constant host_in_zeros : host_in_type := (clk => '0',
                                            ctrl_bus => ( data => (others => '0'), addr => (others => '0'), wstb => '0'),
                                            status_bus => ( addr => (others => '0'), data => (others => '0')),
                                            interrupt_bus => (ier => (others => '0'), ier_wstb => '0',
                                                              isr => (others => '0')),
                                            bram_bus => ( data => (others => '0'), addr => (others => '0'),
                                                          id => (others => '0'), q => (others => '0'),
                                                          qv => '0', wstb => '0', rstb => '0'),
                                            extmem_bus => ( data => (others => '0'), addr => 0, bank => 0,
                                                            wstb => '0', rstb => '0',gnt => '0',clrgnt => '0'));
                                      
                                    
                                      
                                            
  type host_out_type is record
    status_bus : status_bus_type;
    interrupt_bus : interrupt_bus_type;
    bram_bus : bram_bus_type;
    extmem_bus : extmem_out_type;
  end record;

  type board_type is (adm_xp,adp_xpi,adm_xrc4,adpe_xrc4);

  type link_in_type is record  
    rx_data    : std_logic_vector(15 downto 0);
    rx_src_rdy : std_logic;
    rx_sof     : std_logic;
    rx_eof     : std_logic;
    tx_dst_rdy : std_logic;
  end record;
  
  type link_out_type is record  
    tx_data    : std_logic_vector(15 downto 0);
    tx_src_rdy : std_logic;
    tx_sof     : std_logic;
    tx_eof     : std_logic;
  end record;

  type links_in_type is array (0 to 3) of link_in_type;
  type links_out_type is array (0 to 3) of link_out_type;
  
  component hail_simulator
    generic (
      board              : board_type;
      number_of_memories : integer);
    port (
      clk        : in  std_logic;
      rst        : in  std_logic;
      system_out : in  std_logic_vector(system_width-1 downto 0);
      system_in  : out std_logic_vector(system_width-1 downto 0);
      links_in   : in  links_in_type;
      links_out  : out links_out_type;
      host_in    : in  host_in_type;
      host_out   : out host_out_type);
  end component;

  component link_connect
    port (
      linkA_in   : out  link_in_type;
      linkA_out  : in   link_out_type;
      linkB_in   : out  link_in_type;
      linkB_out  : in   link_out_type);
  end component;


  component user_top_level
    port (
      clk         : in  std_logic;
      rst         : in  std_logic;
      system_in   : in  std_logic_vector(system_width-1 downto 0);
      system_out  : out std_logic_vector(system_width-1 downto 0));
  end component;
  
  procedure host_write_control_register (
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable address  : in  integer;
    variable data     : in  std_logic_vector);
  
  procedure host_read_status_register (
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable address  : in  integer;
    variable data     : out std_logic_vector);

  procedure host_set_interrupt_register (
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable data     : in  std_logic_vector);
  
  procedure host_read_interrupt_register (
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable data     : out std_logic_vector);

  procedure host_wait_on_interrupt (
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable mask     : in  std_logic_vector);

  procedure host_clear_interrupt_register (
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable mask     : in  std_logic_vector);
  
  procedure host_write_external_memory (
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable bank     : in  integer;
    variable address  : in  integer;
    variable data     : in  std_logic_vector);

  procedure host_read_external_memory (
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable bank     : in  integer;
    variable address  : in  integer;
    variable data     : out std_logic_vector);

  procedure host_external_memory_set_grant(
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable bank     : in integer);
  
  procedure host_external_memory_clr_grant(
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable bank     : in integer);
  
  procedure host_external_memory_request_status(
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable bank     : in integer;
    variable request  : out boolean);
  
  procedure host_write_internal_memory (
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable bank     : in  integer;
    variable address  : in  integer;
    variable data     : in  std_logic_vector);

  procedure host_read_internal_memory (
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable bank     : in  integer;
    variable address  : in  integer;
    variable data     : out std_logic_vector);


  
end hail_simulation;

package body hail_simulation is

  procedure host_write_control_register (
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable address  : in  integer;
    variable data     : in  std_logic_vector)
  is
  begin
    -- Initialise host input signals to 0
    host_in <= host_in_zeros;
    -- Set up data and addr
    assert data'length <= reg_width report "hail_simulation.host_write_control_register::input data too wide" severity failure;
    host_in.ctrl_bus.data(data'length-1 downto 0) <= data;
    host_in.ctrl_bus.addr <= CONV_STD_LOGIC_VECTOR(address,reg_addr_width);
    host_in.ctrl_bus.wstb <= '1';
    wait for 1 ns;                      -- Allow 1 ns set up
    host_in.clk <= '1';
    wait for 8 ns;                     -- Pulse LCLK for 16 ns
    host_in.clk <= '0';
    wait for 7 ns;
    host_in.ctrl_bus.wstb <= '0';
  end procedure host_write_control_register;

  procedure host_read_status_register (
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable address  : in  integer;
    variable data     : out std_logic_vector)
  is
  begin
    -- Initialise host input signals to 0
    host_in <= host_in_zeros;
    -- Set up addr
    host_in.status_bus.addr <= CONV_STD_LOGIC_VECTOR(address,reg_addr_width);
    wait for 1 ns;                      -- Allow 1 ns set up
    host_in.clk <= '1';
    wait for 8 ns;                     -- Pulse LCLK for 16 ns
    host_in.clk <= '0';
    wait for 7 ns;
    assert data'length <= reg_width report "hail_simulation.host_read_status_register::output data too wide" severity failure;
    data := host_out.status_bus.data(data'length-1 downto 0);
  end procedure host_read_status_register;

  procedure host_set_interrupt_register (
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable data     : in  std_logic_vector)
  is
  begin
    host_in <= host_in_zeros;
    assert data'length <= reg_width report "hail_simulation.host_set_interrupt_register::input data too wide" severity failure;
    host_in.interrupt_bus.ier(data'length-1 downto 0) <= data;
    host_in.interrupt_bus.ier_wstb <= '1';
    wait for 1 ns;                      -- Allow 1 ns set up
    host_in.clk <= '1';
    wait for 8 ns;                     -- Pulse LCLK for 16 ns
    host_in.clk <= '0';
    wait for 7 ns;
    host_in.interrupt_bus.ier_wstb <= '0';
  end procedure host_set_interrupt_register;
    
  procedure host_read_interrupt_register (
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable data     : out std_logic_vector)
  is
  begin
    assert data'length <= reg_width report "hail_simulation.host_read_interrupt_register::output data too wide" severity failure;
    data := host_out.interrupt_bus.isr(data'length-1 downto 0);
  end procedure host_read_interrupt_register;
  
  procedure host_wait_on_interrupt (
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable mask     : in  std_logic_vector)
  is
  begin
    assert mask'length <= reg_width report "hail_simulation.host_wait_on_interrupt::input mask too wide" severity failure;
    host_in <= host_in_zeros;
    while OR_reduce(mask and host_out.interrupt_bus.isr(mask'length-1 downto 0)) = '0' loop
      -- Clock LCLK until ISR changes
      wait for 1 ns;                      -- Allow 1 ns set up
      host_in.clk <= '1';
      wait for 8 ns;                     -- Pulse LCLK for 16 ns
      host_in.clk <= '0';
      wait for 7 ns;
    end loop;  
  end procedure host_wait_on_interrupt;

  procedure host_clear_interrupt_register (
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable mask     : in  std_logic_vector)
  is
  begin
    assert mask'length <= reg_width report "hail_simulation.host_clear_interrupt_register::input mask too wide" severity failure;
    host_in <= host_in_zeros;
    host_in.interrupt_bus.isr(mask'length-1 downto 0) <= mask;
    wait for 1 ns;                      -- Allow 1 ns set up
    host_in.clk <= '1';
    wait for 8 ns;                     -- Pulse LCLK for 16 ns
    host_in.clk <= '0';
    wait for 7 ns;
  end procedure host_clear_interrupt_register;


  procedure host_write_external_memory (
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable bank     : in  integer;
    variable address  : in  integer;
    variable data     : in  std_logic_vector)
   is
   begin
    assert data'length <= extmem_width report "hail_simulation.host_write_external_memory::input data too wide" severity failure;
    host_in <= host_in_zeros;
    host_in.extmem_bus.data(data'length-1 downto 0) <= data;
    host_in.extmem_bus.addr <= address;
    host_in.extmem_bus.bank <= bank;
    host_in.extmem_bus.wstb <= '1';
    wait for 1 ns;                      -- Allow 1 ns set up
    host_in.clk <= '1';
    wait for 8 ns;                     -- Pulse LCLK for 16 ns
    host_in.clk <= '0';
    wait for 7 ns;
    host_in.extmem_bus.wstb <= '0';
  end procedure host_write_external_memory; 

  procedure host_read_external_memory (
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable bank     : in  integer;
    variable address  : in  integer;
    variable data     : out std_logic_vector)
    is
   begin
    assert data'length <= extmem_width report "hail_simulation.host_read_external_memory::output data too wide" severity failure;
    host_in <= host_in_zeros;
    host_in.extmem_bus.addr <= address;
    host_in.extmem_bus.bank <= bank;
    host_in.extmem_bus.rstb <= '1';
    wait for 1 ns;                      -- Allow 1 ns set up
    host_in.clk <= '1';
    wait for 8 ns;                     -- Pulse LCLK for 16 ns
    host_in.clk <= '0';
    wait for 7 ns;
    host_in.extmem_bus.rstb <= '0';
    data := host_out.extmem_bus.data(data'length-1 downto 0);
  end procedure host_read_external_memory;

  procedure host_external_memory_set_grant(
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable bank     : in integer)
  is
   begin
    host_in <= host_in_zeros;
    host_in.extmem_bus.bank <= bank;
    host_in.extmem_bus.gnt <= '1';
    wait for 1 ns;                      -- Allow 1 ns set up
    host_in.clk <= '1';
    wait for 8 ns;                     -- Pulse LCLK for 16 ns
    host_in.clk <= '0';
    wait for 7 ns;
    host_in.extmem_bus.gnt <= '0';
  end procedure host_external_memory_set_grant; 

  procedure host_external_memory_clr_grant(
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable bank     : in integer)
  is
   begin
    host_in <= host_in_zeros;
    host_in.extmem_bus.bank <= bank;
    host_in.extmem_bus.clrgnt <= '1';
    wait for 1 ns;                      -- Allow 1 ns set up
    host_in.clk <= '1';
    wait for 8 ns;                     -- Pulse LCLK for 16 ns
    host_in.clk <= '0';
    wait for 7 ns;
    host_in.extmem_bus.clrgnt <= '0';
  end procedure host_external_memory_clr_grant; 

  procedure host_external_memory_request_status(
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable bank     : in integer;
    variable request  : out boolean)
   is
   begin
    host_in <= host_in_zeros;
    host_in.extmem_bus.bank <= bank;
    wait for 1 ns;                      -- Allow 1 ns set up
    host_in.clk <= '1';
    wait for 8 ns;                     -- Pulse LCLK for 16 ns
    host_in.clk <= '0';
    wait for 7 ns;
    request := (host_out.extmem_bus.req = '1');
  end procedure host_external_memory_request_status; 

  
  procedure host_write_internal_memory (
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable bank     : in  integer;
    variable address  : in  integer;
    variable data     : in  std_logic_vector)
  is
  begin
    assert data'length <= bram_width report "hail_simulation.host_write_internal_memory::input data too wide" severity failure;
    host_in <= host_in_zeros;
    host_in.bram_bus.data(data'length-1 downto 0) <= data;
    host_in.bram_bus.addr <= CONV_STD_LOGIC_VECTOR(address,bram_addr_width);
    host_in.bram_bus.id <= CONV_STD_LOGIC_VECTOR(bank,bram_id_width);
    host_in.bram_bus.wstb <= '1';
    wait for 1 ns;                      -- Allow 1 ns set up
    host_in.clk <= '1';
    wait for 8 ns;                     -- Pulse LCLK for 16 ns
    host_in.clk <= '0';
    wait for 7 ns;
    host_in.bram_bus.wstb <= '0';
  end procedure host_write_internal_memory;

  
  procedure host_read_internal_memory (
    signal   host_in  : out host_in_type;
    signal   host_out : in  host_out_type;
    variable bank     : in  integer;
    variable address  : in  integer;
    variable data     : out std_logic_vector)
  is
  begin
    assert data'length <= bram_width report "hail_simulation.host_read_internal_memory::output data too wide" severity failure;
    host_in <= host_in_zeros;
    host_in.bram_bus.addr <= CONV_STD_LOGIC_VECTOR(address,bram_addr_width);
    host_in.bram_bus.id <= CONV_STD_LOGIC_VECTOR(bank,bram_id_width);
    host_in.bram_bus.rstb <= '1';
    wait for 1 ns;                      -- Allow 1 ns set up
    host_in.clk <= '1';
    wait for 8 ns;                     -- Pulse LCLK for 16 ns
    host_in.clk <= '0';
    wait for 7 ns;
    host_in.bram_bus.rstb <= '0';
    data := host_out.bram_bus.q(data'length-1 downto 0);
  end procedure host_read_internal_memory;
  
end hail_simulation;
