------------------------------------------------------------------------
-- Title      : Demo testbench
-- Project    : Virtex-5 Embedded Tri-Mode Ethernet MAC Wrapper
-- File       : configuration_tb.vhd
-- Version    : 1.8
-------------------------------------------------------------------------------
--
-- (c) Copyright 2004-2010 Xilinx, Inc. All rights reserved.
--
-- This file contains confidential and proprietary information
-- of Xilinx, Inc. and is protected under U.S. and
-- international copyright and other intellectual property
-- laws.
--
-- DISCLAIMER
-- This disclaimer is not a license and does not grant any
-- rights to the materials distributed herewith. Except as
-- otherwise provided in a valid license issued to you by
-- Xilinx, and to the maximum extent permitted by applicable
-- law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
-- WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
-- AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
-- BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
-- INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
-- (2) Xilinx shall not be liable (whether in contract or tort,
-- including negligence, or under any other theory of
-- liability) for any loss or damage of any kind or nature
-- related to, arising under or in connection with these
-- materials, including for any direct, or any indirect,
-- special, incidental, or consequential loss or damage
-- (including loss of data, profits, goodwill, or any type of
-- loss or damage suffered as a result of any action brought
-- by a third party) even if such damage or loss was
-- reasonably foreseeable or Xilinx had been advised of the
-- possibility of the same.
--
-- CRITICAL APPLICATIONS
-- Xilinx products are not designed or intended to be fail-
-- safe, or for use in any application requiring fail-safe
-- performance, such as life-support or safety devices or
-- systems, Class III medical devices, nuclear facilities,
-- applications related to the deployment of airbags, or any
-- other applications that could lead to death, personal
-- injury, or severe property or environmental damage
-- (individually and collectively, "Critical
-- Applications"). Customer assumes the sole risk and
-- liability of any use of Xilinx products in Critical
-- Applications, subject only to applicable laws and
-- regulations governing limitations on product liability.
--
-- THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
-- PART OF THIS FILE AT ALL TIMES.
--
------------------------------------------------------------------------
-- Description: Management
--
--              This testbench will exercise the ports of the generic
--              Host Interface to configure the EMAC pair.
------------------------------------------------------------------------


library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;


entity configuration_tb is
    port(
      reset                       : out std_logic;
      ------------------------------------------------------------------
      -- Host Interface
      ------------------------------------------------------------------
      host_clk                    : out std_logic;
      host_opcode                 : out std_logic_vector(1 downto 0);
      host_req                    : out std_logic;
      host_miim_sel               : out std_logic;
      host_addr                   : out std_logic_vector(9 downto 0);
      host_wr_data                : out std_logic_vector(31 downto 0);
      host_miim_rdy               : in  std_logic;
      host_rd_data                : in  std_logic_vector(31 downto 0);
      host_emac1_sel              : out std_logic;

      ------------------------------------------------------------------
      -- Test Bench Semaphores
      ------------------------------------------------------------------
      sync_acq_status_0           : in  std_logic;

      emac0_configuration_busy    : out boolean;
      emac0_monitor_finished_1g   : in  boolean;
      emac0_monitor_finished_100m : in  boolean;
      emac0_monitor_finished_10m  : in  boolean;

      emac1_configuration_busy    : out boolean;
      emac1_monitor_finished_1g   : in  boolean;
      emac1_monitor_finished_100m : in  boolean;
      emac1_monitor_finished_10m  : in  boolean

      );
end configuration_tb;


architecture behavioral of configuration_tb is


    -----------------------------------------------------------------------------
    -- Register Map Constants
    -----------------------------------------------------------------------------

    -- Management configuration register address (0x340)
    constant config_management_address   : std_logic_vector(8 downto 0) := "101000000";

    -- Flow control configuration register address (0x2C0)
    constant config_flow_control_address : std_logic_vector(8 downto 0) := "011000000";

    -- Receiver configuration register address (0x240)
    constant receiver_address            : std_logic_vector(8 downto 0) := "001000000";

    -- Transmitter configuration register address (0x280)
    constant transmitter_address         : std_logic_vector(8 downto 0) := "010000000";

    -- EMAC configuration register address (0x300)
    constant emac_config_add             : std_logic_vector(8 downto 0) := "100000000";


    ----------------------------------------------------------------------
    -- testbench signals
    ----------------------------------------------------------------------

    signal hostclk      : std_logic;
    signal hostopcode   : std_logic_vector(1 downto 0);
    signal hostreq      : std_logic := '0';
    signal hostmiimsel  : std_logic;
    signal hostaddr     : std_logic_vector(9 downto 0);
    signal hostwrdata   : std_logic_vector(31 downto 0);
    signal hostemac1sel : std_logic;


begin


    ------------------------------------------------------------------
    -- Drive outputs from internal signals
    ------------------------------------------------------------------
    host_clk       <= hostclk;
    host_opcode    <= hostopcode;               
    host_req       <= hostreq;                  
    host_miim_sel  <= hostmiimsel;              
    host_addr      <= hostaddr;                 
    host_wr_data   <= hostwrdata;              
    host_emac1_sel <= hostemac1sel;             


    ----------------------------------------------------------------------------
    -- HOSTCLK driver
    ----------------------------------------------------------------------------

    -- Drive HOSTCLK at one third the frequency of GTX_CLK
    p_hostclk : process
    begin
        hostclk <= '0';
        wait for 2 ns;
        loop
            wait for 12 ns;
            hostclk <= '1';
            wait for 12 ns;
            hostclk <= '0';
        end loop;
    end process P_hostclk;


    ----------------------------------------------------------------------------
    -- Configuration Through the Host Interface
    ----------------------------------------------------------------------------
    emac_configuration : process

        -------------------------------------
        -- EMAC Host Configuration Write Procedure
        -------------------------------------
        procedure config_write (
          address              : in std_logic_vector(8 downto 0);    
          data                 : in std_logic_vector(31 downto 0);    
          emacsel              : in std_logic) is    
        begin  
          hostemac1sel         <= emacsel;
          hostaddr(9)          <= '1';
          hostaddr(8 downto 0) <= address;
          hostmiimsel          <= '0';
          hostopcode           <= "01";
          hostwrdata           <= data;
          wait until hostclk'event and hostclk = '0';
        	
          hostaddr(9)          <= '1';
          hostmiimsel          <= '0';
          hostopcode           <= "11";
          hostwrdata           <= (others => '0');
          wait until hostclk'event and hostclk = '0';
        	
        end config_write;


        -------------------------------------
        -- EMAC Host Configuration Read Procedure
        -------------------------------------
        procedure config_read (
          address              : in std_logic_vector(8 downto 0);    
          emacsel              : in std_logic) is    
        begin  
          hostemac1sel         <= emacsel;
          hostaddr(9)          <= '1';
          hostaddr(8 downto 0) <= address;
          hostmiimsel          <= '0';
          hostopcode           <= "11";
          wait until hostclk'event and hostclk = '0';

        end config_read;

  
        -------------------------------------
        -- EMAC Host MDIO Write Procedure
        -------------------------------------
        procedure mdio_write (
          address              : in std_logic_vector(9 downto 0);    
          data                 : in std_logic_vector(15 downto 0);
          emacsel              : in std_logic) is    
        begin  
          hostreq              <= '1';
          hostaddr(9 downto 0) <= address;
          hostmiimsel          <= '1';
          hostopcode           <= "01";
          hostwrdata           <= "0000000000000000" & data;
          wait until hostclk'event and hostclk = '0';
        	
          hostreq              <= '0';
          hostmiimsel          <= '0';
          wait until hostclk'event and hostclk = '0';

          -- Wait for MDIO operation to complete.
          wait until host_miim_rdy'event and host_miim_rdy = '1';
          wait until hostclk'event and hostclk = '0';
        	
        end mdio_write;


        variable data : std_logic_vector(31 downto 0) := (others => '0');


    begin -- emac_configuration

      assert false
      report "Timing checks are not valid" & cr
      severity note;

      emac0_configuration_busy <= false;
      emac1_configuration_busy <= false;

      -- Initialise the Host Bus
      hostemac1sel         <= '0';
      hostaddr(9)          <= '1';
      hostaddr(8 downto 0) <= "000000000";
      hostmiimsel          <= '0';
      hostopcode           <= "11";
      hostwrdata           <= (others => '0');
      data                 := (others => '0');

      -- Reset the core
      assert false
      report "Resetting the design..." & cr
      severity note;

      reset <= '1';
      wait for  4000 ns;
      reset <= '0';
      wait for 200 ns;

      assert false
      report "Timing checks are valid" & cr
      severity note;

      emac0_configuration_busy <= true;
      emac1_configuration_busy <= true;


      assert false
      report "Please wait approximately 15 us for the GTP reset sequence to complete" & cr
      severity note;

      


      -- wait for the RocketIO attached to EMAC0 to initialise
      while (sync_acq_status_0 /= '1') loop
        wait until hostclk'event and hostclk = '0';
      end loop;


      ----------------------------------------------------------------------------
      -- Configuration: initialisation of EMAC0
      ----------------------------------------------------------------------------

        -- Set up MDC frequency. Write 0x48 to Management configuration register 
        -- (Address=340). This will enable MDIO and set MDC to approx 2.4 MHz
        --------------------------------------------------------------------------
        assert false
        report "Setting MDC Frequency to 2.4MHZ of EMAC0..." & cr
        severity note;

        config_write (config_management_address,
                      "00000000000000000000000001001000",
                      '0');


        -- Now that the MDIO has been configured it can be used to write to the
        -- MDIO Management register set in the PCS sublayer.  Here the PHY Control
        -- register is set to disable Auto-Negotiation.
        ---------------------------------------------------------------------------
        assert false
          report "Disabling Auto-Negotiation in PCS sublayer of EMAC0 via MDIO.... please wait for approximately 28 us...." & cr
          severity note; 
      
        mdio_write ("0000000000",
                    "0000000100000000",
                    '0');

        wait for 2 us;

        -- Disable Flow Control.  Set top 3 bits of the flow control
        -- configuration register (Address=2C0) to zero therefore disabling tx
        -- and rx flow control.
        --------------------------------------------------------------------------
        assert false
        report "Disabling tx and rx flow control of EMAC0..." & cr 
        severity note;

        -- Read the current config value from the register
        config_read  (config_flow_control_address,
                      '0');

        -- Now turn off the relevant bits and write back into the register
        data := "000" & host_rd_data(28 downto 0);

        config_write (config_flow_control_address,
                      data,
                      '0');


        -- Setting the tx configuration bit to enable the transmitter
        -- and set to full duplex mode.
        -- Write to Transmittter Configuration Register (Address = 0x280).
        --------------------------------------------------------------------------
        assert false
        report "Setting tx configuration of EMAC0..." & cr
        severity note;

        -- Read the current config value from the register
        config_read  (transmitter_address,
                      '0');

        -- Now set the relevant bits and write back into the register
        data := '0' & host_rd_data(30 downto 29) & '1' & host_rd_data(27) & '0' & host_rd_data(25 downto 0);

        config_write (transmitter_address,
                      data,
                      '0');

        -- Setting the rx configuration bit to enable the receiver
        -- and set to full duplex mode.
        -- Write to Receiver Configuration Register (Address = 0x240).
        -------------------------------------------------------------------------
        assert false
        report "Setting rx configuration of EMAC0..." & cr
        severity note;

        -- Read the current config value from the register
        config_read  (receiver_address,
                      '0');

        -- Now set the relevant bits and write back into the register
        data := '0' & host_rd_data(30 downto 29) & '1' & host_rd_data(27) & '0' & host_rd_data(25 downto 0);

        config_write (receiver_address,
                      data,
                      '0');


      ----------------------------------------------------------------------------
      -- Setting the speed of EMAC0 to 1Gb/s.
      ----------------------------------------------------------------------------
      -- Write to EMAC Configuration Register (Address = 0x300).
      assert false
      report "Setting speed of EMAC0 to 1Gb/s..." & cr
      severity note;

      -- Read the current config value from the register
      config_read  (emac_config_add,
                    '0');

      -- Now set the relevant bits and write back into the register
      data := "10" & host_rd_data(29 downto 0);

      config_write (emac_config_add,
                    data,
                    '0');

      emac0_configuration_busy <= false;


      -- wait for EMAC0 1Gb/s frames to complete
      while (not emac0_monitor_finished_1g) loop
         wait for 8 ns;
      end loop;		   


      emac0_configuration_busy <= true;

      ----------------------------------------------------------------------------
      -- Setting the speed of EMAC0 to 100Mb/s.
      ----------------------------------------------------------------------------
      -- Write to EMAC Configuration Register (Address = 0x300).
      assert false
      report "Setting speed of EMAC0 to 100Mb/s..." & cr
      severity note;

      -- Read the current config value from the register
      config_read  (emac_config_add,
                    '0');

      -- Now set the relevant bits and write back into the register
      data := "01" & host_rd_data(29 downto 0);

      config_write (emac_config_add,
                    data,
                    '0');

      emac0_configuration_busy <= false;


      -- wait for EMAC0 100Mb/s frames to complete
      while (not emac0_monitor_finished_100m) loop
         wait for 80 ns;
      end loop;		   


      emac0_configuration_busy <= true;
      ----------------------------------------------------------------------------
      -- Setting the speed of EMAC0 to 10Mb/s.
      ----------------------------------------------------------------------------
      -- Write to EMAC Configuration Register (Address = 0x300).
      assert false
      report "Setting speed of EMAC0 to 10Mb/s..." & cr
      severity note;

      -- Read the current config value from the register
      config_read  (emac_config_add,
                    '0');

      -- Now set the relevant bits and write back into the register
      data := "00" & host_rd_data(29 downto 0);

      config_write (emac_config_add,
                    data,
                    '0');

      emac0_configuration_busy <= false;


      -- wait for EMAC0 10Mb/s frames to complete
      while (not emac0_monitor_finished_10m) loop
         wait for 800 ns;
      end loop;		   


      wait for 100 ns;

      -- Our work here is done
        assert false
      report "Simulation stopped"
      severity failure;

    end process emac_configuration;



    -----------------------------------------------------------------------------
    -- If the simulation is still going after 2 ms 
    -- then something has gone wrong
    -----------------------------------------------------------------------------
    p_timebomb : process
    begin
      wait for 2 ms;
    	assert false
    	report "** ERROR - Simulation running forever!"
    	severity failure;
    end process p_timebomb;



end behavioral;

