LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.NUMERIC_STD.ALL; USE IEEE.MATH_REAL.ALL; use std.textio.all; -- Imports the standard textio package. use work.emac_types.all; use work.utils_pkg.all; ENTITY pkt_gen IS Generic ( f_sysclk : real := 100.0; PKT_DLY_MIN : real := 1.0E-6; PKT_DLY_MAX : real := 100.0E-6; PKT_SIZE_MIN : natural := 64; PKT_SIZE_MAX : natural := 1518 ); Port ( clk : in STD_LOGIC; rst : in STD_LOGIC; mii_tx_clk : in STD_LOGIC; mii_tx_en : out STD_LOGIC; mii_tx_er : out STD_LOGIC; mii_tx : out unsigned(7 downto 0) ); END pkt_gen; ARCHITECTURE behavior OF pkt_gen IS subtype word_ptr_t is unsigned(15 downto 0); signal pkt_data : unsigned(31 downto 0); signal pkt_nbytes : word_ptr_t := X"0040"; signal pkt_nwords : word_ptr_t := X"0010"; signal pkt_delay : natural := natural(1.0*f_sysclk); signal tx_packets : natural; signal tx_bytes : natural; signal mii_fifo_din : unsigned(35 downto 0); signal mii_fifo_dout : unsigned(35 downto 0); signal mii_fifo_we : std_logic; signal mii_fifo_re : std_logic; signal mii_fifo_empty : std_logic; signal mii_fifo_full : std_logic; signal xfer_size : word_ptr_t; signal xfer_ptr : word_ptr_t; signal xfer_cnt : word_ptr_t; signal xfer_set : std_logic; signal xfer_en : std_logic; signal xfer_sync : unsigned(1 downto 0); signal xfer_cnt_en : std_logic; signal xfer_bsy : std_logic; signal xfer_pre_rdy : std_logic; signal uncommit_en : std_logic; signal piso8_din : unsigned(31 downto 0); signal piso8_din_be : unsigned(3 downto 0); signal piso8_din_rdy : std_logic; signal piso8_din_vld : std_logic; signal piso8_dout : unsigned(7 downto 0); signal piso8_dout_vld : std_logic; signal piso8_dout_en : std_logic; signal piso4_din_rdy : std_logic; signal tx_en : std_logic; subtype ifg_cnt_t is natural range 0 to 23; -- 10/100 mbps -- subtype ifg_cnt_t is natural range 0 to 11; -- 1000 mbps signal ifg_cnt : ifg_cnt_t; signal ifg_idle : std_logic; type xfer_state_t is (xfer_init, xfer_idle, xfer_setup, xfer_arm, xfer_active, xfer_uncommit, xfer_free); signal xfer_s, xfer_sn : xfer_state_t; type stream_state_t is (stream_init, stream_idle, stream_start, stream_preamble0, stream_preamble1, stream_active, stream_crc, stream_stop, stream_finish); signal stream_s, stream_sn : stream_state_t; type piso_byte_mask_array_t is array (0 to 3) of unsigned (3 downto 0); constant piso_byte_mask_rom : piso_byte_mask_array_t := ( "1111", "1000", "1100", "1110" ); signal preamble_en : std_logic; signal preamble_addr : natural range 0 to 1; type preamble_t is array (0 to 1) of unsigned(31 downto 0); constant preamble : preamble_t := ( X"55555555", X"555555D5" ); begin mii_tx_er <= '0'; piso8_din <= preamble(preamble_addr) when preamble_en = '1' else mii_fifo_dout(31 downto 0); piso8_din_be <= "1111" when preamble_en = '1' else mii_fifo_dout(35 downto 32); mii_fifo_we <= xfer_bsy; xfer_cnt_en <= xfer_bsy and not mii_fifo_full; mii_fifo_din(35 downto 32) <= piso_byte_mask_rom(to_integer(pkt_nbytes(1 downto 0))) when xfer_pre_rdy = '1' else "1111"; mii_fifo_din(31 downto 0) <= pkt_data; ------------------------------------------------------------------ -- Transfer stuff ------------------------------------------------------------------ xfer_state_next: process(clk) begin if rising_edge(clk) then if rst = '1' then xfer_s <= xfer_init; else xfer_s <= xfer_sn; end if; end if; end process; xfer_state: process(xfer_s, xfer_bsy, xfer_sync) begin uncommit_en <= '0'; xfer_set <= '0'; xfer_en <= '0'; xfer_sn <= xfer_s; case xfer_s is when xfer_init => xfer_sn <= xfer_idle; when xfer_idle => xfer_sn <= xfer_setup; when xfer_setup => xfer_set <= '1'; xfer_sn <= xfer_arm; when xfer_arm => xfer_en <= '1'; xfer_sn <= xfer_active; when xfer_active => xfer_en <= '1'; if xfer_bsy = '0' then xfer_sn <= xfer_uncommit; end if; when xfer_uncommit => uncommit_en <= '1'; xfer_sn <= xfer_free; when xfer_free => if xfer_sync(1) = '1' then xfer_sn <= xfer_idle; end if; when others => xfer_sn <= xfer_idle; end case; end process; ------------------------------------------------------------------ interframe_gap_ready: process(clk) begin if rising_edge(clk) then xfer_sync(1) <= xfer_sync(0); xfer_sync(0) <= mii_fifo_empty; end if; end process; ------------------------------------------------------------------ interframe_gap_counter: process(mii_tx_clk) begin if rising_edge(mii_tx_clk) then ifg_idle <= '0'; if rst = '1' or piso8_dout_vld = '1' then ifg_cnt <= ifg_cnt_t'high; ifg_idle <= '1'; elsif ifg_cnt /= 0 then ifg_cnt <= ifg_cnt - 1; else ifg_idle <= '1'; end if; end if; end process; ------------------------------------------------------------------ pkt_params: process(clk) variable size : word_ptr_t; variable delay : natural; variable krand : real; variable seed1 : integer; variable seed2 : integer; begin if rising_edge(clk) then if rst = '1' then size := to_unsigned(PKT_SIZE_MIN, word_ptr_t'length); delay := natural(1.0E6*PKT_DLY_MIN*f_sysclk); seed1 := 31101970; seed2 := 12586901; tx_packets <= 0; tx_bytes <= 0; elsif uncommit_en = '1' then uniform(seed1, seed2, krand); size := to_unsigned(PKT_SIZE_MIN + natural(real(PKT_SIZE_MAX-PKT_SIZE_MIN)*krand), word_ptr_t'length); delay := natural(1.0E6*f_sysclk*(PKT_DLY_MIN + (PKT_DLY_MAX-PKT_DLY_MIN)*krand)); tx_packets <= tx_packets + 1; tx_bytes <= tx_bytes + to_integer(pkt_nbytes); end if; pkt_delay <= delay; pkt_nbytes <= size; if size(1 downto 0) = 0 then pkt_nwords <= "00" & size(word_ptr_t'left downto 2); else pkt_nwords <= "00" & size(word_ptr_t'left downto 2) + 1; end if; end if; end process; ------------------------------------------------------------------ xfer_counter: process(clk) begin if rising_edge(clk) then if xfer_set = '1' then xfer_cnt <= pkt_nwords; xfer_size <= (others => '0'); xfer_bsy <= '0'; xfer_pre_rdy <= '0'; elsif xfer_en = '1' then xfer_bsy <= '1'; if xfer_cnt_en = '1' or xfer_bsy = '0' then if xfer_cnt /= 1 then xfer_cnt <= xfer_cnt - 1; xfer_size <= xfer_size + 1; else xfer_pre_rdy <= '1'; end if; if xfer_pre_rdy = '1' then xfer_bsy <= '0'; end if; end if; end if; end if; end process; ------------------------------------------------------------------ pkt_data_gen: process(clk) variable data : unsigned(7 downto 0); begin if rising_edge(clk) then if xfer_set = '1' then data := (others => '0'); elsif xfer_cnt_en = '1' or xfer_bsy = '0' then pkt_data(7 downto 0) <= data; data := data + 1; pkt_data(15 downto 8) <= data; data := data + 1; pkt_data(23 downto 16) <= data; data := data + 1; pkt_data(31 downto 24) <= data; data := data + 1; end if; end if; end process; ------------------------------------------------------------------ stream_state_next: process(mii_tx_clk) begin if rising_edge(mii_tx_clk) then if rst = '1' then stream_s <= stream_init; else stream_s <= stream_sn; end if; end if; end process; stream_state: process(stream_s, ifg_idle, mii_fifo_empty, piso8_din_rdy, piso8_dout_vld) begin piso8_din_vld <= '0'; mii_fifo_re <= '0'; preamble_en <= '0'; preamble_addr <= 0; stream_sn <= stream_s; case stream_s is when stream_init => if mii_fifo_empty = '1' then stream_sn <= stream_idle; end if; when stream_idle => if mii_fifo_empty = '0' and piso8_din_rdy = '1' then stream_sn <= stream_start; end if; when stream_start => stream_sn <= stream_preamble0; when stream_preamble0 => preamble_addr <= 0; preamble_en <= '1'; piso8_din_vld <= '1'; if piso8_din_rdy = '1' then stream_sn <= stream_preamble1; end if; when stream_preamble1 => preamble_addr <= 1; preamble_en <= '1'; piso8_din_vld <= '1'; if piso8_din_rdy = '1' then stream_sn <= stream_active; end if; when stream_active => piso8_din_vld <= not mii_fifo_empty; mii_fifo_re <= piso8_din_rdy; if mii_fifo_empty = '1' then stream_sn <= stream_crc; end if; when stream_crc => stream_sn <= stream_stop; when stream_stop => if piso8_dout_vld = '0' then stream_sn <= stream_finish; end if; when stream_finish => if ifg_idle = '0' then stream_sn <= stream_idle; end if; when others => stream_sn <= stream_idle; end case; end process; ------------------------------------------------------------------ -- Instantiate synchronous FIFO inst_mii_fifo: entity work.fifo_async GENERIC MAP ( addr_width => 4, data_width => mii_fifo_din'length, do_last_read_update => true ) PORT MAP ( rst => rst, clk_w => clk, clk_r => mii_tx_clk, we => mii_fifo_we, re => mii_fifo_re, fifo_full => mii_fifo_full, fifo_empty => mii_fifo_empty, fifo_afull => open, fifo_aempty => open, data_w => mii_fifo_din, data_r => mii_fifo_dout ); inst_piso : entity work.piso GENERIC MAP ( data_width_in => 32, data_width_out => 8, msb_first => true ) PORT MAP ( rst => rst, clk => mii_tx_clk, din_vld => piso8_din_vld, din_rdy => piso8_din_rdy, din_be => piso8_din_be, din => piso8_din, dout_vld => piso8_dout_vld, dout_en => piso8_dout_en, dout => piso8_dout ); piso8_dout_en <= piso4_din_rdy and ifg_idle; inst_piso_10mbps : entity work.piso GENERIC MAP ( data_width_in => 8, data_width_out => 4, msb_first => false ) PORT MAP ( rst => rst, clk => mii_tx_clk, din_vld => piso8_dout_vld, din_rdy => piso4_din_rdy, din_be => "11", din => piso8_dout, dout_vld => tx_en, dout_en => '1', dout => mii_tx(3 downto 0) ); mii_tx_en <= tx_en; mii_tx(7 downto 4) <= "0000"; end behavior;