------------------------------------------------------------------------- -- Project: JCPU, a portable 8-bit RISC CPU written in VHDL -- This file: testbench for system test using Xilinx ML-402 -- Copyright (C) 2007 J. Ahrensfeld -- This library is free software; you can redistribute it and/or -- modify it under the terms of the GNU Lesser General Public -- License as published by the Free Software Foundation; either -- version 2.1 of the License, or (at your option) any later version. -- This library is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- Lesser General Public License for more details. -- You should have received a copy of the GNU Lesser General Public -- License along with this library; if not, write to the Free Software -- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -- For questions and ideas, please contact the author at jens@jayfield.org ----------------------------------------------------------------------- LIBRARY ieee; use IEEE.STD_LOGIC_1164.ALL; USE ieee.numeric_std.ALL; ENTITY tb_emac_top_jb IS END tb_emac_top_jb; ARCHITECTURE behavior OF tb_emac_top_jb IS constant CLK_PERIOD : time := 10 ns; constant MII_CLK_PERIOD : time := 37.7 ns; signal CLK : std_logic := '1'; signal RST : std_logic := '1'; -- Slave signal CYC_I : std_logic := '0'; signal STB_I : std_logic := '0'; signal WE_I : std_logic := '0'; signal SEL_I : unsigned(3 downto 0) := (others => '1'); signal ACK_O : std_logic; signal INT_O : std_logic; signal MRDY_I : std_logic := '0'; signal SRDY_O : std_logic; signal ADDR_I : unsigned(31 downto 0) := (others => '-'); signal DAT_I : unsigned(31 downto 0) := (others => '-'); signal DAT_O : unsigned(31 downto 0) := (others => '-'); signal DAT_O_reg : unsigned(31 downto 0) := (others => '-'); signal status_reg : unsigned(31 downto 0) := (others => '0'); signal size_reg : unsigned(31 downto 0) := (others => '0'); -- MII signals signal mii_rx_clk_board : std_logic := '1'; signal mii_tx_clk_board : std_logic := '1'; signal mii_rx_clk : std_logic := '1'; signal mii_tx_clk : std_logic := '1'; signal mii_rx : unsigned(7 downto 0) := (others => '-'); signal mii_tx : unsigned(7 downto 0); signal mii_rx_dv : std_logic := '0'; signal mii_rx_er : std_logic := '0'; signal mii_tx_en : std_logic; signal mii_tx_er : std_logic; signal mii_crs : std_logic := '0'; signal mii_col : std_logic := '0'; signal mii_gtx_clk : std_logic; signal loop_back_en : std_logic := '0'; signal pktgen_tx : unsigned(7 downto 0); signal pktgen_tx_en : std_logic; signal pktgen_tx_er : std_logic; signal pktgen_en : std_logic := '0'; signal pktgen_gigabit : std_logic := '0'; signal pktgen_fcs_en : std_logic := '0'; signal dat_o_cnt_en : std_logic := '0'; signal dat_o_cnt_rst : std_logic := '1'; signal dat_o_cnt : natural; signal pkt_count : natural; type emac_action_t is (emac_idle, emac_alloc, emac_write, emac_commit, emac_wait_data, emac_read, emac_free); signal emac_action : emac_action_t; constant RX_STATUS_REG_ADDR : unsigned(31 downto 0) := X"0000_0000"; constant RX_SIZE_REG_ADDR : unsigned(31 downto 0) := X"0000_0004"; constant TX_STATUS_REG_ADDR : unsigned(31 downto 0) := X"0000_0008"; constant TX_SIZE_REG_ADDR : unsigned(31 downto 0) := X"0000_000C"; constant DATA_REG_ADDR : unsigned(31 downto 0) := X"0000_8000"; BEGIN inst_emac_top_jb : entity work.emac_top_jb GENERIC MAP ( f_sysclk => 100.0, RX_RAM_SIZE => 2048, TX_RAM_SIZE => 2048 ) PORT MAP ( CLK_I => CLK, RST_I => RST, INT_O => INT_O, CYC_I => CYC_I, STB_I => STB_I, SEL_I => SEL_I, WE_I => WE_I, ACK_O => ACK_O, SRDY_O => SRDY_O, MRDY_I => MRDY_I, ADDR_I => ADDR_I, DAT_I => DAT_I, DAT_O => DAT_O, mii_rx_clk => mii_rx_clk_board, mii_rx_dv => mii_rx_dv, mii_rx_er => mii_rx_er, mii_rx => mii_rx, mii_tx_clk => mii_tx_clk_board, mii_tx_en => mii_tx_en, mii_tx_er => mii_tx_er, mii_tx => mii_tx, mii_gtx_clk => mii_gtx_clk, mii_crs => mii_crs, mii_col => mii_col ); inst_pkt_gen : entity work.pkt_gen GENERIC MAP ( f_sysclk => 100.0, PKT_SIZE_MIN => 64, PKT_SIZE_MAX => 1512 ) PORT MAP ( clk => CLK, rst => RST, en => pktgen_en, gigabit_en => pktgen_gigabit, fcs_gen_en => pktgen_fcs_en, mii_tx_clk => mii_tx_clk_board, mii_tx_en => pktgen_tx_en, mii_tx_er => pktgen_tx_er, mii_tx => pktgen_tx ); CLK_GEN: process begin wait for CLK_PERIOD/2; CLK <= not CLK; end process; MII_CLK_GEN: process begin wait for MII_CLK_PERIOD/2; mii_rx_clk <= not mii_rx_clk; mii_tx_clk <= not mii_tx_clk; end process; mii_rx_clk_board <= mii_rx_clk; mii_tx_clk_board <= mii_tx_clk; DAT_O_register: process(CLK) begin if rising_edge(CLK) then if ACK_O = '1' then DAT_O_reg <= DAT_O; end if; end if; end process; DAT_O_count_register: process(CLK) begin if rising_edge(CLK) then if dat_o_cnt_rst = '1' then dat_o_cnt <= 0; elsif ACK_O = '1' and dat_o_cnt_en = '1' then dat_o_cnt <= dat_o_cnt + 1; end if; end if; end process; mii_rx <= mii_tx when loop_back_en = '1' else pktgen_tx; mii_rx_dv <= mii_tx_en when loop_back_en = '1' else pktgen_tx_en; mii_rx_er <= mii_tx_er when loop_back_en = '1' else pktgen_tx_er; mii_crs <= '0'; mii_col <= '0'; -- Master STIMULUS: process procedure emac_tx_reset_100mbps is begin CYC_I <= '1'; wait until rising_edge(CLK) and SRDY_O = '1'; DAT_I <= X"A000_0000"; STB_I <= '1'; WE_I <= '1'; ADDR_I <= TX_STATUS_REG_ADDR; wait until rising_edge(CLK) and SRDY_O = '1'; STB_I <= '0'; WE_I <= '0'; end procedure emac_tx_reset_100mbps; procedure emac_rx_reset_100mbps is begin CYC_I <= '1'; wait until rising_edge(CLK) and SRDY_O = '1'; DAT_I <= X"A000_0000"; STB_I <= '1'; WE_I <= '1'; ADDR_I <= RX_STATUS_REG_ADDR; wait until rising_edge(CLK) and SRDY_O = '1'; STB_I <= '0'; WE_I <= '0'; end procedure emac_rx_reset_100mbps; procedure emac_tx_reset_1000mbps is begin CYC_I <= '1'; wait until rising_edge(CLK) and SRDY_O = '1'; DAT_I <= X"E000_0000"; STB_I <= '1'; WE_I <= '1'; ADDR_I <= TX_STATUS_REG_ADDR; wait until rising_edge(CLK) and SRDY_O = '1'; STB_I <= '0'; WE_I <= '0'; end procedure emac_tx_reset_1000mbps; procedure emac_rx_reset_1000mbps is begin CYC_I <= '1'; wait until rising_edge(CLK) and SRDY_O = '1'; DAT_I <= X"E000_0000"; STB_I <= '1'; WE_I <= '1'; ADDR_I <= RX_STATUS_REG_ADDR; wait until rising_edge(CLK) and SRDY_O = '1'; STB_I <= '0'; WE_I <= '0'; end procedure emac_rx_reset_1000mbps; procedure emac_alloc (size : natural) is begin -- TX-ALLOCATION -- set TX-size emac_action <= emac_alloc; CYC_I <= '1'; wait until rising_edge(CLK) and SRDY_O = '1'; DAT_I <= to_unsigned(size, 32); STB_I <= '1'; WE_I <= '1'; ADDR_I <= TX_SIZE_REG_ADDR; check_alloc_ok: while(true) loop -- set alloc request wait until rising_edge(CLK) and SRDY_O = '1'; WE_I <= '0'; STB_I <= '1'; ADDR_I <= TX_STATUS_REG_ADDR; wait until rising_edge(CLK) and SRDY_O = '1'; STB_I <= '0'; wait until rising_edge(CLK) and ACK_O = '1'; status_reg <= DAT_O; wait until rising_edge(CLK) and SRDY_O = '1'; DAT_I <= X"0002_0000" or (not X"0001_0000" and status_reg); STB_I <= '1'; WE_I <= '1'; ADDR_I <= TX_STATUS_REG_ADDR; check_bsy: while (true) loop wait until rising_edge(CLK) and SRDY_O = '1'; WE_I <= '0'; STB_I <= '1'; ADDR_I <= TX_STATUS_REG_ADDR; wait until rising_edge(CLK) and SRDY_O = '1'; STB_I <= '0'; wait until rising_edge(CLK) and ACK_O = '1'; status_reg <= DAT_O; wait until rising_edge(CLK); if status_reg(17) = '0' then exit check_bsy; end if; end loop; if status_reg(16) = '1' then exit check_alloc_ok; end if; end loop; CYC_I <= '0'; emac_action <= emac_idle; end procedure emac_alloc; procedure emac_commit is begin -- RX- DEALLOCATION emac_action <= emac_commit; -- set free request CYC_I <= '1'; wait until rising_edge(CLK) and SRDY_O = '1'; WE_I <= '0'; STB_I <= '1'; ADDR_I <= TX_STATUS_REG_ADDR; wait until rising_edge(CLK) and SRDY_O = '1'; STB_I <= '0'; wait until rising_edge(CLK) and ACK_O = '1'; status_reg <= DAT_O; wait until rising_edge(CLK) and SRDY_O = '1'; DAT_I <= X"0001_0000" or (not X"0002_0000" and status_reg); STB_I <= '1'; WE_I <= '1'; ADDR_I <= TX_STATUS_REG_ADDR; wait until rising_edge(CLK) and SRDY_O = '1'; STB_I <= '0'; WE_I <= '0'; emac_action <= emac_idle; end procedure emac_commit; procedure emac_write (size : natural) is variable data : unsigned (7 downto 0); variable num_words : natural; begin -- FILL TX data emac_action <= emac_write; if (size mod 4) = 0 then num_words := size/4; else num_words := size/4 + 1; end if; CYC_I <= '1'; wait until rising_edge(CLK) and SRDY_O = '1'; data := X"00"; ADDR_I <= DATA_REG_ADDR; WE_I <= '1'; for i in 1 to num_words loop STB_I <= '1'; DAT_I(7 downto 0) <= data; data := data + 1; DAT_I(15 downto 8) <= data; data := data + 1; DAT_I(23 downto 16) <= data; data := data + 1; DAT_I(31 downto 24) <= data; data := data + 1; wait until rising_edge(CLK) and SRDY_O = '1'; end loop; STB_I <= '0'; wait until rising_edge(CLK) and SRDY_O = '1'; emac_commit; emac_action <= emac_idle; end procedure emac_write; procedure emac_read (size_in : natural) is variable data : unsigned (7 downto 0); variable size, num_words : natural; begin emac_action <= emac_wait_data; -- check if data available check_data_avail: while (true) loop CYC_I <= '1'; wait until rising_edge(CLK) and SRDY_O = '1'; WE_I <= '0'; STB_I <= '1'; ADDR_I <= RX_STATUS_REG_ADDR; wait until rising_edge(CLK) and SRDY_O = '1'; STB_I <= '0'; wait until rising_edge(CLK) and ACK_O = '1'; status_reg <= DAT_O; wait until rising_edge(CLK); if status_reg(17) = '1' and status_reg(16) = '1' then exit check_data_avail; end if; end loop; read_size: dat_o_cnt_rst <= '1'; CYC_I <= '1'; wait until rising_edge(CLK) and SRDY_O = '1'; WE_I <= '0'; STB_I <= '1'; ADDR_I <= RX_SIZE_REG_ADDR; wait until rising_edge(CLK) and SRDY_O = '1'; STB_I <= '0'; wait until rising_edge(CLK) and ACK_O = '1'; size_reg <= DAT_O; wait until rising_edge(CLK); -- set packet request CYC_I <= '1'; wait until rising_edge(CLK) and SRDY_O = '1'; WE_I <= '0'; STB_I <= '1'; ADDR_I <= RX_STATUS_REG_ADDR; wait until rising_edge(CLK) and SRDY_O = '1'; STB_I <= '0'; wait until rising_edge(CLK) and ACK_O = '1'; status_reg <= DAT_O; wait until rising_edge(CLK) and SRDY_O = '1'; DAT_I <= X"0002_0000" or (not X"0001_0000" and status_reg); STB_I <= '1'; WE_I <= '1'; ADDR_I <= RX_STATUS_REG_ADDR; wait until rising_edge(CLK) and SRDY_O = '1'; STB_I <= '0'; WE_I <= '0'; emac_action <= emac_read; -- Read RX data size := size_in; if (size_in = 0) then size := to_integer(size_reg(15 downto 0)); end if; if (size mod 4) = 0 then num_words := size/4; else num_words := size/4 + 1; end if; dat_o_cnt_rst <= '0'; dat_o_cnt_en <= '1'; CYC_I <= '1'; wait until rising_edge(CLK) and SRDY_O = '1'; ADDR_I <= DATA_REG_ADDR; WE_I <= '0'; STB_I <= '1'; for i in 1 to num_words loop wait until rising_edge(CLK) and SRDY_O = '1'; end loop; STB_I <= '0'; wait until rising_edge(CLK) and dat_o_cnt = num_words; dat_o_cnt_en <= '0'; emac_action <= emac_idle; end procedure emac_read; procedure emac_free is begin -- RX- DEALLOCATION emac_action <= emac_free; -- set free request CYC_I <= '1'; wait until rising_edge(CLK) and SRDY_O = '1'; WE_I <= '0'; STB_I <= '1'; ADDR_I <= RX_STATUS_REG_ADDR; wait until rising_edge(CLK) and SRDY_O = '1'; STB_I <= '0'; wait until rising_edge(CLK) and ACK_O = '1'; status_reg <= DAT_O; wait until rising_edge(CLK) and SRDY_O = '1'; DAT_I <= X"0001_0000" or (not X"0002_0000" and status_reg); STB_I <= '1'; WE_I <= '1'; ADDR_I <= RX_STATUS_REG_ADDR; wait until rising_edge(CLK) and SRDY_O = '1'; STB_I <= '0'; WE_I <= '0'; emac_action <= emac_idle; end procedure emac_free; begin wait for 6*MII_CLK_PERIOD; RST <= '0'; wait for 60*CLK_PERIOD; emac_rx_reset_100mbps; emac_tx_reset_100mbps; pktgen_gigabit <= '0'; pktgen_fcs_en <= '1'; wait for 60*CLK_PERIOD; emac_alloc (1004); emac_alloc (1004); emac_alloc (1004); emac_alloc (1004); emac_alloc (1004); emac_alloc (1004); emac_alloc (1004); emac_alloc (1004); emac_alloc (1004); emac_alloc (1004); emac_alloc (1004); emac_alloc (1004); for i in 1 to 2 loop emac_alloc (72); emac_write (72); wait for 10us; end loop; wait until rising_edge(mii_tx_clk) and mii_tx_en = '0'; wait for 600*CLK_PERIOD; loop_back_en <= '1'; emac_alloc (74); emac_write (74); emac_alloc (105); emac_write (105); emac_read (0); emac_free; emac_read (0); emac_free; emac_alloc (103); emac_write (103); emac_read (0); emac_free; emac_alloc (71); emac_write (71); emac_read (0); emac_free; emac_alloc (82); emac_write (82); emac_alloc (86); emac_write (86); emac_read (0); emac_free; emac_read (0); emac_free; emac_alloc (77); emac_write (77); emac_alloc (99); emac_write (99); emac_alloc (65); emac_write (65); emac_alloc (321); emac_write (321); emac_read (0); emac_free; emac_alloc (1111); emac_write (1111); emac_read (0); emac_free; emac_alloc (73); emac_write (73); emac_alloc (107); emac_write (107); emac_alloc (83); emac_write (83); emac_read (0); emac_free; emac_alloc (72); emac_write (72); emac_alloc (1003); emac_write (1003); emac_read (0); emac_free; emac_read (0); emac_free; emac_read (0); emac_free; emac_read (0); emac_free; emac_read (0); emac_free; emac_read (0); emac_free; emac_read (0); emac_free; wait for 6000*CLK_PERIOD; loop_back_en <= '0'; pktgen_en <= '1'; pkt_count <= 0; for i in 1 to 500 loop wait for 1 us; emac_read (0); emac_free; pkt_count <= pkt_count + 1; end loop; pktgen_en <= '0'; emac_read (0); emac_free; wait; end process; END;