📄 eth_rx.vhd
字号:
--------------------------------------------------------------------------------- Entity: eth_rx-- File: eth_rx.vhd-- Author: Marko Isomaki-- Description: Ethernet Media Access Controller receiver module-------------------------------------------------------------------------------library ieee;library grlib;library gaisler; use ieee.std_logic_1164.all;use gaisler.ethernet_mac.all; use grlib.stdlib.all;entity eth_rx is generic( nsync : integer := 2); port( rst : in std_ulogic; eth_clk : in std_ulogic; eth_rx_in : in eth_rx_in_type; eth_rx_out : out eth_rx_out_type );end entity; architecture rtl of eth_rx is constant maxSize : std_logic_vector(10 downto 0) := conv_std_logic_vector(1518,11); constant minSize : std_logic_vector(10 downto 0) := conv_std_logic_vector(64,11); type rx_state_type is (idle, wait_sfd, data1, data2, errorst, report_status, wait_report, check_crc, discard_packet); type reg_type is record er : std_ulogic; en : std_ulogic; rxd : std_logic_vector(3 downto 0); crc : std_logic_vector(31 downto 0); sync_start : std_ulogic; start : std_ulogic; write : std_ulogic; done : std_ulogic; odd_nibble : std_ulogic; byte_count : std_logic_vector(10 downto 0); data : std_logic_vector(31 downto 0); dataout : std_logic_vector(31 downto 0); rx_state : rx_state_type; status : std_logic_vector(2 downto 0); writeerror : std_ulogic; write_ack : std_logic_vector(nsync downto 0); done_ack : std_logic_vector(nsync downto 0); rxen : std_logic_vector(1 downto 0); end record; signal r, rin : reg_type;begin comb : process(rst, eth_rx_in, r) is variable v : reg_type; variable index : integer range 0 to 3; variable crc_en : std_ulogic; variable write_req : std_ulogic; variable write_ack : std_ulogic; variable done_ack : std_ulogic; variable tc0, tc1, tc2, tc3 : std_ulogic; begin v := r; v.rxd := eth_rx_in.rxd; v.en := eth_rx_in.rx_dv; v.er := eth_rx_in.rx_er; write_req := '0'; crc_en := '0'; index := conv_integer(r.byte_count(1 downto 0)); --synchronization v.rxen(1) := r.rxen(0); v.rxen(0) := eth_rx_in.rxen; v.write_ack(0) := eth_rx_in.write_ack; v.done_ack(0) := eth_rx_in.done_ack; if nsync = 2 then v.write_ack(1) := r.write_ack(0); v.done_ack(1) := r.done_ack(0); end if; write_ack := r.write_ack(nsync) xor r.write_ack(nsync-1); done_ack := r.done_ack(nsync) xor r.done_ack(nsync-1); case r.rx_state is when idle => v.writeerror := '0'; v.status := receiveOk; v.byte_count := (others => '0'); v.odd_nibble := '0'; if (r.en and r.rxen(1)) = '1' then v.rx_state := wait_sfd; v.sync_start := not r.sync_start; elsif r.en = '1' then v.rx_state := discard_packet; end if; when discard_packet => if r.en = '0' then v.rx_state := idle; end if; when wait_sfd => if r.en = '0' then v.rx_state := idle; elsif r.rxd = "1101" then v.rx_state := data1; end if; v.start := '0'; v.crc := (others => '1'); if r.er = '1' then v.status := frameCheckError; end if; when data1 => if r.en = '1' then crc_en := '1'; v.odd_nibble := not r.odd_nibble; v.rx_state := data2; case index is when 0 => v.data(27 downto 24) := r.rxd; when 1 => v.data(19 downto 16) := r.rxd; when 2 => v.data(11 downto 8) := r.rxd; when 3 => v.data(3 downto 0) := r.rxd; end case; else v.rx_state := check_crc; end if; if (r.byte_count(1 downto 0) = "00" and r.start = '1') or (r.en = '0') then write_req := '1'; end if; if r.er = '1' then v.status := frameCheckError; end if; if r.writeerror = '1' then v.rx_state := errorst; v.status := overrun; end if; if r.byte_count > maxSize then v.rx_state := errorst; v.status := frameTooLong; end if; when data2 => if r.en = '1' then crc_en := '1'; v.odd_nibble := not r.odd_nibble; v.rx_state := data1; v.byte_count := r.byte_count + 1; v.start := '1'; case index is when 0 => v.data(31 downto 28) := r.rxd; when 1 => v.data(23 downto 20) := r.rxd; when 2 => v.data(15 downto 12) := r.rxd; when 3 => v.data(7 downto 4) := r.rxd; end case; else v.rx_state := check_crc; end if; if r.er = '1' then v.status := frameCheckError; end if; if r.writeerror = '1' then v.rx_state := errorst; v.status := overrun; end if; when check_crc => if r.crc /= X"C704DD7B" then if r.odd_nibble = '1' then v.status := alignmentError; else v.status := frameCheckError; end if; end if; if write_ack = '1' then v.rx_state := report_status; end if; if r.writeerror = '1' then v.status := overrun; end if; if r.byte_count < minSize then v.rx_state := idle; end if; when errorst => if r.en = '0' then if r.byte_count < minSize then v.rx_state := idle; else v.rx_state := report_status; end if; end if; when report_status => v.done := not r.done; v.rx_state := wait_report; when wait_report => if done_ack = '1' then v.rx_state := idle; v.done_ack(nsync) := r.done_ack(nsync-1); end if; when others => null; end case; --write to fifo if write_req = '1' then if write_ack = '0' then v.writeerror := '1'; else v.write_ack(nsync) := r.write_ack(nsync-1); v.dataout := r.data; v.write := not r.write; end if; end if; if eth_rx_in.write_ack = '1' then if eth_rx_in.writeok = '0' then v.writeerror := '1'; end if; end if; --crc generation if crc_en = '1' then --xor top nibble in crc reg with data to determine which --offsets should be xored tc0 := r.rxd(0) xor r.crc(31); tc1 := r.rxd(1) xor r.crc(30); tc2 := r.rxd(2) xor r.crc(29); tc3 := r.rxd(3) xor r.crc(28); --the lsbit is sent first which means tcd(0) is xored with crc(31) etc --dont forget to invert the resulting crc before transmitting --initial value must be 0xFFFFFFFF v.crc(31) := r.crc(27); v.crc(30) := r.crc(26); v.crc(29) := tc0 xor r.crc(25); v.crc(28) := tc1 xor r.crc(24); v.crc(27) := tc2 xor r.crc(23); v.crc(26) := tc0 xor tc3 xor r.crc(22); v.crc(25) := tc0 xor tc1 xor r.crc(21); v.crc(24) := tc1 xor tc2 xor r.crc(20); v.crc(23) := tc2 xor tc3 xor r.crc(19); v.crc(22) := tc3 xor r.crc(18); v.crc(21) := r.crc(17); v.crc(20) := r.crc(16); v.crc(19) := tc0 xor r.crc(15); v.crc(18) := tc1 xor r.crc(14); v.crc(17) := tc2 xor r.crc(13); v.crc(16) := tc3 xor r.crc(12); v.crc(15) := tc0 xor r.crc(11); v.crc(14) := tc0 xor tc1 xor r.crc(10); v.crc(13) := tc0 xor tc1 xor tc2 xor r.crc(9); v.crc(12) := tc1 xor tc2 xor tc3 xor r.crc(8); v.crc(11) := tc0 xor tc2 xor tc3 xor r.crc(7); v.crc(10) := tc0 xor tc1 xor tc3 xor r.crc(6); v.crc(9) := tc1 xor tc2 xor r.crc(5); v.crc(8) := tc0 xor tc2 xor tc3 xor r.crc(4); v.crc(7) := tc0 xor tc1 xor tc3 xor r.crc(3); v.crc(6) := tc1 xor tc2 xor r.crc(2); v.crc(5) := tc0 xor tc2 xor tc3 xor r.crc(1); v.crc(4) := tc0 xor tc1 xor tc3 xor r.crc(0); v.crc(3) := tc0 xor tc1 xor tc2; v.crc(2) := tc1 xor tc2 xor tc3; v.crc(1) := tc2 xor tc3; v.crc(0) := tc3; end if; if rst = '0' then v.rx_state := idle; v.write := '0'; v.done := '0'; v.sync_start := '0'; v.write_ack(nsync) := '1'; v.done_ack := (others => '0'); v.write_ack(nsync-1 downto 0) := (others => '0'); end if; eth_rx_out.start <= r.sync_start; eth_rx_out.done <= r.done; eth_rx_out.write <= r.write; eth_rx_out.data <= r.dataout; eth_rx_out.length <= r.byte_count; eth_rx_out.status <= r.status; rin <= v; end process; regs : process(eth_clk) is begin if rising_edge(eth_clk) then r <= rin; end if; end process;end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -