📄 eth_tx.vhd
字号:
--------------------------------------------------------------------------------- Entity: eth_tx-- File: eth_tx.vhd-- Author: Marko Isomaki-- Description: Ethernet Media Access Controller Transmitter Module-------------------------------------------------------------------------------library ieee;use ieee.std_logic_1164.all;library gaisler;use gaisler.net.all;use gaisler.ethernet_mac.all;library grlib;use grlib.stdlib.all; entity eth_tx is generic( nsync : integer := 2; --number sync registers attempt_limit : integer := 16; --max nbr of transmit attempts backoff_limit : integer := 10; --max nbr of times to backoff slot_time : integer := 128; --number of nibbles for slot time interframe_space : integer := 24 --interframe gap ); port( rst : in std_ulogic; eth_clk : in std_ulogic; eth_tx_in : in eth_tx_in_type; eth_tx_out : out eth_tx_out_type );end entity;architecture rtl of eth_tx is constant ifg_bits : integer := log2(interframe_space); constant ifg_val : std_logic_vector(ifg_bits-1 downto 0) := conv_std_logic_vector(interframe_space-1, ifg_bits); constant ifg_part1 : std_logic_vector(ifg_bits-1 downto 0) := conv_std_logic_vector((interframe_space*2)/3, ifg_bits); constant maxattempts : std_logic_vector(4 downto 0) := conv_std_logic_vector(attempt_limit, 5); constant delay_zero : std_logic_vector(9 downto 0) := (others => '0'); constant slot_zero : std_logic_vector(6 downto 0) := (others => '0'); function mirror(din : in std_logic_vector(3 downto 0)) return std_logic_vector is variable do : std_logic_vector(3 downto 0); begin do(3) := din(0); do(2) := din(1); do(1) := din(2); do(0) := din(3); return do; end function; type tx_state_type is (idle, preamble, sfd, data1, data2, pad1, pad2, fcs, finish, calc_backoff, wait_backoff, send_jam, send_jam2, check_attempts); type def_state_type is (monitor, def_on, ifg1, ifg2, frame_waitingst); type reg_type is record --deference process def_state : def_state_type; ifg_cycls : std_logic_vector(4 downto 0); deferring : std_ulogic; was_transmitting : std_ulogic; --tx process main_state : tx_state_type; transmitting : std_ulogic; tx_en : std_ulogic; txd : std_logic_vector(3 downto 0); cnt : std_logic_vector(3 downto 0); icnt : std_logic_vector(1 downto 0); crc : std_logic_vector(31 downto 0); crc_en : std_ulogic; byte_count : std_logic_vector(10 downto 0); slot_count : std_logic_vector(6 downto 0); random : std_logic_vector(9 downto 0); delay_val : std_logic_vector(9 downto 0); retry_cnt : std_logic_vector(4 downto 0); status : std_logic_vector(1 downto 0); data : std_logic_vector(31 downto 0); --synchronization read : std_ulogic; done : std_ulogic; restart : std_ulogic; start : std_logic_vector(nsync downto 0); read_ack : std_logic_vector(nsync downto 0); crs : std_logic_vector(1 downto 0); col : std_logic_vector(1 downto 0); fullduplex : std_logic_vector(1 downto 0); end record; signal r, rin : reg_type; begin comb : process(rst, eth_tx_in, r) is variable collision : std_ulogic; variable frame_waiting : std_ulogic; variable index : integer range 0 to 7; variable start : std_ulogic; variable read_ack : std_ulogic; variable tc0, tc1, tc2 , tc3 : std_ulogic; variable v : reg_type; begin v := r; frame_waiting := '0'; collision := r.col(1) and not r.fullduplex(1); --synchronization v.col(1) := r.col(0); v.col(0) := eth_tx_in.col; v.crs(1) := r.crs(0); v.crs(0) := eth_tx_in.crs; v.fullduplex(1) := r.fullduplex(0); v.fullduplex(0) := eth_tx_in.full_duplex; v.start(0) := eth_tx_in.start; v.read_ack(0) := eth_tx_in.read_ack; if nsync = 2 then v.start(1) := r.start(0); v.read_ack(1) := r.read_ack(0); end if; start := r.start(nsync) xor r.start(nsync-1); read_ack := r.read_ack(nsync) xor r.read_ack(nsync-1); --crc generation if r.crc_en = '1' then --xor top nibble in crc reg with data to determine which --offsets should be xored tc0 := r.txd(0) xor r.crc(31); tc1 := r.txd(1) xor r.crc(30); tc2 := r.txd(2) xor r.crc(29); tc3 := r.txd(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; --main fsm case r.main_state is when idle => v.transmitting := '0'; v.read_ack(nsync) := r.read_ack(nsync-1); if (start and not r.deferring) = '1' then v.main_state := preamble; v.transmitting := '1'; v.tx_en := '1'; v.byte_count := (others => '1'); v.status := (others => '0'); v.read := not r.read; v.start(nsync) := r.start(nsync-1); elsif start = '1' then frame_waiting := '1'; end if; v.txd := "0101"; v.cnt := "1110"; when preamble => v.cnt := r.cnt - 1; if r.cnt = "0000" then v.txd := "1101"; v.main_state := sfd; end if; if collision = '1' then v.main_state := send_jam; end if; when sfd => v.main_state := data1; v.icnt := (others => '0'); v.crc_en := '1'; v.crc := (others => '1'); v.byte_count := (others => '0'); v.txd := eth_tx_in.data(27 downto 24); if collision = '1' then v.main_state := send_jam; end if; if (read_ack and eth_tx_in.valid) = '0' then v.status(0) := '1'; v.main_state := finish; v.tx_en := '0'; else v.data := eth_tx_in.data; v.read := not r.read; v.read_ack(nsync) := r.read_ack(nsync-1); end if; when data1 => index := conv_integer(r.icnt); v.byte_count := r.byte_count + 1; v.main_state := data2; v.icnt := r.icnt + 1; case index is when 0 => v.txd := r.data(31 downto 28); when 1 => v.txd := r.data(23 downto 20); when 2 => v.txd := r.data(15 downto 12); when 3 => v.txd := r.data(7 downto 4); when others => null; end case; if index = 3 then if (read_ack and eth_tx_in.valid) = '0' then v.status(0) := '1'; v.main_state := finish; v.tx_en := '0'; else v.data := eth_tx_in.data; v.read := not r.read; v.read_ack(nsync) := r.read_ack(nsync-1); end if; end if; if v.byte_count = eth_tx_in.length then v.tx_en := '1'; if conv_integer(v.byte_count) >= 60 then v.main_state := fcs; v.cnt := (others => '0'); else v.main_state := pad1; end if; end if; if collision = '1' then v.main_state := send_jam; end if; when data2 => index := conv_integer(r.icnt); v.main_state := data1; case index is when 0 => v.txd := r.data(27 downto 24); when 1 => v.txd := r.data(19 downto 16); when 2 => v.txd := r.data(11 downto 8); when 3 => v.txd := r.data(3 downto 0); when others => null; end case; if collision = '1' then v.main_state := send_jam; end if; when pad1 => v.main_state := pad2; if collision = '1' then v.main_state := send_jam; end if; when pad2 => v.byte_count := r.byte_count + 1; if conv_integer(v.byte_count) = 60 then v.main_state := fcs; v.cnt := (others => '0'); else v.main_state := pad1; end if; if collision = '1' then v.main_state := send_jam; end if; when fcs => v.cnt := r.cnt + 1; v.crc_en := '0'; index := conv_integer(r.cnt); case index is when 0 => v.txd := mirror(not v.crc(31 downto 28)); when 1 => v.txd := mirror(not r.crc(27 downto 24)); when 2 => v.txd := mirror(not r.crc(23 downto 20)); when 3 => v.txd := mirror(not r.crc(19 downto 16)); when 4 => v.txd := mirror(not r.crc(15 downto 12)); when 5 => v.txd := mirror(not r.crc(11 downto 8)); when 6 => v.txd := mirror(not r.crc(7 downto 4)); when 7 => v.txd := mirror(not r.crc(3 downto 0)); v.main_state := finish; when others => null; end case; when finish => v.tx_en := '0'; v.transmitting := '0'; v.main_state := idle; v.retry_cnt := (others => '0'); v.done := not r.done; when send_jam => v.cnt := "0110"; v.main_state := send_jam2; v.crc_en := '0'; when send_jam2 => v.cnt := r.cnt - 1; if r.cnt = "0000" then v.main_state := check_attempts; v.retry_cnt := r.retry_cnt + 1; end if; when check_attempts => if r.retry_cnt = maxattempts then v.main_state := finish; v.status(1) := '1'; else v.main_state := calc_backoff; v.restart := not r.restart; end if; v.tx_en := '0'; when calc_backoff => v.delay_val := (others => '0'); for i in 1 to backoff_limit-1 loop if i < conv_integer(r.retry_cnt)+1 then v.delay_val(i) := r.random(i); end if; end loop; v.main_state := wait_backoff; v.slot_count := (others => '1'); when wait_backoff => if r.delay_val = delay_zero then v.main_state := idle; end if; v.slot_count := r.slot_count - 1; if r.slot_count = slot_zero then v.slot_count := (others => '1'); v.delay_val := r.delay_val - 1; end if; when others => v.main_state := idle; end case; --random values; v.random := r.random(8 downto 0) & (not (r.random(2) xor r.random(9))); --deference case r.def_state is when monitor => v.was_transmitting := '0'; if ( (r.crs(1) and not r.fullduplex(1)) or (r.transmitting and r.fullduplex(1)) ) = '1' then v.deferring := '1'; v.def_state := def_on; v.was_transmitting := r.transmitting; end if; when def_on => v.was_transmitting := r.was_transmitting or r.transmitting; if r.fullduplex(1) = '1' then if r.transmitting = '0' then v.def_state := ifg1; end if; v.ifg_cycls := ifg_val; else if (r.transmitting or r.crs(1)) = '0' then v.def_state := ifg1; v.ifg_cycls := (others => '0'); end if; end if; when ifg1 => v.ifg_cycls := r.ifg_cycls + 1; if r.ifg_cycls = ifg_part1 then v.def_state := ifg2; elsif r.crs(1) = '1' then v.ifg_cycls := (others => '0'); end if; when ifg2 => v.ifg_cycls := r.ifg_cycls + 1; if r.ifg_cycls = ifg_val then v.deferring := '0'; if (r.fullduplex(1) or not frame_waiting) = '1' then v.def_state := monitor; elsif frame_waiting = '1' then v.def_state := frame_waitingst; end if; end if; when frame_waitingst => if frame_waiting = '0' then v.def_state := monitor; end if; when others => v.def_state := monitor; end case; if rst = '0' then v.main_state := idle; v.random := (others => '0'); v.def_state := monitor; v.deferring := '0'; v.tx_en := '0'; v.done := '0'; v.restart := '0'; v.read := '0'; v.start := (others => '0'); v.read_ack := (others => '0'); end if; rin <= v; eth_tx_out.done <= r.done; eth_tx_out.restart <= r.restart; eth_tx_out.read <= r.read; eth_tx_out.status <= r.status; eth_tx_out.tx_er <= '0'; eth_tx_out.tx_en <= r.tx_en; eth_tx_out.txd <= r.txd; end process; regs : process(eth_clk) is begin if rising_edge(eth_clk) then r <= rin; end if; end process;end architecture;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -