diff --git a/trashernet/trashernet_mac.vhd b/trashernet/trashernet_mac.vhd index af37594..db91d56 100644 --- a/trashernet/trashernet_mac.vhd +++ b/trashernet/trashernet_mac.vhd @@ -11,13 +11,14 @@ entity trashernet_mac is rst : in std_logic; -- Asynchronous reset -- PHY signals - rx_data : in std_logic_vector(7 downto 0); -- RX Data + rx_data : in byte; -- RX Data rx_data_valid : in std_logic; -- RX Data valid rx_active : in std_logic; -- RX of packet in progress - tx_data : out std_logic_vector(7 downto 0); -- TX Data + tx_data : out byte; -- TX Data tx_data_en : out std_logic; -- Transmitter enable tx_data_ack : in std_logic; -- Latched data_tx + tx_active : in std_logic; -- Transmitter active carrier_detect : in std_logic; -- Carrier detected rx_error : in std_logic; -- Receive error @@ -30,14 +31,19 @@ entity trashernet_mac is rx_mac_valid : out std_logic; -- `rx_mac` values (headers + data) are valid rx_mac_header_rcv : out std_logic; -- `rx_mac` header have been received and are valid rx_mac_crc_ok : out std_logic; -- End of packet, CRC OK (strobe independent from other rx_mac fields) - rx_mac_crc_error : out std_logic -- End of packet, CRC invalid + rx_mac_crc_error : out std_logic; -- End of packet, CRC invalid + + tx_mac_destination : in mac_addr_t; -- Destination MAC address + tx_mac_source : in mac_addr_t; -- Source MAC address + tx_mac_ethertype : in ethertype_t; -- Ethertype or length + tx_mac_data : in byte; -- Payload + tx_mac_data_en : in std_logic; -- Start (and keep) transmitting a frame + tx_mac_data_ack : out std_logic -- The byte on `tx_mac_data` has been latched. Update to next word. ); end entity trashernet_mac; architecture rtl of trashernet_mac is - signal crc : std_logic_vector(31 downto 0); - signal crc_ok : std_logic; - signal crc_clear : std_logic; + constant ETH_POLYNOMIAL : std_logic_vector(31 downto 0) := x"04C11DB7"; begin rx : block @@ -52,7 +58,9 @@ begin signal sr_payload : byte_vector(0 to 4); - constant ETH_POLYNOMIAL : std_logic_vector(crc'range) := x"04C11DB7"; + signal crc : std_logic_vector(ETH_POLYNOMIAL'range); + signal crc_ok : std_logic; + signal crc_clear : std_logic; begin crc_inst : entity work.crc generic map( @@ -136,4 +144,88 @@ begin end block rx; + tx : block + type tx_state_t is (IDLE, HEADER, DATA, TXCRC); + signal tx_state : tx_state_t; + + signal sr : byte_vector(0 to tx_mac_destination'length + tx_mac_source'length + tx_mac_ethertype'length - 1); + constant BIT_CNT_MAX : integer := sr'high; + signal byte_cnt : integer range 0 to BIT_CNT_MAX; + + signal crc : std_logic_vector(ETH_POLYNOMIAL'range); + signal crc_clear : std_logic; + signal crc_valid : std_logic; + begin + crc_inst : entity work.crc + generic map( + POLYNOMIAL => ETH_POLYNOMIAL, + START => x"FFFFFFFF", + FINAL_XOR => x"FFFFFFFF", + REVERSE_OUT => true + ) + port map( + clk => clk, + rst => rst, + data => tx_data, + data_valid => crc_valid, + crc_clear => crc_clear, + crc_out => crc + ); + + tx_main : process(clk, rst) is + begin + if rst then + tx_mac_data_ack <= '0'; + + elsif rising_edge(clk) then + tx_mac_data_ack <= '0'; + crc_valid <= '0'; + + if tx_data_ack then + sr <= sr(sr'low + 1 to sr'high) & x"00"; + crc_valid <= '1'; + if byte_cnt /= 0 then + byte_cnt <= byte_cnt - 1; + end if; + end if; + case tx_state is + when IDLE => + if not tx_active and tx_mac_data_en then + sr(0 to 7) <= byte_vector'(0 to 6 => x"55", 7 => x"D5"); + byte_cnt <= 7; + tx_state <= HEADER; + end if; + + when HEADER => + if (tx_data_ack = '1') and (byte_cnt = 0) then -- Sync Header TX complete + sr <= tx_mac_destination & tx_mac_source & tx_mac_ethertype; + crc_valid <= '1'; + byte_cnt <= BIT_CNT_MAX; + tx_state <= DATA; + end if; + + when DATA => + if (tx_data_ack = '1') and (byte_cnt = 0) then -- MAC Header TX complete + if tx_mac_data_en then + sr(0) <= tx_mac_data; + tx_mac_data_ack <= '1'; + else + sr(0 to 3) <= (crc(7 downto 0), crc(15 downto 8), crc(23 downto 16), crc(31 downto 24)); + byte_cnt <= 4 - 1; + tx_state <= TXCRC; + end if; + end if; + + when TXCRC => + if (tx_data_ack = '1') and (byte_cnt = 0) then -- CRC TX complete + tx_state <= IDLE; + end if; + end case; + end if; + end process tx_main; + tx_data_en <= '1' when tx_state /= IDLE else '0'; + crc_clear <= '1' when tx_state = HEADER else '0'; + tx_data <= sr(sr'low); + end block tx; + end architecture rtl;