library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.wishbone_package.all;
use work.crossbar_package.all;
use work.dma_package.all;
use work.test_slave_package.all;
use work.clock_crossing_package.all;

entity test is
end test;

architecture rtl of test is
   constant masters : natural := 3;
   constant slaves  : natural := 3;
   
   signal m : wishbone_master_out;
   signal s : wishbone_master_in;
   
   signal intercon_slave_i  : wishbone_slave_in_vector(masters-1 downto 0);
   signal intercon_slave_o  : wishbone_slave_out_vector(masters-1 downto 0);
   signal intercon_master_i : wishbone_master_in_vector(slaves-1 downto 0);
   signal intercon_master_o : wishbone_master_out_vector(slaves-1 downto 0);
   
   signal ram_slave_i : wishbone_slave_in;
   signal ram_slave_o : wishbone_slave_out;
   
   signal rst : std_logic := '1';
   signal clk : std_logic := '0';
   signal ram_clk : std_logic := '0';
   
   procedure tick(signal clk : out std_logic) is
   begin
     wait for 20ns;
     clk <= '0';
     wait for 20ns;
     clk <= '1';
     wait for 0ns;
   end tick;
   
   procedure write (signal clk   : out std_logic;
                    signal m     : out wishbone_master_out;
                    signal r     : in  wishbone_master_in;
                    constant a   : in  wishbone_address; 
                    constant d   : in  wishbone_data) is
   begin
     m.CYC <= '1';
     m.STB <= '1';
     m.SEL <= (others => '1');
     m.WE <= '1';
     m.ADR <= a;
     m.DAT <= d;

     tick(clk);
     while r.STALL = '1' loop
       tick(clk);
     end loop;
     
     m.STB <= '0';
     m.SEL <= (others => '0');
     m.ADR <= (others => '0');
     m.DAT <= (others => '0');
     m.WE  <= '0';
     
     while r.ACK = '0' loop
       tick(clk);
     end loop;
     
     m.CYC <= '0';
     tick(clk);
   end write;
begin
   intercon : crossbar
      generic map
      (
         masters  => masters,
         slaves   => slaves,
         async    => false
      )
      port map
      (
         clk      => clk,
         rst      => rst,
         slave_i  => intercon_slave_i,
         slave_o  => intercon_slave_o,
         master_i => intercon_master_i,
         master_o => intercon_master_o,
         address  => (0 => x"00000000",
                      1 => x"10000000",
                      2 => x"80000000"),
         mask     => (0 => x"f0000000",
                      1 => x"f0000000",
                      2 => x"ffffffe0")
      );
   
   s0 : test_slave
      generic map
      (
         delay => 3
      )
      port map
      (
         clk     => clk,
         rst     => rst,
         slave_i => intercon_master_o(0),
         slave_o => intercon_master_i(0)
      );
      
   s1a : clock_crossing
      port map(
         rst        => rst,
         slave_clk  => clk,
         slave_i    => intercon_master_o(1),
         slave_o    => intercon_master_i(1),
         master_clk => ram_clk,
         master_i   => ram_slave_o,
         master_o   => ram_slave_i);
   
   s1r : test_slave
      generic map
      (
         delay => 1
      )
      port map
      (
         rst     => rst,
         clk     => ram_clk,
         slave_i => ram_slave_i,
         slave_o => ram_slave_o
      );
   
   dmac : dma
      generic map
      (
         logRingLen => 4
      )
      port map
      (
         clk        => clk,
         rst        => rst,
         w_master_i => intercon_slave_o(1),
         w_master_o => intercon_slave_i(1),
         r_master_i => intercon_slave_o(2),
         r_master_o => intercon_slave_i(2),
         slave_i    => intercon_master_o(2),
         slave_o    => intercon_master_i(2)
      );
   
   intercon_slave_i(0) <= m;
   s <= intercon_slave_o(0);
   
   main : process
   begin
      m <= (
        CYC => '0',
        STB => '0',
        ADR => (others => '0'),
        SEL => (others => '0'),
        WE  => '0',
        DAT => (others => '0'));
      
      rst <= '1';
      tick(clk);
      tick(clk);
      tick(clk);
      rst <= '0';
      tick(clk);
      
      write(clk, m, s, x"80000000", x"10fffff0");
      write(clk, m, s, x"80000004", x"02345670");
      write(clk, m, s, x"80000008", x"00000004");
      write(clk, m, s, x"8000000c", x"00000004");
      write(clk, m, s, x"80000010", x"00000007");
      for i in 0 to 1024 loop
        tick(clk);
      end loop;
   end process;
   
   ram : process
   begin
      for i in 0 to 2048 loop
         wait for 13ns;
         ram_clk <= '0';
         wait for 13ns;
         ram_clk <= '1';
      end loop;
   end process;
end rtl;
