diff --git a/lib/emac/emac_jb.vhd b/lib/emac/emac_jb.vhd index 5477c33..1daca4a 100644 --- a/lib/emac/emac_jb.vhd +++ b/lib/emac/emac_jb.vhd @@ -40,46 +40,478 @@ END emac_jb; ARCHITECTURE behavior OF emac_jb IS + constant TX_RAM_ADDR_WIDTH : natural := 9; + subtype word_ptr_t is unsigned(TX_RAM_ADDR_WIDTH-1 downto 0); + -- Signals for EMAC connections - signal tx_fifo_din : unsigned(7 downto 0); - signal tx_fifo_dout : unsigned(7 downto 0); + signal tx_fifo_din : unsigned(35 downto 0); + signal tx_fifo_dout : unsigned(35 downto 0); signal tx_fifo_we : std_logic; signal tx_fifo_re : std_logic; signal tx_fifo_empty : std_logic; - signal rx_fifo_din : unsigned(7 downto 0); - signal rx_fifo_dout : unsigned(7 downto 0); - signal rx_fifo_we : std_logic; - signal rx_fifo_re : std_logic; - signal rx_fifo_empty : std_logic; - signal rx_busy : std_logic; - signal tx_busy : std_logic; + signal tx_fifo_full : std_logic; signal rx_int_en : std_logic; signal tx_int_en : std_logic; signal irq_rx : std_logic; signal irq_tx : std_logic; - signal tx_trig : std_logic; - signal rx_trig : std_logic; signal tx_err : std_logic; - signal tx_size : unsigned(15 downto 0); - signal rx_size : unsigned(15 downto 0); - signal tx_counter : unsigned(15 downto 0); - signal rx_counter : unsigned(15 downto 0); + + signal tx_flush_en : std_logic; + signal tx_flush_rdy : std_logic; + signal tx_flush_ptr_set : std_logic; + + signal tx_commit_en : std_logic; + signal tx_flush_ptr : word_ptr_t; + + signal host_data_we : std_logic; + signal host_data_reg : unsigned(31 downto 0); + signal host_tx_size : unsigned(15 downto 0); + + signal tx_fill_cnt : word_ptr_t; + signal tx_fill_ptr : word_ptr_t; + signal tx_fill_rdy : std_logic; + signal tx_fill_cnt_set : std_logic; + signal tx_fill_cnt_adv : std_logic; + signal tx_fill_ptr_adv : std_logic; + + signal tx_alloc_OK : std_logic; + signal tx_alloc_req_en : std_logic; + signal tx_alloc_req : std_logic; + signal tx_alloc_ack : std_logic; + + signal tx_nwords_free : word_ptr_t; + signal tx_alloc_base : word_ptr_t; + signal tx_alloc_size : word_ptr_t; + signal tx_alloc_en : std_logic; + + signal tx_free_en : std_logic; + signal tx_uncommit_en : std_logic; + signal tx_host_size_adj : word_ptr_t; + signal tx_fill_remain : unsigned(1 downto 0); + + signal tx_xfer_size : word_ptr_t; + signal tx_xfer_ptr : word_ptr_t; + signal tx_xfer_cnt : word_ptr_t; + signal tx_xfer_en : std_logic; + signal tx_xfer_ptr_set : std_logic; + signal tx_xfer_ptr_adv : std_logic; + signal tx_xfer_cnt_set : std_logic; + signal tx_xfer_cnt_adv : std_logic; + signal tx_xfer_rdy : std_logic; + signal xfer_tag : unsigned(3 downto 0); + signal xfer_remain : unsigned(1 downto 0); + signal xfer_odd : std_logic; + signal xfer_remain_en : std_logic; + + signal tx_ram_en_a : std_logic; + signal tx_ram_we_a : std_logic; + signal tx_ram_addr_a : unsigned(TX_RAM_ADDR_WIDTH-1 downto 0); + signal tx_ram_din_a : unsigned(35 downto 0); + signal tx_ram_dout_a : unsigned(35 downto 0); + signal tx_ram_en_b : std_logic; + signal tx_ram_we_b : std_logic; + signal tx_ram_addr_b : unsigned(TX_RAM_ADDR_WIDTH-1 downto 0); + signal tx_ram_din_b : unsigned(35 downto 0); + signal tx_ram_dout_b : unsigned(35 downto 0); + + signal piso_din_be : unsigned(3 downto 0); + signal piso_din_rdy : std_logic; + signal tx_data_vld : std_logic; + + subtype inter_frame_gap_cnt_t is natural range 0 to natural(10.0*f_sysclk)-1; + signal inter_frame_gap_cnt : inter_frame_gap_cnt_t; + signal inter_frame_gap_rdy : std_logic; + + alias tx_ram_data_in_a is tx_ram_din_a(31 downto 0); + alias tx_ram_tag_in_a is tx_ram_din_a(35 downto 32); + alias tx_ram_data_out_a is tx_ram_dout_a(31 downto 0); + alias tx_ram_tag_out_a is tx_ram_dout_a(35 downto 32); + + alias tx_ram_data_in_b is tx_ram_din_b(31 downto 0); + alias tx_ram_tag_in_b is tx_ram_din_b(35 downto 32); + alias tx_ram_data_out_b is tx_ram_dout_b(31 downto 0); + alias tx_ram_tag_out_b is tx_ram_dout_b(35 downto 32); + + type host_tx_state_t is (host_tx_init, host_tx_flush, host_tx_idle, host_tx_alloc, host_tx_setup, host_tx_arm, host_tx_fill, host_tx_commit); + signal host_tx_s, host_tx_sn : host_tx_state_t; + + type xfer_tx_state_t is (xfer_tx_init, xfer_tx_idle, xfer_tx_setup, xfer_wait, xfer_tx_active, xfer_tx_free); + signal xfer_tx_s, xfer_tx_sn : xfer_tx_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", + "0001", + "0011", + "0111" + ); + begin - SRDY_O <= CYC_I; - INT_O <= irq_rx or irq_tx; - mii_gtx_clk <= '0'; - mii_tx_er <= tx_err; + SRDY_O <= CYC_I; + INT_O <= irq_rx or irq_tx; + mii_gtx_clk <= '0'; + mii_tx_er <= tx_err; + + tx_ram_tag_in_b <= "0000"; + tx_ram_en_b <= '1'; + tx_ram_we_b <= tx_uncommit_en or tx_flush_en; + tx_ram_addr_b <= tx_flush_ptr when (tx_flush_en = '1' or tx_uncommit_en = '1') else tx_xfer_ptr; + xfer_tag <= tx_ram_tag_out_b; + + tx_ram_en_a <= '1'; + tx_ram_we_a <= tx_commit_en or tx_fill_cnt_adv; + tx_ram_tag_in_a <= tx_fill_remain & "01" when tx_commit_en = '1' else "0000"; + tx_ram_data_in_a <= resize(tx_host_size_adj, 16) & resize(tx_alloc_base, 16) when tx_commit_en = '1' else host_data_reg; + tx_ram_addr_a <= tx_alloc_base when tx_commit_en = '1' else tx_fill_ptr; + + piso_din_be <= (others => '1'); + tx_fifo_re <= piso_din_rdy; + tx_data_vld <= not tx_fifo_empty; + + tx_fifo_din(35 downto 32) <= piso_byte_mask_rom(to_integer(xfer_remain)) when xfer_remain_en = '1' else "1111"; + tx_fifo_din(31 downto 0) <= tx_ram_data_out_b; + +------------------------------------------------------------------ +host_tx_state_next: + process(CLK_I) + begin + if rising_edge(CLK_I) then + if RST_I = '1' then + host_tx_s <= host_tx_init; + else + host_tx_s <= host_tx_sn; + end if; + end if; + end process; + +host_tx_state: + process(host_tx_s, tx_flush_rdy, tx_alloc_req, tx_alloc_OK, tx_fill_rdy, host_data_we) + begin + + tx_flush_en <= '0'; + tx_flush_ptr_set <= '0'; + tx_alloc_ack <= '0'; + tx_fill_cnt_set <= '0'; + tx_fill_ptr_adv <= '0'; + tx_commit_en <= '0'; + tx_alloc_en <= '0'; + + host_tx_sn <= host_tx_s; + + case host_tx_s is + + when host_tx_init => + tx_flush_ptr_set <= '1'; + host_tx_sn <= host_tx_flush; + + when host_tx_flush => + tx_flush_en <= '1'; + if tx_flush_rdy = '1' then + tx_flush_en <= '0'; + host_tx_sn <= host_tx_idle; + end if; + + when host_tx_idle => + if tx_alloc_req = '1' then + host_tx_sn <= host_tx_alloc; + end if; + + when host_tx_alloc => + if tx_alloc_OK = '1' then + host_tx_sn <= host_tx_setup; + tx_alloc_ack <= '1'; + end if; + + when host_tx_setup => + tx_fill_cnt_set <= '1'; + host_tx_sn <= host_tx_arm; + + when host_tx_arm => + tx_fill_ptr_adv <= '1'; + tx_fill_cnt_adv <= '1'; + host_tx_sn <= host_tx_fill; + + when host_tx_fill => + tx_fill_cnt_adv <= host_data_we; + tx_fill_ptr_adv <= not tx_fill_rdy and host_data_we; + if tx_fill_rdy = '1' then + host_tx_sn <= host_tx_commit; + end if; + + when host_tx_commit => + tx_commit_en <= '1'; + tx_alloc_en <= '1'; + host_tx_sn <= host_tx_idle; + + when others => + host_tx_sn <= host_tx_idle; + end case; + + end process; + +------------------------------------------------------------------ +-- Allocation stuff +------------------------------------------------------------------ +alloc_request_logic: + process(CLK_I) + begin + if rising_edge(CLK_I) then + if RST_I = '1' then + tx_alloc_req <= '0'; + elsif tx_alloc_req_en = '1' and tx_alloc_req = '0' then + tx_alloc_req <= '1'; + tx_fill_remain <= host_tx_size(1 downto 0); + tx_host_size_adj <= host_tx_size(word_ptr_t'left+2 downto 2); + if host_tx_size(1 downto 0) /= "00" then + tx_host_size_adj <= host_tx_size(word_ptr_t'left+2 downto 2) + 1; + end if; + elsif tx_alloc_ack = '1' then + tx_alloc_req <= '0'; + tx_alloc_size <= tx_host_size_adj; + end if; + end if; + end process; + +------------------------------------------------------------------ +alloc_base_logic: + process(CLK_I) + begin + if rising_edge(CLK_I) then + if tx_flush_en = '1' then + tx_alloc_base <= (others => '0'); + elsif tx_commit_en = '1' then + tx_alloc_base <= tx_fill_ptr; + end if; + end if; + end process; + +------------------------------------------------------------------ +alloc_eval_logic: + process(CLK_I) + begin + if rising_edge(CLK_I) then + tx_alloc_OK <= '0'; + if tx_alloc_req = '1' then + if tx_host_size_adj < tx_nwords_free then + tx_alloc_OK <= '1'; + end if; + end if; + end if; + end process; + +------------------------------------------------------------------ +tx_nwords_free_counter: + process(CLK_I) + begin + if rising_edge(CLK_I) then + if tx_flush_en = '1' then + tx_nwords_free <= (others => '1'); + elsif tx_alloc_en = '1' then + tx_nwords_free <= tx_nwords_free - tx_host_size_adj; + elsif tx_free_en = '1' then + tx_nwords_free <= tx_nwords_free + tx_xfer_size; + end if; + end if; + end process; + +------------------------------------------------------------------ +tx_flush_counter: + process(CLK_I) + begin + if rising_edge(CLK_I) then + if tx_flush_en = '0' then + tx_flush_rdy <= '0'; + if tx_flush_ptr_set = '1' then + tx_flush_ptr <= (others => '1'); + elsif tx_xfer_ptr_set = '1' then + tx_flush_ptr <= tx_ram_data_out_b(tx_flush_ptr'left downto 0); + end if; + elsif tx_flush_ptr /= 0 then + tx_flush_ptr <= tx_flush_ptr - 1; + else + tx_flush_rdy <= '1'; + end if; + end if; + end process; + +------------------------------------------------------------------ +-- Fill stuff +------------------------------------------------------------------ +tx_fill_counter: + process(CLK_I) + begin + if rising_edge(CLK_I) then + if tx_fill_cnt_set = '1' then + tx_fill_rdy <= '0'; + tx_fill_cnt <= tx_alloc_size; + elsif tx_fill_cnt_adv = '1' then + if tx_fill_cnt /= 0 then + tx_fill_cnt <= tx_fill_cnt - 1; + else + tx_fill_rdy <= '1'; + end if; + end if; + end if; + end process; + +tx_fill_pointer: + process(CLK_I) + begin + if rising_edge(CLK_I) then + if tx_flush_en = '1' then + tx_fill_ptr <= (others => '0'); + elsif tx_fill_ptr_adv = '1' then + tx_fill_ptr <= tx_fill_ptr + 1; + end if; + end if; + end process; + +------------------------------------------------------------------ +-- Transfer stuff +------------------------------------------------------------------ +xfer_tx_state_next: + process(CLK_I) + begin + if rising_edge(CLK_I) then + if RST_I = '1' then + xfer_tx_s <= xfer_tx_init; + else + xfer_tx_s <= xfer_tx_sn; + end if; + end if; + end process; + +xfer_tx_state: + process(xfer_tx_s, xfer_tag, xfer_odd, tx_xfer_rdy, inter_frame_gap_rdy, tx_alloc_en, tx_fifo_full) + begin + + tx_xfer_cnt_set <= '0'; + tx_xfer_cnt_adv <= '0'; + tx_xfer_ptr_set <= '0'; + tx_xfer_ptr_adv <= '0'; + tx_xfer_en <= '0'; + xfer_remain_en <= '0'; + tx_free_en <= '0'; + tx_uncommit_en <= '0'; + + xfer_tx_sn <= xfer_tx_s; + + case xfer_tx_s is + + when xfer_tx_init => + xfer_tx_sn <= xfer_tx_idle; + + when xfer_tx_idle => + if xfer_tag(0) = '1' then + tx_xfer_ptr_set <= '1'; + tx_xfer_cnt_set <= '1'; + xfer_tx_sn <= xfer_wait; + end if; + + when xfer_wait => + if inter_frame_gap_rdy = '1' then + xfer_tx_sn <= xfer_tx_setup; + end if; + + when xfer_tx_setup => + tx_uncommit_en <= '1'; + tx_xfer_ptr_adv <= '1'; + tx_xfer_cnt_adv <= '1'; + xfer_tx_sn <= xfer_tx_active; + + when xfer_tx_active => + tx_xfer_en <= '1'; + tx_xfer_cnt_adv <= not tx_fifo_full; + tx_xfer_ptr_adv <= not tx_fifo_full; + if tx_xfer_rdy = '1' then + xfer_remain_en <= xfer_odd; + tx_xfer_en <= '0'; + tx_xfer_cnt_adv <= '0'; + tx_xfer_ptr_adv <= '0'; + xfer_tx_sn <= xfer_tx_free; + end if; + + when xfer_tx_free => + tx_free_en <= not tx_alloc_en; + if tx_alloc_en = '0' then + xfer_tx_sn <= xfer_tx_idle; + end if; + + when others => + xfer_tx_sn <= xfer_tx_idle; + end case; + + end process; + +------------------------------------------------------------------ +interframe_gap_counter: + process(CLK_I) + begin + if rising_edge(CLK_I) then + if tx_flush_en = '1' then + inter_frame_gap_rdy <= '1'; + elsif tx_fifo_empty = '0' then + inter_frame_gap_rdy <= '0'; + inter_frame_gap_cnt <= inter_frame_gap_cnt_t'high; + elsif inter_frame_gap_cnt /= 0 then + inter_frame_gap_cnt <= inter_frame_gap_cnt - 1; + else + inter_frame_gap_rdy <= '1'; + end if; + end if; + end process; + +------------------------------------------------------------------ +tx_xfer_counter: + process(CLK_I) + begin + if rising_edge(CLK_I) then + if tx_xfer_cnt_set = '1' then + tx_xfer_size <= (others => '0'); + tx_xfer_rdy <= '0'; + tx_xfer_cnt <= tx_ram_data_out_b(tx_xfer_ptr'left+16 downto 16); + elsif tx_xfer_cnt_adv = '1' then + if tx_xfer_cnt /= 0 then + tx_xfer_cnt <= tx_xfer_cnt - 1; + tx_xfer_size <= tx_xfer_size + 1; + else + tx_xfer_rdy <= '1'; + end if; + end if; + end if; + + end process; + +tx_xfer_pointer: + process(CLK_I) + begin + if rising_edge(CLK_I) then + tx_fifo_we <= tx_xfer_en; + if tx_xfer_ptr_set = '1' then + tx_xfer_ptr <= tx_ram_data_out_b(tx_xfer_ptr'left downto 0); + xfer_remain <= xfer_tag(3 downto 2); + xfer_odd <= '0'; + if xfer_tag(3 downto 2) /= "00" then + xfer_odd <= '1'; + end if; + elsif tx_xfer_ptr_adv = '1' then + tx_xfer_ptr <= tx_xfer_ptr + 1; + end if; + end if; + + end process; ------------------------------------------------------------------ registers_write: process(CLK_I) begin if rising_edge(CLK_I) then - tx_fifo_we <= '0'; - tx_trig <= '0'; - rx_trig <= '0'; + host_data_we <= '0'; + tx_alloc_req_en <= '0'; if RST_I = '1' then rx_int_en <= '0'; tx_int_en <= '0'; @@ -88,19 +520,19 @@ registers_write: case ADDR_I(5 downto 2) is when "0000" => - tx_err <= DAT_I(31); - tx_int_en <= DAT_I(5); - rx_int_en <= DAT_I(4); - tx_trig <= DAT_I(1); - rx_trig <= DAT_I(0); + tx_err <= DAT_I(31); + tx_alloc_req_en <= DAT_I(16); + tx_int_en <= DAT_I(5); + rx_int_en <= DAT_I(4); when "0001" => - rx_size <= DAT_I(15 downto 0); - tx_size <= DAT_I(31 downto 16); + if tx_alloc_req = '0' then + host_tx_size <= DAT_I(31 downto 16); + end if; when "0010" => - tx_fifo_we <= '1'; - tx_fifo_din <= DAT_I(7 downto 0); + host_data_we <= '1'; + host_data_reg <= DAT_I; when others => null; end case; @@ -112,7 +544,6 @@ registers_read: process(CLK_I) begin if rising_edge(CLK_I) then - rx_fifo_re <= '0'; ACK_O <= '0'; if (STB_I and CYC_I) = '1' then ACK_O <= not WE_I; @@ -124,18 +555,14 @@ registers_read: DAT_O(30) <= mii_rx_er; DAT_O(29) <= mii_col; DAT_O(28) <= mii_crs; + DAT_O(16) <= tx_alloc_req; DAT_O(5) <= tx_int_en; DAT_O(4) <= rx_int_en; - DAT_O(1) <= tx_busy; - DAT_O(0) <= rx_busy; when "0001" => - DAT_O(15 downto 0) <= rx_size; - DAT_O(31 downto 16) <= tx_size; + DAT_O(31 downto 16) <= host_tx_size; when "0010" => - rx_fifo_re <= not WE_I; - DAT_O(7 downto 0) <= rx_fifo_dout; when others => null; end case; @@ -143,12 +570,34 @@ registers_read: end if; end process; +inst_tx_ram : entity work.dpram_2w2r + GENERIC MAP + ( + addr_width => TX_RAM_ADDR_WIDTH, + data_width => 36 + ) + PORT MAP + ( + clk_a => CLK_I, + clk_b => CLK_I, + en_a => tx_ram_en_a, + en_b => tx_ram_en_b, + we_a => tx_ram_we_a, + we_b => tx_ram_we_b, + addr_a => tx_ram_addr_a, + addr_b => tx_ram_addr_b, + din_a => tx_ram_din_a, + din_b => tx_ram_din_b, + dout_a => tx_ram_dout_a, + dout_b => tx_ram_dout_b + ); + -- Instantiate synchronous FIFO inst_tx_fifo: entity work.fifo_async GENERIC MAP ( - addr_width => 12, - data_width => 8, + addr_width => 5, + data_width => 36, do_last_read_update => true ) PORT MAP @@ -158,7 +607,7 @@ inst_tx_fifo: entity work.fifo_async clk_r => mii_tx_clk, we => tx_fifo_we, re => tx_fifo_re, - fifo_full => open, + fifo_full => tx_fifo_full, fifo_empty => tx_fifo_empty, fifo_afull => open, fifo_aempty => open, @@ -166,39 +615,25 @@ inst_tx_fifo: entity work.fifo_async data_r => tx_fifo_dout ); -tx_data_out: - process(mii_tx_clk) - begin - if rising_edge(mii_tx_clk) then - mii_tx <= tx_fifo_dout; - tx_fifo_re <= tx_busy; - mii_tx_en <= not tx_fifo_empty and tx_fifo_re; - end if; - end process; - -tx_busy_logic: - process(CLK_I) - begin - if rising_edge(CLK_I) then - if RST_I = '1' then - tx_busy <= '0'; - elsif tx_trig = '1' then - tx_busy <= '1'; - elsif tx_fifo_empty = '1' then - tx_busy <= '0'; - end if; - end if; - end process; - -rx_busy_logic: - process(CLK_I) - begin - if rising_edge(CLK_I) then - if RST_I = '1' then - rx_busy <= '1'; - end if; - end if; - end process; +inst_piso : entity work.piso + GENERIC MAP + ( + data_width_in => 32, + data_width_out => 8, + msb_first => false + ) + PORT MAP + ( + rst => RST_I, + clk => mii_tx_clk, + din_vld => tx_data_vld, + din_rdy => piso_din_rdy, + din_be => tx_fifo_dout(35 downto 32), + din => tx_fifo_dout(31 downto 0), + dout_en => mii_tx_en, + dout => mii_tx + + ); irq_register: process(CLK_I) diff --git a/lib/emac/src/tb_emac_jb.vhd b/lib/emac/src/tb_emac_jb.vhd index 9ea0f66..e156215 100644 --- a/lib/emac/src/tb_emac_jb.vhd +++ b/lib/emac/src/tb_emac_jb.vhd @@ -32,7 +32,7 @@ END tb_emac_jb; ARCHITECTURE behavior OF tb_emac_jb IS constant CLK_PERIOD : time := 10 ns; - constant MII_CLK_PERIOD : time := 40 ns; + constant MII_CLK_PERIOD : time := 8 ns; signal CLK : std_logic := '1'; signal RST : std_logic := '1'; @@ -48,6 +48,7 @@ ARCHITECTURE behavior OF tb_emac_jb IS 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 => '-'); -- MII signals signal mii_rx_clk_board : std_logic := '1'; @@ -64,7 +65,29 @@ ARCHITECTURE behavior OF tb_emac_jb IS signal mii_col : std_logic := '0'; signal mii_gtx_clk : std_logic; + signal shift_sa : integer := 0; + signal shift_din_vld : std_logic := '0'; + signal shift_din : unsigned(31 downto 0) := (others => '-'); + signal shift_dout_vld : std_logic; + signal shift_dout : unsigned(31 downto 0); + signal piso_din_vld : std_logic := '0'; + signal piso_din_rdy : std_logic; + signal piso_din_be : unsigned(7 downto 0) := (others => '0'); + signal piso_din : unsigned(31 downto 0) := (others => '-'); + signal piso_dout_en : std_logic; + signal piso_dout : unsigned(3 downto 0); + + signal sipo_enable : std_logic := '0'; + signal sipo_din_en : std_logic := '0'; + signal sipo_din : unsigned(3 downto 0) := (others => '-'); + signal sipo_dout_vld : std_logic; + signal sipo_dout_be : unsigned(7 downto 0); + signal sipo_dout : unsigned(31 downto 0); + + type emac_action_t is (emac_idle, emac_alloc, emac_write, emac_read); + signal emac_action : emac_action_t; + BEGIN inst_emac_jb : entity work.emac_jb @@ -101,6 +124,67 @@ inst_emac_jb : entity work.emac_jb ); +inst_shifter : entity work.shifter + GENERIC MAP + ( + data_width => 32, + aggregate_size => 4, + do_pipelined => true + ) + PORT MAP + ( + rst => RST, + clk => CLK, + sa => shift_sa, + din_vld => shift_din_vld, + din => shift_din, + dout_vld => shift_dout_vld, + dout => shift_dout + + ); + +inst_piso : entity work.piso + GENERIC MAP + ( + data_width_in => 32, + data_width_out => 4, + msb_first => true + ) + PORT MAP + ( + rst => RST, + clk => CLK, + din_vld => piso_din_vld, + din_rdy => piso_din_rdy, + din_be => piso_din_be, + din => piso_din, + dout_en => piso_dout_en, + dout => piso_dout + + ); + +inst_sipo : entity work.sipo + GENERIC MAP + ( + data_width_in => 4, + data_width_out => 32, + msb_first => true + ) + PORT MAP + ( + rst => RST, + clk => CLK, + enable => sipo_enable, + din_en => sipo_din_en, + din => sipo_din, + dout_be => sipo_dout_be, + dout_vld => sipo_dout_vld, + dout => sipo_dout + + ); + sipo_din <= piso_dout; + sipo_din_en <= piso_dout_en; + CLK_GEN: process begin wait for CLK_PERIOD/2; @@ -110,48 +194,219 @@ CLK_GEN: process MII_CLK_GEN: process begin wait for MII_CLK_PERIOD/2; - mii_rx_clk <= not mii_rx_clk after 3000 ps; - mii_tx_clk <= not mii_tx_clk after 3000 ps; + mii_rx_clk <= not mii_rx_clk; + mii_tx_clk <= not mii_tx_clk; end process; - mii_rx_clk_board <= mii_rx_clk after 3000 ps; - mii_tx_clk_board <= mii_tx_clk after 3000 ps; + 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; + -- Master STIMULUS: process + procedure emac_alloc (size : natural) is begin - - wait for 6*CLK_PERIOD; - RST <= '0'; - wait for 60*CLK_PERIOD; - - -- FILL TX data + + -- TX-ALLOCATION + -- set TX-size + emac_action <= emac_alloc; CYC_I <= '1'; wait until rising_edge(CLK) and SRDY_O = '1'; - DAT_I <= X"0000_0001"; - ADDR_I <= X"0000_0008"; + DAT_I <= to_unsigned(size, 16) & X"55AA"; + STB_I <= '1'; WE_I <= '1'; - for i in 0 to 240 loop - STB_I <= '1'; - wait until rising_edge(CLK) and SRDY_O = '1'; - DAT_I <= DAT_I + 1; - end loop; - + ADDR_I <= X"0000_0004"; wait until rising_edge(CLK) and SRDY_O = '1'; STB_I <= '0'; - -- Trigger TX + -- set alloc request CYC_I <= '1'; wait until rising_edge(CLK) and SRDY_O = '1'; - DAT_I <= X"0000_0002"; + DAT_I <= X"0001_0000"; STB_I <= '1'; WE_I <= '1'; ADDR_I <= X"0000_0000"; wait until rising_edge(CLK) and SRDY_O = '1'; STB_I <= '0'; + WE_I <= '0'; + -- check alloc busy + check_bsy: + while (true) loop + CYC_I <= '1'; + wait until rising_edge(CLK) and SRDY_O = '1'; + STB_I <= '1'; + ADDR_I <= X"0000_0000"; + wait until rising_edge(CLK) and SRDY_O = '1'; + STB_I <= '0'; + wait until rising_edge(CLK) and ACK_O = '1'; + wait until rising_edge(CLK); + if DAT_O_reg(16) = '0' then + exit check_bsy; + end if; + end loop; + emac_action <= emac_idle; + + end procedure emac_alloc; + + 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 <= X"0000_0008"; + 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_action <= emac_idle; + + end procedure emac_write; + + begin + + wait for 6*MII_CLK_PERIOD; + RST <= '0'; + wait for 60*CLK_PERIOD; + + emac_alloc (1536); + emac_write (1536); + + emac_alloc (1536); + emac_write (1536); + + emac_alloc (1536); + emac_write (1536); + + emac_alloc (64); + emac_write (64); + + emac_alloc (512); + emac_write (512); + + emac_alloc (1536); + emac_write (1536); + + emac_alloc (65); + emac_write (65); + + emac_alloc (66); + emac_write (66); + + emac_alloc (67); + emac_write (67); + + emac_alloc (512); + emac_write (512); + + wait for 4000*CLK_PERIOD; + + wait until rising_edge(CLK); + shift_din <= X"12345678"; + shift_sa <= 0; + shift_din_vld <= '1'; + wait until rising_edge(CLK); + shift_sa <= shift_sa + 1; + wait until rising_edge(CLK); + shift_sa <= shift_sa + 1; + wait until rising_edge(CLK); + shift_sa <= shift_sa + 1; + wait until rising_edge(CLK); + shift_sa <= shift_sa + 1; + wait until rising_edge(CLK); + shift_sa <= shift_sa + 1; + wait until rising_edge(CLK); + shift_sa <= shift_sa + 1; + wait until rising_edge(CLK); + shift_sa <= shift_sa + 1; + wait until rising_edge(CLK); + + shift_sa <= 0; + wait until rising_edge(CLK); + shift_sa <= shift_sa - 1; + wait until rising_edge(CLK); + shift_sa <= shift_sa - 1; + wait until rising_edge(CLK); + shift_sa <= shift_sa - 1; + wait until rising_edge(CLK); + shift_sa <= shift_sa - 1; + wait until rising_edge(CLK); + shift_sa <= shift_sa - 1; + wait until rising_edge(CLK); + shift_sa <= shift_sa - 1; + wait until rising_edge(CLK); + shift_sa <= shift_sa - 1; + + wait until rising_edge(CLK); + shift_din_vld <= '0'; + + + for i in 1 to 10 loop + + wait until rising_edge(CLK); + sipo_enable <= '1'; + piso_din_vld <= '1'; + piso_din <= X"12345678"; + piso_din_be <= "11111111"; + wait until rising_edge(CLK) and piso_din_rdy = '1'; + piso_din <= piso_din + X"12345678"; + piso_din_be <= "11100111"; + wait until rising_edge(CLK) and piso_din_rdy = '1'; + piso_din <= piso_din + X"12345678"; + piso_din_be <= "11111100"; + wait until rising_edge(CLK) and piso_din_rdy = '1'; + piso_din <= piso_din + X"12345678"; + piso_din_be <= "00111111"; + wait until rising_edge(CLK) and piso_din_rdy = '1'; + piso_din <= (others => '-'); + piso_din_vld <= '0'; + + + wait until rising_edge(CLK) and sipo_dout_vld = '1'; + wait until rising_edge(CLK); + wait until rising_edge(CLK) and sipo_dout_vld = '1'; + + sipo_enable <= '0'; + + wait for 33*CLK_PERIOD; + + end loop; + wait; end process;