Skip to content
Snippets Groups Projects
Commit 3a13405c authored by Tomasz Wlostowski's avatar Tomasz Wlostowski
Browse files

wr_endpoint: ep_tx_framer.vhd: WB-compatible version with 802.1q egress...

wr_endpoint: ep_tx_framer.vhd: WB-compatible version with 802.1q egress untagging (not fully tested)
parent 1ecf0401
Branches
Tags
No related merge requests found
......@@ -6,7 +6,7 @@
-- Author : Tomasz Wlostowski
-- Company : CERN BE-CO-HT
-- Created : 2009-06-22
-- Last update: 2011-07-12
-- Last update: 2011-08-15
-- Platform : FPGA-generic
-- Standard : VHDL'87
-------------------------------------------------------------------------------
......@@ -32,6 +32,7 @@ use ieee.numeric_std.all;
library work;
use work.gencores_pkg.all;
use work.genram_pkg.all;
use work.wr_fabric_pkg.all;
use work.endpoint_private_pkg.all;
use work.ep_wbgen2_pkg.all;
......@@ -102,7 +103,7 @@ architecture behavioral of ep_tx_framer is
constant c_IFG_LENGTH : integer := 8;
type t_tx_framer_state is (TXF_IDLE, TXF_HEADER, TXF_DATA, TXF_OOB, TXF_WAIT_CRC, TXF_EMBED_CRC1, TXF_EMBED_CRC2, TXF_EMBED_CRC3, TXF_GAP, TXF_PAD, TXF_ABORT);
type t_tx_framer_state is (TXF_IDLE, TXF_ADDR, TXF_PAUSE, TXF_QHEADER, TXF_DATA, TXF_OOB, TXF_WAIT_CRC, TXF_EMBED_CRC1, TXF_EMBED_CRC2, TXF_EMBED_CRC3, TXF_GAP, TXF_PAD, TXF_ABORT);
-- general signals
signal state : t_tx_framer_state;
......@@ -146,13 +147,10 @@ architecture behavioral of ep_tx_framer is
signal snk_out : t_wrf_sink_out;
signal abort_now : std_logic;
type t_header_processor_rval is record
next_state : t_tx_framer_state;
sof : std_logic;
data : std_logic_vector(15 downto 0);
valid : std_logic;
end record;
signal stall_int : std_logic;
signal stall_int_d0: std_logic;
signal untagging : std_logic;
function b2s (x : boolean)
......@@ -164,92 +162,46 @@ architecture behavioral of ep_tx_framer is
return '0';
end if;
end function;
signal vut_rd_vid : integer;
signal vut_wr_vid : integer;
signal vut_untag : std_logic;
signal vut_is_802_1q : std_logic;
signal vut_stored_tag : std_logic_vector(15 downto 0);
signal vut_stored_ethertype : std_logic_vector(15 downto 0);
impure function f_process_packet_header(
snk : t_wrf_sink_in;
offset : unsigned(3 downto 0);
has_mac : std_logic;
is_pause : std_logic;
pause_delay : std_logic_vector(15 downto 0)
) return t_header_processor_rval is
variable rv : t_header_processor_rval;
begin
begin -- behavioral
rv.next_state := TXF_HEADER;
-- pause frame generation
if(is_pause = '1') then
rv.valid := '1';
case offset is
when x"0" =>
rv.sof := '1';
rv.data := x"0180";
when x"1"=>
rv.sof := '0';
rv.data := x"c200";
when x"2" =>
rv.data := x"0001";
when x"3" =>
rv.data := regs_b.mach_o;
when x"4" =>
rv.data := regs_b.macl_o(31 downto 16);
when x"5" =>
rv.data := regs_b.macl_o(15 downto 0);
when x"6" =>
rv.data := x"8808";
when x"7" =>
rv.data := pause_delay;
rv.next_state := TXF_PAD;
when others => null;
end case;
else
-- SRC MAC insertion, VLAN stuff
rv.valid := '1';
case offset is
when x"0" =>
rv.sof := '1';
rv.data := snk.dat;
when x"1" =>
rv.sof := '1';
rv.data := snk.dat;
when x"2" =>
rv.data := snk.dat;
when x"3" =>
if(has_mac = '0') then
rv.data := regs_b.mach_o;
else
rv.data := snk.dat;
end if;
when x"4" =>
if(has_mac = '0') then
rv.data := regs_b.macl_o(31 downto 16);
else
rv.data := snk.dat;
end if;
when x"5" =>
if(has_mac = '0') then
rv.data := regs_b.macl_o(15 downto 0);
else
rv.data := snk.dat;
end if;
-- no VLAN tagging support - just treat the eventual 802.1q header as
-- a payload
-- if (not g_with_vlans) then
rv.next_state := TXF_DATA;
-- end if;
when others => null;
end case;
end if;
return rv;
end function;
-----------------------------------------------------------------------------
-- VLAN Functionality
-----------------------------------------------------------------------------
gen_with_vlans : if(g_with_vlans) generate
begin -- behavioral
vut_rd_vid <= to_integer(unsigned(snk_i.dat(11 downto 0)));
vut_wr_vid <= to_integer(unsigned(regs_b.vcr1_vid_o));
p_untagged_set_access : process(clk_sys_i)
variable vut_set : std_logic_vector(4095 downto 0);
begin
if rising_edge(clk_sys_i) then
if(regs_b.vcr1_value_wr_o = '1') then
vut_set(vut_wr_vid) := regs_b.vcr1_value_o;
end if;
if(snk_valid = '1') then
vut_untag <= vut_set(vut_rd_vid);
end if;
end if;
end process;
end generate gen_with_vlans;
regs_b <= c_ep_registers_init_value;
crc_gen_reset <= '1' when rst_n_i = '0' else ((sof_p1 and (not tx_pause_mode)) or crc_gen_force_reset);
......@@ -274,6 +226,7 @@ begin -- behavioral
match_o => open,
crc_o => crc_value);
p_detect_frame : process(clk_sys_i)
begin
if rising_edge(clk_sys_i) then
......@@ -287,7 +240,7 @@ begin -- behavioral
sof_p1 <= not snk_cyc_d0 and snk_i.cyc;
eof_p1 <= snk_cyc_d0 and not snk_i.cyc;
snk_valid <= (snk_i.cyc and snk_i.stb and snk_i.we and not snk_out.stall);
snk_valid <= (snk_i.cyc and snk_i.stb and snk_i.we) and not stall_int;
decoded_status <= f_unmarshall_wrf_status(snk_i.dat);
......@@ -302,8 +255,8 @@ begin -- behavioral
if rst_n_i = '0' then
stored_status.has_smac <= '0';
stored_status.is_hp <= '0';
stored_status.has_crc <= '0';
stored_status.is_hp <= '0';
stored_status.has_crc <= '0';
else
if(snk_valid = '1' and snk_i.adr = c_WRF_STATUS) then
stored_status <= decoded_status;
......@@ -328,7 +281,7 @@ begin -- behavioral
oob_state <= OOB_1;
end if;
when OOB_1 =>
if(snk_valid = '1' and snk_i.adr = c_WRF_OOB) then
if(snk_valid = '1' and snk_i.adr = c_WRF_OOB) then
oob.oob_type <= snk_i.dat(15 downto 12);
oob_state <= OOB_2;
end if;
......@@ -345,7 +298,6 @@ begin -- behavioral
end generate gen_ts_supported;
p_tx_fsm : process (clk_sys_i)
variable phdr : t_header_processor_rval;
begin -- process
if rising_edge(clk_sys_i) then
if(rst_n_i = '0') then
......@@ -364,7 +316,6 @@ begin -- behavioral
snk_out.err <= '0';
snk_out.rty <= '0';
snk_out.ack <= '0';
tx_pause_ack_o <= '0';
......@@ -372,6 +323,7 @@ begin -- behavioral
crc_gen_force_reset <= '0';
oob_fid_stb_o <= '0';
else
-- we are in the middle of the frame and the framer has got suddenly
......@@ -385,10 +337,10 @@ begin -- behavioral
q_valid <= '0';
elsif (state /= TXF_IDLE and pcs_error_i = '1') then
tx_ready <= '0';
counter <= (others => '0');
snk_o.err <= '1';
state <= TXF_GAP;
tx_ready <= '0';
counter <= (others => '0');
snk_out.err <= '1';
state <= TXF_GAP;
else
case state is
......@@ -399,21 +351,23 @@ begin -- behavioral
when TXF_IDLE => -- idle state - wait for the next frame
snk_o.err <= '0';
snk_o.rty <= '0';
snk_out.err <= '0';
snk_out.rty <= '0';
q_abort <= '0';
tx_ready <= tx_flow_enable_i;
-- Check start-of-frame and send-pause signals and eventually
-- commence frame transmission
-- Check start-of-frame and send-pause signals and eventually
-- commence frame transmission
if((sof_p1 = '1' or tx_pause_i = '1') and regs_b.ecr_tx_en_o = '1') then
-- enable writing to PCS FIFO
if(pcs_dreq_i = '1' and (sof_p1 = '1' or tx_pause_i = '1') and regs_b.ecr_tx_en_o = '1') then
-- enable writing to PCS FIFO
q_sof <= '1';
q_eof <= '0';
write_mask <= '1';
tx_pause_ack_o <= tx_pause_i;
tx_pause_mode <= tx_pause_i;
tx_pause_delay <= tx_pause_delay_i;
......@@ -422,7 +376,12 @@ begin -- behavioral
crc_gen_enable_mask <= '1';
counter <= (others => '0');
state <= TXF_HEADER;
if(tx_pause_i = '1') then
state <= TXF_PAUSE;
else
state <= TXF_ADDR;
end if;
else
write_mask <= '0';
q_valid <= '0';
......@@ -434,30 +393,145 @@ begin -- behavioral
-------------------------------------------------------------------------------
-- TX FSM state HEADER: processes the frame header
-------------------------------------------------------------------------------
when TXF_HEADER =>
tx_pause_ack_o <= '0';
tx_ready <= not tx_pause_mode;
when TXF_PAUSE =>
tx_ready <= '0';
tx_pause_ack_o <= '0';
q_sof <= '0';
crc_gen_force_reset <= '0';
if((snk_valid = '1' and snk_i.adr = c_WRF_DATA) or tx_pause_mode = '1') then
phdr := f_process_packet_header(snk_i, counter(3 downto 0), stored_status.has_smac, tx_pause_mode, tx_pause_delay);
if(pcs_dreq_i = '1') then
q_valid <= '1';
case counter(3 downto 0) is
when x"0" => q_data <= x"0180";
when x"1" => q_data <= x"c200";
when x"2" => q_data <= x"0001";
when x"3" => q_data <= regs_b.mach_o;
when x"4" => q_data <= regs_b.macl_o(31 downto 16);
when x"5" => q_data <= regs_b.macl_o(15 downto 0);
when x"6" => q_data <= x"8808";
when x"7" => q_data <= tx_pause_delay;
state <= TXF_PAD;
when others => null;
end case;
counter <= counter + 1;
else
q_valid <= '0';
end if;
q_sof <= phdr.sof;
q_data <= phdr.data;
q_valid <= phdr.valid;
when TXF_ADDR =>
q_sof <= '0';
crc_gen_force_reset <= '0';
state <= phdr.next_state;
if (pcs_dreq_i = '1' and snk_valid = '1' and snk_i.adr = c_WRF_DATA) then
counter <= counter + 1;
case counter(3 downto 0) is
when x"0" => q_data <= snk_i.dat; q_valid <= '1';
when x"1" => q_data <= snk_i.dat; q_valid <= '1';
when x"2" => q_data <= snk_i.dat; q_valid <= '1';
when x"3" =>
if(stored_status.has_smac = '1') then
q_data <= snk_i.dat;
else
q_data <= regs_b.mach_o;
end if;
q_valid <= '1';
when x"4" =>
if(stored_status.has_smac = '1') then
q_data <= snk_i.dat;
else
q_data <= regs_b.macl_o(31 downto 16);
end if;
q_valid <= '1';
when x"5" =>
if(stored_status.has_smac = '1') then
q_data <= snk_i.dat;
else
q_data <= regs_b.macl_o(15 downto 0);
end if;
q_valid <= '1';
when x"6" =>
if(g_with_vlans and snk_i.dat = x"8100") then -- 802.1q frame
q_data <= (others => 'X');
q_valid <= '0';
counter <= (others => '0');
state <= TXF_QHEADER;
else
q_data <= snk_i.dat;
q_valid <= '1';
state <= TXF_DATA;
end if;
when others => null;
end case;
else
q_sof <= '0'; -- tx_valid == 0
q_valid <= '0';
q_data <= (others => 'X');
end if;
when TXF_QHEADER =>
if(g_with_vlans and pcs_dreq_i = '1') then
case counter(3 downto 0) is
when x"0" => -- TPID
if(snk_valid = '1' and snk_i.adr = c_WRF_DATA) then
counter <= counter + 1;
vut_stored_ethertype <= snk_i.dat;
end if;
when x"1" => -- VLAN Tag
if(snk_valid = '1' and snk_i.adr = c_WRF_DATA) then
counter <= counter + 1;
vut_stored_tag <= snk_i.dat;
tx_ready <= '0';
end if;
when x"2" =>
if(vut_untag = '1' or untagging = '1') then -- VID is in the untagged set
untagging <= '1';
tx_ready <= '1';
q_data <= vut_stored_ethertype;
q_valid <= '1';
counter <= counter +1;
else
untagging <= '0';
q_data <= x"8100";
q_valid <= '1';
counter <= counter + 1;
end if;
when x"3" =>
if(untagging = '1') then
if(snk_valid = '1') then
q_data <= snk_i.dat;
q_valid <= '1';
state <= TXF_DATA;
else
q_valid <= '0';
end if;
elsif(untagging = '0') then
q_data <= vut_stored_ethertype;
q_valid <= '1';
counter <= counter + 1;
else
q_valid <= '0';
tx_ready <= '1';
end if;
when x"4" =>
if(untagging = '0') then
q_data <= vut_stored_tag;
q_valid <= '1';
tx_ready <= '1';
state <= TXF_DATA;
end if;
when others => null;
end case;
else
q_valid <= '0';
end if;
-------------------------------------------------------------------------------
-- TX FSM state PAD: pads a pause frame to 64 bytes.
-------------------------------------------------------------------------------
......@@ -470,29 +544,31 @@ begin -- behavioral
state <= TXF_WAIT_CRC;
q_valid <= '0';
else
q_data <= x"0000";
q_data <= x"0000";
q_valid <= '1';
end if;
-------------------------------------------------------------------------------
-- TX FSM state DATA: trasmits frame payload
-------------------------------------------------------------------------------
when TXF_DATA =>
tx_ready <= '1';
if(eof_p1 = '1') then
if(stored_status.has_crc = '0') then
state <= TXF_WAIT_CRC;
else
q_eof <= '1';
q_eof <= '1';
counter <= (others => '0');
state <= TXF_GAP;
end if;
tx_ready <= '0';
-- check if we have an OOB block
-- check if we have an OOB block
if(oob.valid = '1' and oob.oob_type = c_WRF_OOB_TYPE_TX and g_with_timestamper) then
oob_fid_stb_o <= '1';
end if;
......@@ -501,9 +577,9 @@ begin -- behavioral
if(snk_valid = '1' and snk_i.adr = c_WRF_DATA) then
q_data <= snk_i.dat;
q_valid <= '1';
q_bytesel <= not snk_i.sel(1); --tx_bytesel_i;
write_mask <= snk_i.sel(1);
odd_length <= not snk_i.sel(1); --tx_bytesel_i;
q_bytesel <= not snk_i.sel(0); --tx_bytesel_i;
write_mask <= snk_i.sel(0);
odd_length <= not snk_i.sel(0); --tx_bytesel_i;
else
q_valid <= '0';
end if;
......@@ -511,13 +587,13 @@ begin -- behavioral
-------------------------------------------------------------------------------
-- TX FSM states: WAIT_CRC, EMBED_CRC: dealing with frame checksum field
-------------------------------------------------------------------------------
when TXF_WAIT_CRC =>
oob_fid_stb_o <= '0';
q_valid <= '0';
state <= TXF_EMBED_CRC1;
crc_gen_enable_mask <= '0';
when TXF_EMBED_CRC1 =>
if(odd_length = '1') then -- CRC at odd position
q_data(7 downto 0) <= crc_value(31 downto 24);
......@@ -529,7 +605,7 @@ begin -- behavioral
write_mask <= '1';
q_bytesel <= '0';
state <= TXF_EMBED_CRC2;
when TXF_EMBED_CRC2 =>
if(odd_length = '1') then -- CRC at odd position
q_data(15 downto 0) <= crc_value(23 downto 8);
......@@ -555,13 +631,14 @@ begin -- behavioral
-------------------------------------------------------------------------------
-- TX FSM states: WAIT_CRC, EMBED_CRC: dealing with frame checksum field
-------------------------------------------------------------------------------
when TXF_GAP =>
q_abort <= '0';
q_valid <= '0';
snk_o.err <= '0';
snk_o.rty <= '0';
q_bytesel <= '0';
q_eof <= '0';
q_abort <= '0';
q_valid <= '0';
snk_out.err <= '0';
snk_out.rty <= '0';
q_bytesel <= '0';
if(counter = c_IFG_LENGTH) then
if(pcs_busy_i = '0') then
......@@ -592,7 +669,10 @@ begin -- behavioral
oob_fid_value_o <= oob.frame_id;
snk_out.stall <= not (tx_ready or (not regs_b.ecr_tx_en_o)); -- /dev/null if disabled
stall_int <= not (pcs_dreq_i and tx_ready) and regs_b.ecr_tx_en_o; -- /dev/null if disabled
snk_out.stall <= stall_int;
p_gen_ack : process(clk_sys_i)
begin
......@@ -610,7 +690,7 @@ begin -- behavioral
q_bytesel,
q_abort);
pcs_valid_o <= q_sof or (q_valid and write_mask);
pcs_valid_o <= q_sof or q_eof or (q_valid and write_mask);
end behavioral;
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment