fpga: lib: Update xport_sv

- Detect dropped words at the dispatch level. This prevents
   an overflow on CHDR from block CPU.
 - Dropped packets are recorded as CPU or CHDR drop count
 - Refactor to put chdr_xport_adapter.sv in different clock
   domain to improve timing
 - Unwrinkle tkeep/trailing transitions


Original-commit: 7f86724ec3387f75d39d683b2ac5f5152e714c74
This commit is contained in:
Andrew Moch
2020-08-05 17:18:12 -05:00
committed by Wade Fife
parent 466e61d3ef
commit f28357679e
6 changed files with 437 additions and 182 deletions
+17 -3
View File
@@ -511,15 +511,29 @@ module chdr_xport_adapter #(
data_fifo_o.tready = au.tready & pass_packet;
end
// Clock Crossing to the ethernet clock domain
logic [47:0] e_my_mac;
logic [31:0] e_my_ip;
logic [15:0] e_my_udp_chdr_port;
// crossing clock boundaries.
// my_mac, my_ip, my_udp_chdr_port must be written
// prior to traffic, or an inconsistent version will
// exist for a clock period or 2. This would be better
// done with a full handshake.
synchronizer #(.WIDTH(96),.STAGES(1))
e_info_sync (.clk(eth_rx.clk),.rst(eth_rx.rst),
.in({my_mac,my_ip,my_udp_chdr_port}),
.out({e_my_mac,e_my_ip,e_my_udp_chdr_port}));
// add the UDP header back on before sending to EthTx
eth_ipv4_add_udp #(
.PREAMBLE_BYTES(PREAMBLE_BYTES),
.MAX_PACKET_BYTES(MAX_PACKET_BYTES)
) add_udp_i (
.i(au), .o(eth_tx),
.mac_src(my_mac),
.ip_src(my_ip),
.udp_src(my_udp_chdr_port),
.mac_src(e_my_mac),
.ip_src(e_my_ip),
.udp_src(e_my_udp_chdr_port),
.mac_dst(au_mac_dst),
.ip_dst(au_ip_dst),
.udp_dst(au_udp_dst)
+130 -39
View File
@@ -48,7 +48,7 @@ module eth_ifc_tb #(
// Include for register offsets
`include "../eth_regs.vh"
// allows the DUT to push full words and tb does not check tuser/tkeep of packets it's transmitting
localparam IGNORE_EXTRA_DATA = 1;
localparam IGNORE_EXTRA_DATA = 0;
//---------------------------------------------------------------------------
// Clocks
@@ -68,10 +68,10 @@ module eth_ifc_tb #(
TestExec test = new();
localparam MAX_PACKET_BYTES = 2**16;
AxiStreamIf #(.DATA_WIDTH(ENET_W),.USER_WIDTH(ENET_USER_W),.TKEEP(0),
AxiStreamIf #(.DATA_WIDTH(ENET_W),.USER_WIDTH(ENET_USER_W),
.MAX_PACKET_BYTES(MAX_PACKET_BYTES))
eth_tx (eth_clk, eth_reset);
AxiStreamIf #(.DATA_WIDTH(ENET_W),.USER_WIDTH(ENET_USER_W),.TKEEP(0),
AxiStreamIf #(.DATA_WIDTH(ENET_W),.USER_WIDTH(ENET_USER_W),
.MAX_PACKET_BYTES(MAX_PACKET_BYTES))
eth_rx (eth_clk, eth_reset);
@@ -86,7 +86,7 @@ module eth_ifc_tb #(
e2c (clk, reset);
// Bus functional model for a axi_stream controller
AxiStreamBfm #(.DATA_WIDTH(ENET_W),.USER_WIDTH(ENET_USER_W),.TKEEP(0),
AxiStreamBfm #(.DATA_WIDTH(ENET_W),.USER_WIDTH(ENET_USER_W),
.MAX_PACKET_BYTES(MAX_PACKET_BYTES)) eth =
new(.master(eth_rx), .slave(eth_tx));
AxiStreamBfm #(.DATA_WIDTH(CHDR_W),.USER_WIDTH(CHDR_USER_W),.TKEEP(0),.TUSER(0)) v =
@@ -123,8 +123,12 @@ module eth_ifc_tb #(
eth_ipv4_interface #(
.PREAMBLE_BYTES(PREAMBLE_BYTES),
.PROTOVER(PROTOVER), .MTU(MTU), .NODE_INST(NODE_INST),
.REG_AWIDTH(REG_AWIDTH), .RT_TBL_SIZE(RT_TBL_SIZE),
.CPU_FIFO_SIZE(MTU),
.CHDR_FIFO_SIZE(MTU),
.PROTOVER(PROTOVER),
.NODE_INST(NODE_INST),
.REG_AWIDTH(REG_AWIDTH),
.RT_TBL_SIZE(RT_TBL_SIZE),
.BASE(BASE),.SYNC(SYNC),
.ENET_W(ENET_W),.CPU_W(CPU_W),.CHDR_W(CHDR_W)
) eth_interface (
@@ -168,6 +172,7 @@ module eth_ifc_tb #(
always_comb begin
eth_tx.tdata = eth_tx_tdata;
eth_tx.tuser = eth_tx_tuser;
eth_tx.tkeep = eth_tx.trailing2keep(eth_tx_tuser);
eth_tx.tlast = eth_tx_tlast;
eth_tx.tvalid = eth_tx_tvalid;
eth_tx_tready = eth_tx.tready;
@@ -202,7 +207,7 @@ module eth_ifc_tb #(
end
eth_interface #(
.PROTOVER(PROTOVER), .MTU(MTU), .NODE_INST(NODE_INST),
.PROTOVER(PROTOVER), .NODE_INST(NODE_INST), .MTU(MTU),
.REG_AWIDTH(REG_AWIDTH), .RT_TBL_SIZE(RT_TBL_SIZE),
.BASE(BASE)
) eth_interface (
@@ -210,9 +215,6 @@ module eth_ifc_tb #(
.my_udp_port (my_udp_chdr_port)
);
end
always_comb begin
eth_tx.tkeep = '1;
end
task automatic reg_wr (
// Register port: Write port (domain: clk)
@@ -310,7 +312,10 @@ module eth_ifc_tb #(
reg_rd_check(REG_BRIDGE_MAC_MSB,DEF_BRIDGE_MAC_ADDR[47:32]);
reg_rd_check(REG_BRIDGE_IP,DEF_BRIDGE_IP_ADDR);
reg_rd_check(REG_BRIDGE_UDP,DEF_BRIDGE_UDP_PORT);
if (SV_ETH_IFC) begin
reg_rd_check(REG_CHDR_DROPPED,0);
reg_rd_check(REG_CPU_DROPPED,0);
end
test.end_test();
endtask : test_registers
@@ -330,7 +335,7 @@ module eth_ifc_tb #(
typedef AxiStreamPacket #(CHDR_W,CHDR_USER_W) ChdrAxisPacket_t;
typedef ChdrPacket #(CHDR_W,CHDR_USER_W) ChdrPacket_t;
task automatic test_ethcpu(int num_samples[$], int ERROR_PROB=2);
task automatic test_ethcpu(int num_samples[$], int ERROR_PROB=2, int EXPECT_DROPS=0);
TestExec test_e2c = new();
automatic EthXportPacket_t send[$];
automatic CpuXportPacket_t expected[$];
@@ -402,20 +407,41 @@ module eth_ifc_tb #(
end
end
begin //rx_thread
foreach(expected[i]) begin
automatic CpuAxisPacket_t actual_a;
automatic CpuXportPacket_t actual = new();
cpu.get(actual_a);
actual.import_axis(actual_a);
actual.tuser_to_tkeep();
// $display({"****************::%s::**********************\n",
// "**send** \n%s\n**expected**\n%s\n**actual**\n%s \n".
// "%d byte with error %d"},
// TEST_NAME,
// send[i].sprint(),expected[i].sprint(),actual.sprint(),
// num_samples[i],send[i].has_error());
`ASSERT_ERROR(!actual.compare_w_sof(expected[i]),"failed to send packet to e2c");
if (EXPECT_DROPS > 0) begin
automatic int pkt_num = 0;
automatic int drop_count = 0;
while (expected.size() > 0) begin
automatic CpuAxisPacket_t actual_a;
automatic CpuXportPacket_t actual = new();
cpu.get(actual_a);
actual.import_axis(actual_a);
actual.tuser_to_tkeep();
while (expected.size > 0 && actual.compare_no_user(expected[0],.PRINT_LVL(0))) begin
void'(expected.pop_front());
++drop_count;
++pkt_num;
$display("Droped packet %d",pkt_num);
`ASSERT_ERROR(drop_count < EXPECT_DROPS,"Exceeded anticipated number of dropped packets e2c");
end
if (expected.size() > 0) begin
++pkt_num;
$display("Rcvd packet %d",pkt_num);
void'(expected.pop_front());
end
end
if (SV_ETH_IFC) begin
$display("Verify drop count is %d",drop_count);
reg_rd_check(REG_CPU_DROPPED,drop_count);
end
end else begin
foreach(expected[i]) begin
automatic CpuAxisPacket_t actual_a;
automatic CpuXportPacket_t actual = new();
cpu.get(actual_a);
actual.import_axis(actual_a);
actual.tuser_to_tkeep();
`ASSERT_ERROR(!actual.compare_w_sof(expected[i]),"failed to send packet to e2c");
end
end
end
join
@@ -512,7 +538,9 @@ module eth_ifc_tb #(
wait_for_udp_packets(DEF_DEST_UDP_PORT);
eth.get(actual_a);
actual.import_axis(actual_a);
actual.tuser_to_tkeep();
if (!SV_ETH_IFC) begin
actual.tuser_to_tkeep();
end
`ASSERT_ERROR(!actual.compare_w_pad(expected[i],!SV_ETH_IFC),"failed to send packet to c2e");
end
end
@@ -556,7 +584,7 @@ module eth_ifc_tb #(
return chdr_pkt;
endfunction : unflatten_chdr
task automatic test_ethchdr(int num_samples[$], int ERROR_PROB=2);
task automatic test_ethchdr(int num_samples[$], int ERROR_PROB=2, int EXPECT_DROPS=0);
TestExec test_e2v = new();
automatic EthXportPacket_t send[$];
automatic ChdrXportPacket_t expected[$];
@@ -655,13 +683,41 @@ module eth_ifc_tb #(
end
end
begin //rx_thread
foreach(expected[i]) begin
automatic ChdrAxisPacket_t actual_a;
automatic ChdrXportPacket_t actual = new();
v.get(actual_a);
actual.import_axis(actual_a);
actual.tuser_to_tkeep();
`ASSERT_ERROR(!actual.compare_no_user(expected[i]),"failed to send packet e2v");
if (EXPECT_DROPS > 0) begin
automatic int pkt_num = 0;
automatic int drop_count = 0;
while (expected.size() > 0) begin
automatic ChdrAxisPacket_t actual_a;
automatic ChdrXportPacket_t actual = new();
v.get(actual_a);
actual.import_axis(actual_a);
actual.tuser_to_tkeep();
while (expected.size > 0 && actual.compare_no_user(expected[0],.PRINT_LVL(0))) begin
void'(expected.pop_front());
++drop_count;
++pkt_num;
$display("Droped packet %d",pkt_num);
`ASSERT_ERROR(drop_count < EXPECT_DROPS,"Exceeded anticipated number of dropped packets e2v");
end
if (expected.size() > 0) begin
++pkt_num;
$display("Rcvd packet %d",pkt_num);
void'(expected.pop_front());
end
end
if (SV_ETH_IFC) begin
$display("Verify drop count is %d",drop_count);
reg_rd_check(REG_CHDR_DROPPED,drop_count);
end
end else begin
foreach(expected[i]) begin
automatic ChdrAxisPacket_t actual_a;
automatic ChdrXportPacket_t actual = new();
v.get(actual_a);
actual.import_axis(actual_a);
actual.tuser_to_tkeep();
`ASSERT_ERROR(!actual.compare_no_user(expected[i]),"failed to send packet e2v");
end
end
end
join
@@ -785,9 +841,8 @@ module eth_ifc_tb #(
wait_for_udp_packets(.udp_dest_port(0));
eth.get(actual_a);
actual.import_axis(actual_a);
actual.tuser_to_tkeep();
actual_raw = actual.dump_bytes();
repeat(PREAMBLE_BYTES) actual_raw.pop_front();
repeat(PREAMBLE_BYTES) void'(actual_raw.pop_front());
decode_udp_pkt(actual_raw,eth_hdr,ipv4_hdr,udp_hdr,chdr_raw);
chdr_pkt = unflatten_chdr(chdr_raw);
// fills remainder of packet with zeros
@@ -939,9 +994,8 @@ module eth_ifc_tb #(
eth.get(actual_a);
actual.import_axis(actual_a);
actual.tuser_to_tkeep();
actual_raw = actual.dump_bytes();
repeat(PREAMBLE_BYTES) actual_raw.pop_front();
repeat(PREAMBLE_BYTES) void'(actual_raw.pop_front());
decode_udp_pkt(actual_raw,eth_hdr,ipv4_hdr,udp_hdr,chdr_raw);
chdr_pkt = unflatten_chdr(chdr_raw);
// fills remainder of packet with zeros
@@ -966,6 +1020,7 @@ module eth_ifc_tb #(
initial begin : tb_main
automatic int num_samples[$];
automatic int cpu_num_samples[$];
automatic int expected_drops;
localparam QUICK = 0;
test.start_test({TEST_NAME,"Wait for Reset"}, 10us);
clk_gen.reset();
@@ -981,6 +1036,42 @@ module eth_ifc_tb #(
test_chdr_endpoint();
// Check what happens if the input bandwidth exceeds
// the devices ability to consume packets
// This can happen in matched bandwidth cases
// if there is hold off from upstream
// Dropped packets exceed the drop count cause an error
// The actual droped count is compared versus the real count
test.start_test({TEST_NAME,"::Input overrun"}, 200us);
eth.set_master_stall_prob(0);
eth.set_slave_stall_prob(0);
cpu.set_master_stall_prob(0);
cpu.set_slave_stall_prob(0);
v.set_master_stall_prob(0);
v.set_slave_stall_prob(0);
num_samples = {7936,7936,7936,7936,7936,320,
7936,7936,7936,7936,7936,320};
// The actual number of expected drops depends on the
// bus width difference between ENET_W and CHDR/CPU_W
// in this SIM unlimited etherent bandwidth is coming in at over 300 MHZ
// and output runs at 200 MHZ. This causes excess BW on transmitter even when matched.
expected_drops = 9;
test_ethchdr(num_samples,.EXPECT_DROPS(expected_drops),.ERROR_PROB(0));
test_ethcpu(num_samples,.EXPECT_DROPS(expected_drops),.ERROR_PROB(0));
test.end_test();
eth.set_master_stall_prob(38);
eth.set_slave_stall_prob(38);
cpu.set_master_stall_prob(38);
cpu.set_slave_stall_prob(38);
v.set_master_stall_prob(38);
v.set_slave_stall_prob(38);
num_samples = {1,2,3,4,5,6,7,8,
ENET_W/8-1,ENET_W/8,ENET_W/8+1,
2*ENET_W/8-1,2*ENET_W/8,2*ENET_W/8+1,
+77 -66
View File
@@ -16,15 +16,15 @@
//
// Parameters:
// - PROTOVER: RFNoC protocol version {8'd<major>, 8'd<minor>}
// - MTU: Log2 of the MTU of the packet in 64-bit words
// - CPU_FIFO_SIZE: Log2 of the FIFO depth (in 64-bit words) for the CPU egress path
// - CPU_FIFO_SIZE: Log2 of the FIFO depth (in bytes) for the CPU egress path
// - CHDR_FIFO_SIZE: Log2 of the FIFO depth (in bytes) for the CHDR egress path
// - RT_TBL_SIZE: Log2 of the depth of the return-address routing table
// - NODE_INST: The node type to return for a node-info discovery
// - DROP_UNKNOWN_MAC: Drop packets not addressed to us?
// - DROP_MIN_PACKET: Drop packets smaller than 64 bytes?
// - PREAMBLE_BYTES: Number of bytes of Preamble expected
// - ADD_SOF: Add a SOF indication into the tuser field
// If false use TKEEP instead of USER
// - ADD_SOF: Add a SOF indication into the tuser field of the e2c path.
// If false use TKEEP instead of USER.
// - SYNC: Set if MAC is not the same as bus_clk
// - ENET_W: Width of the link to the Ethernet MAC
// - CPU_W: Width of the CPU interface
@@ -45,8 +45,8 @@
module eth_ipv4_chdr_adapter #(
logic [15:0] PROTOVER = {8'd1, 8'd0},
int MTU = 10,
int CPU_FIFO_SIZE = MTU,
int CPU_FIFO_SIZE = $clog2(8*1024),
int CHDR_FIFO_SIZE = $clog2(8*1024),
int RT_TBL_SIZE = 6,
int NODE_INST = 0,
bit DROP_UNKNOWN_MAC = 0,
@@ -58,6 +58,7 @@ module eth_ipv4_chdr_adapter #(
int CPU_W = 64,
int CHDR_W = 64
)(
// Device info
input logic [15:0] device_id,
// Device addresses
@@ -65,6 +66,9 @@ module eth_ipv4_chdr_adapter #(
input logic [31:0] my_ip,
input logic [15:0] my_udp_chdr_port,
output logic chdr_dropped,
output logic cpu_dropped,
// Ethernet MAC
AxiStreamIf.master eth_tx, // tUser = {1'b0,trailing bytes};
AxiStreamIf.slave eth_rx, // tUser = {error,trailing bytes};
@@ -90,6 +94,10 @@ module eth_ipv4_chdr_adapter #(
`include "eth_constants.vh"
// tUser = {error,trailing_bytes}
AxiStreamIf #(.DATA_WIDTH(ENET_W),.USER_WIDTH(ENET_USER_W),.TKEEP(0)) eth_rx1(eth_rx.clk,eth_rx.rst);
//---------------------------------------
// E2V and E2C DEMUX
//---------------------------------------
@@ -98,9 +106,8 @@ module eth_ipv4_chdr_adapter #(
// tUser = {*not used*}
AxiStreamIf #(.DATA_WIDTH(CHDR_W),.TKEEP(0),.TUSER(0)) e2v2(e2v.clk,e2v.rst);
// tUser = {*not used*}
AxiStreamIf #(.DATA_WIDTH(CHDR_W),.TKEEP(0),.TUSER(0)) e2v4(e2v.clk,e2v.rst);
// tUser = {*not used*}
AxiStreamIf #(.DATA_WIDTH(CHDR_W),.TKEEP(0),.TUSER(0)) e2v5(e2v.clk,e2v.rst);
AxiStreamIf #(.DATA_WIDTH(CHDR_W),.TKEEP(0),.TUSER(0)) e2v3(e2v.clk,e2v.rst);
// tUser = {1'b0,trailing bytes}
AxiStreamIf #(.DATA_WIDTH(ENET_W),.USER_WIDTH(ENET_USER_W),.TKEEP(0)) e2c1(eth_rx.clk,eth_rx.rst);
@@ -109,35 +116,35 @@ module eth_ipv4_chdr_adapter #(
.TKEEP(!ADD_SOF), .TUSER(ADD_SOF))
e2c2(e2c.clk,e2c.rst);
logic [47:0] e_my_mac;
logic [31:0] e_my_ip;
logic [15:0] e_my_udp_chdr_port;
// crossing clock boundaries.
// my_mac, my_ip,,my_udp_chdr_port must be written
// prior to traffic, or an inconsistent version will
// exist for a clock period or 2. This would be better
// done with a full handshake.
synchronizer #(.WIDTH(96),.STAGES(1))
e_info_sync (.clk(eth_rx.clk),.rst(eth_rx.rst),
.in({my_mac,my_ip,my_udp_chdr_port}),
.out({e_my_mac,e_my_ip,e_my_udp_chdr_port}));
// The older implementation connected with tUser containing trailing bytes
// The newer implementation brings in TKEEP
// inside this block we expect trailing bytes.
always_comb begin
`AXI4S_ASSIGN(eth_rx1,eth_rx)
if (eth_rx.TKEEP) begin
eth_rx1.tuser = {eth_rx.tuser[ENET_USER_W-1],eth_rx.keep2trailing(eth_rx.tkeep)};
end
end
// Ethernet sink. Inspects packet and dispatches
// to the correct port.
eth_ipv4_chdr_dispatch #(
.CPU_FIFO_SIZE(CPU_FIFO_SIZE),
.CHDR_FIFO_SIZE(CHDR_FIFO_SIZE),
.PREAMBLE_BYTES(PREAMBLE_BYTES),
.MAX_PACKET_BYTES(MAX_PACKET_BYTES),
.DROP_UNKNOWN_MAC(DROP_UNKNOWN_MAC),
.DROP_MIN_PACKET(DROP_MIN_PACKET),
.ENET_W(ENET_W)
) eth_dispatch_i (
.eth_rx (eth_rx),
.eth_rx (eth_rx1),
.e2v (e2v1),
.e2c (e2c1),
.my_mac (e_my_mac),
.my_ip (e_my_ip),
.my_udp_chdr_port (e_my_udp_chdr_port)
.my_mac (my_mac),
.my_ip (my_ip),
.my_udp_chdr_port (my_udp_chdr_port),
.chdr_dropped (chdr_dropped),
.cpu_dropped (cpu_dropped)
);
//---------------------------------------
@@ -222,7 +229,7 @@ module eth_ipv4_chdr_adapter #(
.my_udp_chdr_port (my_udp_chdr_port),
.eth_rx (e2v2), // from ethernet
.e2v (e2v4), // to CHDR
.e2v (e2v3), // to CHDR
// optional loop from ethernet to ethernet to talk to node
.v2e (v2e), // from CHDR
.eth_tx (v2e1D) // to ethernet
@@ -261,28 +268,14 @@ module eth_ipv4_chdr_adapter #(
// E2V Output Buffering
//---------------------------------------
// The transport should hook up to a crossbar downstream, which
// may backpressure this module because it is in the middle of
// transferring a packet. To ensure that upstream logic is not
// blocked, we instantiate one packet worth of buffering here.
axi4s_fifo #(
.SIZE(MTU)
) chdr_fifo_i (
.clear(1'b0),.space(),.occupied(),
.i(e2v4),.o(e2v5)
);
if (DEBUG) begin
`AXI4S_DEBUG_ASSIGN(e2v,e2v5)
`AXI4S_DEBUG_ASSIGN(e2v,e2v3)
end else begin
always_comb begin : e2v_direct_assign
`AXI4S_ASSIGN(e2v,e2v5)
`AXI4S_ASSIGN(e2v,e2v3)
end
end
//---------------------------------------
// C2E Path
//---------------------------------------
@@ -291,7 +284,7 @@ module eth_ipv4_chdr_adapter #(
.TKEEP(c2e.TKEEP),.TUSER(c2e.TUSER))
c2eD(c2e.clk,c2e.rst);
// tUser = {1'b0,trailing bytes}
AxiStreamIf #(.DATA_WIDTH(ENET_W),.USER_WIDTH(ENET_USER_W),.TKEEP(0)) c2e1(eth_rx.clk,eth_rx.rst);
AxiStreamIf #(.DATA_WIDTH(ENET_W),.USER_WIDTH(ENET_USER_W),.TKEEP(0),.MAX_PACKET_BYTES(MAX_PACKET_BYTES)) c2e1(eth_rx.clk,eth_rx.rst);
// tUser = {1'b0,trailing bytes}
AxiStreamIf #(.DATA_WIDTH(ENET_W),.USER_WIDTH(ENET_USER_W),.TKEEP(0),.MAX_PACKET_BYTES(MAX_PACKET_BYTES)) c2e2(eth_rx.clk,eth_rx.rst);
// tUser = {1'b0,trailing bytes}
@@ -332,8 +325,8 @@ module eth_ipv4_chdr_adapter #(
// Add pad of PREAMBLE_BYTES empty bytes to the ethernet packet going
// from the CPU to the SFP. This padding added before MAC addresses
// aligns the source and destination IP addresses, UDP headers etc.
// Note that the xge_mac_wrapper strips this padding to recreate the ethernet
// packet
// Note that the xge_mac_wrapper strips this padding to recreate the
// ethernet packet.
axi4s_add_bytes #(.ADD_START(0),.ADD_BYTES(PREAMBLE_BYTES)
) add_header (
.i(c2e1), .o(c2e2)
@@ -380,7 +373,7 @@ module eth_ipv4_chdr_adapter #(
always_comb begin : c2e3_pad
if (pad_state == ST_IDLE) begin
//force to a full word
// force to a full word
// preserve SOF if it's there, but force
// trailing bytes to zero (full word)
c2e3.tuser = 0;
@@ -429,12 +422,13 @@ module eth_ipv4_chdr_adapter #(
//---------------------------------------
// V2E and C2E MUX
//---------------------------------------
// tUser = {1'b0,trailing bytes}
AxiStreamIf #(.DATA_WIDTH(ENET_W),.USER_WIDTH(ENET_USER_W),.TKEEP(0)) eth_tx1 (eth_rx.clk,eth_rx.rst);
// tUser = {1'b0,trailing bytes}
AxiStreamIf #(.DATA_WIDTH(ENET_W),.USER_WIDTH(ENET_USER_W)) eth_tx2 (eth_rx.clk,eth_rx.rst);
logic c2e3_tready;
logic eth_tx1_tlast;
logic eth_tx1_tvalid;
logic eth_tx1_tready;
logic [ENET_W-1:0] eth_tx1_tdata;
logic [ENET_USER_W-1:0] eth_tx1_tuser;
always_comb begin
c2e3.tready = c2e3_tready;
end
@@ -444,30 +438,47 @@ module eth_ipv4_chdr_adapter #(
.clk(eth_rx.clk), .reset(eth_rx.rst), .clear(1'b0),
.i_tdata({c2e3.tuser, c2e3.tdata, v2e3.tuser, v2e3.tdata}), .i_tlast({c2e3.tlast, v2e3.tlast}),
.i_tvalid({c2e3.tvalid, v2e3.tvalid}), .i_tready({c2e3_tready, v2e3.tready}),
.o_tdata({eth_tx1_tuser, eth_tx1_tdata}), .o_tlast(eth_tx1_tlast),
.o_tvalid(eth_tx1_tvalid), .o_tready(eth_tx1_tready)
.o_tdata({eth_tx1.tuser, eth_tx1.tdata}), .o_tlast(eth_tx1.tlast),
.o_tvalid(eth_tx1.tvalid), .o_tready(eth_tx1.tready)
);
// Clean up the noisy mux output. I suspect it is annoying
// the xilinx cores that tlast and tuser(tkeep) flop around
// the Xilinx cores that tlast and tuser(tkeep) flop around
// when tvalid isn't true.
always_comb begin : eth_tx_assign
if (eth_tx1_tvalid) begin
eth_tx.tvalid = 1'b1;
eth_tx.tdata = eth_tx1_tdata;
eth_tx.tlast = eth_tx1_tlast;
if (eth_tx1_tlast) begin
eth_tx.tuser = eth_tx1_tuser;
if (eth_tx1.tvalid) begin
eth_tx2.tvalid = 1'b1;
eth_tx2.tdata = eth_tx1.tdata;
eth_tx2.tlast = eth_tx1.tlast;
// driving both tuser and tkeep
if (eth_tx1.tlast) begin
eth_tx2.tuser = eth_tx1.tuser;
eth_tx2.tkeep = eth_tx1.trailing2keep(eth_tx1.tuser);
end else begin
eth_tx.tuser = '0;
eth_tx2.tuser = '0;
eth_tx2.tkeep = '1;
end
end else begin
eth_tx.tvalid = 1'b0;
eth_tx.tdata = 'X; // use X so synth will optimize
eth_tx.tlast = 0;
eth_tx.tuser = '0;
eth_tx2.tvalid = 1'b0;
eth_tx2.tdata = 'X; // use X so synth will optimize
eth_tx2.tlast = 0;
eth_tx2.tuser = '0;
eth_tx2.tkeep = '1;
end
eth_tx1_tready = eth_tx.tready;
eth_tx1.tready = eth_tx2.tready;
end
//---------------------------------------
// Output pipeline stage
//---------------------------------------
axi4s_fifo #(
.SIZE(1)
) in_reg_i (
.clear(1'b0),.space(),.occupied(),
.i(eth_tx2), .o(eth_tx)
);
endmodule // eth_ipv4_chdr_adapter
+156 -66
View File
@@ -17,7 +17,8 @@
// Traffic not addressed (Eth) to us is dropped(optionally).
//
// Parameters:
// - CPU_FIFO_SIZE: log2 size of CPU RX fifo
// - CPU_FIFO_SIZE: Log2 of the FIFO depth (in bytes) for the CPU egress path
// - CHDR_FIFO_SIZE: Log2 of the FIFO depth (in bytes) for the CHDR egress path
// - PREAMBLE_BYTES: Number of bytes in the Preamble
// - DROP_UNKNOWN_MAC: Drop packets not addressed to us?
// - DROP_MIN_PACKET: Drop packets smaller than 64 bytes?
@@ -35,7 +36,8 @@
//
module eth_ipv4_chdr_dispatch #(
int CPU_FIFO_SIZE = $clog2(1558),
int CPU_FIFO_SIZE = $clog2(8*1024),
int CHDR_FIFO_SIZE = $clog2(8*1024),
int PREAMBLE_BYTES = 6,
int MAX_PACKET_BYTES = 2**16-1,
bit DROP_UNKNOWN_MAC = 0,
@@ -51,9 +53,27 @@ module eth_ipv4_chdr_dispatch #(
// Device addresses
input logic [47:0] my_mac,
input logic [31:0] my_ip,
input logic [15:0] my_udp_chdr_port
input logic [15:0] my_udp_chdr_port,
output logic chdr_dropped,
output logic cpu_dropped
);
// Clock Crossing to the ethernet clock domain
logic [47:0] e_my_mac;
logic [31:0] e_my_ip;
logic [15:0] e_my_udp_chdr_port;
// crossing clock boundaries.
// my_mac, my_ip,,my_udp_chdr_port must be written
// prior to traffic, or an inconsistent version will
// exist for a clock period or 2. This would be better
// done with a full handshake.
synchronizer #(.WIDTH(96),.STAGES(1))
e_info_sync (.clk(eth_rx.clk),.rst(eth_rx.rst),
.in({my_mac,my_ip,my_udp_chdr_port}),
.out({e_my_mac,e_my_ip,e_my_udp_chdr_port}));
localparam ENET_USER_W = $clog2(ENET_W/8)+1;
//---------------------------------------
// Include for byte positions
@@ -68,6 +88,9 @@ module eth_ipv4_chdr_dispatch #(
``I.tready = ``O.tready;
// axi_remov_bytes (PREAMBLE Strip)
AxiStreamIf #(.DATA_WIDTH(ENET_W),.USER_WIDTH(ENET_USER_W),
.TKEEP(0),.MAX_PACKET_BYTES(MAX_PACKET_BYTES))
inp(eth_rx.clk,eth_rx.rst);
// tUser = {error,trailing bytes};
AxiStreamPacketIf #(.DATA_WIDTH(ENET_W),.USER_WIDTH(ENET_USER_W),
.TKEEP(0),.MAX_PACKET_BYTES(MAX_PACKET_BYTES))
@@ -86,21 +109,21 @@ module eth_ipv4_chdr_dispatch #(
// tUser = {error,trailing bytes};
AxiStreamIf #(.DATA_WIDTH(ENET_W),.USER_WIDTH(ENET_USER_W),.TKEEP(0))
cpu0(eth_rx.clk,eth_rx.rst);
// out_reg_cpu
// cpu_out_gate - throw away error packets
// tUser = {error,trailing bytes};
AxiStreamIf #(.DATA_WIDTH(ENET_W),.USER_WIDTH(ENET_USER_W),.TKEEP(0))
cpu1(eth_rx.clk,eth_rx.rst);
// cpu_out_gate - throw away error packets
// tUser = {1'b0,trailing bytes};
AxiStreamIf #(.DATA_WIDTH(ENET_W),.USER_WIDTH(ENET_USER_W),.TKEEP(0))
cpu2(eth_rx.clk,eth_rx.rst);
// cpu_out_fifo
// e2c (OUTPUT)
// CHDR_Branch
// tUser = {error,trailing bytes};
// tUser = {not used};
AxiStreamIf #(.DATA_WIDTH(ENET_W),.TKEEP(0),.TUSER(0))
chdr0(eth_rx.clk,eth_rx.rst);
// tUser = {not used};
AxiStreamIf #(.DATA_WIDTH(ENET_W),.TKEEP(0),.TUSER(0))
chdr1(eth_rx.clk,eth_rx.rst);
// chdr_out_fifo
// e2v(OUTPUT)
//---------------------------------------
@@ -108,9 +131,12 @@ module eth_ipv4_chdr_dispatch #(
//---------------------------------------
if (PREAMBLE_BYTES > 0) begin : gen_strip_preamble
// Strip the preamble
always_comb begin
`AXI4S_ASSIGN(inp,eth_rx);
end
axi4s_remove_bytes #(.REM_START(0),.REM_END(PREAMBLE_BYTES-1)
) strip_preamble (
.i(eth_rx),.o(in0)
.i(inp),.o(in0)
);
end else begin : gen_no_preamble
always_comb begin
@@ -143,10 +169,11 @@ module eth_ipv4_chdr_dispatch #(
dispatch_state_t dispatch_state,next_dispatch_state = ST_IDLE_ETH_L0;
logic cpu_error = 1'b0;
logic chdr_error = 1'b0;
logic chdr0_error = 1'b0;
logic mac_error, mac_error_old = 1'b0;
logic min_packet_error, min_packet_error_old = 1'b0;
logic mac_error;
logic min_packet_error;
logic reached_min_packet;
logic cpu_push_error;
logic chdr_push_error;
// Cached fields
logic [47:0] eth_dst_addr_new, eth_src_addr_new;
@@ -180,8 +207,6 @@ module eth_ipv4_chdr_dispatch #(
udp_src_port_old <= '0;
udp_dst_port_old <= '0;
eth_type_old <= '0;
mac_error_old <= 1'b0;
min_packet_error_old <= 1'b0;
reached_min_packet_old <= 1'b0;
// Statemachine Decisions
@@ -204,26 +229,12 @@ module eth_ipv4_chdr_dispatch #(
if (in0.tvalid && in0.tready) begin
eth_dst_is_broadcast <= eth_dst_addr_new == ETH_ADDR_BCAST;
eth_dst_is_me <= eth_dst_addr_new == my_mac;
udp_dst_is_me <= udp_dst_port_new == my_udp_chdr_port;
ipv4_dst_is_me <= ipv4_dst_addr_new == my_ip;
eth_dst_is_me <= eth_dst_addr_new == e_my_mac;
udp_dst_is_me <= udp_dst_port_new == e_my_udp_chdr_port;
ipv4_dst_is_me <= ipv4_dst_addr_new == e_my_ip;
ipv4_protocol_is_udp <= ip_protocol_new == IPV4_PROTO_UDP;
eth_type_is_ipv4 <= eth_type_new == ETH_TYPE_IPV4;
end
if (in1.tvalid && in1.tready) begin
if (in1.tlast) begin
mac_error_old <= 1'b0;
min_packet_error_old <= 1'b0;
reached_min_packet_old <= 1'b0;
end else begin
if (mac_error)
mac_error_old <= 1'b1;
if(min_packet_error)
min_packet_error_old <= 1'b1;
if(reached_min_packet_new)
reached_min_packet_old <= 1'b1;
end
end
end
end
@@ -240,15 +251,19 @@ module eth_ipv4_chdr_dispatch #(
eth_type_new = in0.get_packet_field16(eth_type_old,ETH_TYPE_BYTE,.NETWORK_ORDER(1));
end
always_comb begin : reached_bytes
reached_min_packet_new = in1.reached_packet_byte(MIN_PACKET_SIZE_BYTE);
reached_end_of_udp = in1.reached_packet_byte(DST_PORT_BYTE+3);// we have enough to decide
end
assign mac_error = in1.tuser[ERROR_BIT] || mac_error_old;
// calculate error conditions
assign mac_error = in1.tuser[ERROR_BIT] && in1.tvalid;
assign cpu_push_error = (in2.tvalid && !cpu0.tready);
assign chdr_push_error = (in2.tvalid && !chdr0.tready);
if (DROP_MIN_PACKET) begin
assign reached_min_packet = (reached_min_packet_new && in1.tuser[BYTES_MSB:0] ==0) || reached_min_packet_old;
assign min_packet_error = (in1.tlast && !reached_min_packet) || min_packet_error_old;
assign min_packet_error = (in1.tlast && !reached_min_packet);
end else begin
assign reached_min_packet = 1'b1;
assign min_packet_error = 1'b0;
@@ -271,16 +286,16 @@ module eth_ipv4_chdr_dispatch #(
//defaults
next_dispatch_state = dispatch_state;
`AXI4S_ASSIGN(in2,in1);
in2.tuser[ERROR_BIT] = mac_error || min_packet_error;
cpu_error = 1'b0;
chdr_error = 1'b0;
in1.tready = 1'b1; // never hold off
// Statemachine always returns to ST_IDLE_ETH_L0 when tlast is set
case (dispatch_state)
ST_IDLE_ETH_L0: begin
cpu_error = 1'b0;
chdr_error = 1'b0;
if (mac_error || min_packet_error) begin
if (mac_error || min_packet_error || cpu_push_error || chdr_push_error) begin
cpu_error = 1'b1;
chdr_error = 1'b1;
next_dispatch_state = ST_DROP_TERM;
@@ -318,7 +333,7 @@ module eth_ipv4_chdr_dispatch #(
ST_FWD_CHDR: begin
cpu_error = 1'b1;
chdr_error = 1'b0;
if (mac_error || min_packet_error) begin
if (mac_error || min_packet_error || chdr_push_error) begin
cpu_error = 1'b1;
chdr_error = 1'b1;
next_dispatch_state = ST_DROP_TERM;
@@ -329,7 +344,7 @@ module eth_ipv4_chdr_dispatch #(
ST_FWD_CPU: begin
cpu_error = 1'b0;
chdr_error = 1'b1;
if (mac_error || min_packet_error) begin
if (mac_error || min_packet_error || cpu_push_error) begin
cpu_error = 1'b1;
chdr_error = 1'b1;
next_dispatch_state = ST_DROP_TERM;
@@ -342,7 +357,6 @@ module eth_ipv4_chdr_dispatch #(
chdr_error = 1'b1;
in2.tlast = 1'b1;
in2.tvalid = 1'b1;
in1.tready = in2.tready;
next_dispatch_state = ST_DROP_WAIT;
end
@@ -352,14 +366,12 @@ module eth_ipv4_chdr_dispatch #(
chdr_error = 1'b0;
in2.tlast = 1'b0;
in2.tvalid = 1'b0;
in1.tready = 1'b1;
end
// We should never get here
default: begin
cpu_error = 1'b0;
chdr_error = 1'b0;
in1.tready = 1'b1;
in2.tvalid = 1'b0;
in2.tlast = 1'b0;
next_dispatch_state = ST_IDLE_ETH_L0;
@@ -371,65 +383,143 @@ module eth_ipv4_chdr_dispatch #(
//---------------------------------------
// SPLIT
//---------------------------------------
// differentiating push_errors for reporting
logic cpu0_push_error, cpu0_push_error_old= 1'b0;
logic chdr0_push_error, chdr0_push_error_old= 1'b0;
logic chdr0_error, chdr0_error_old = 1'b0;
logic cpu0_error, cpu0_error_old = 1'b0;
always_comb begin : cpu0_assign
cpu0_error = (cpu_error && in2.tvalid) || cpu0_error_old;
cpu0_push_error = (cpu_push_error && in2.tvalid)|| cpu0_push_error_old;
cpu0.tdata = in2.tdata;
cpu0.tuser = in2.tuser;
cpu0.tlast = in2.tlast;
cpu0.tvalid = in2.tvalid && chdr0.tready;
cpu0.tuser[ERROR_BIT] = in2.tuser[ERROR_BIT] || cpu_error;
cpu0.tlast = in2.tlast || cpu0_error;
cpu0.tvalid = in2.tvalid || cpu0_error;
chdr0_error = (chdr_error && in2.tvalid) || chdr0_error_old;
chdr0_push_error = (chdr_push_error && in2.tvalid) || chdr0_push_error_old;
chdr0.tdata = in2.tdata;
chdr0.tuser = in2.tuser;
chdr0.tlast = in2.tlast;
chdr0.tvalid = in2.tvalid && cpu0.tready;
chdr0_error = in2.tuser[ERROR_BIT] || chdr_error;
chdr0.tlast = in2.tlast || chdr0_error;
chdr0.tvalid = in2.tvalid || chdr0_error;
// If the downstream sections are not ready, then the packet is dropped
// there isn't really any buffer up stream, so a hold off here would
// mean pushing back on a mac that doesn't have the capability to slow
// down, and a data word would be lost.
in2.tready = 1'b1;
in2.tready = cpu0.tready && chdr0.tready;
end
//---------------------------------------
// CPU Output processing
//---------------------------------------
axi4s_fifo #(
.SIZE(1)
) out_reg_cpu_i (
.clear(),.space(),.occupied(),
.i(cpu0),.o(cpu1)
);
// hold the error bits until the end of the packet
always_ff @(posedge eth_rx.clk) begin : error_ff
if (eth_rx.rst) begin
cpu0_error_old <= 1'b0;
chdr0_error_old <= 1'b0;
cpu0_push_error_old <= 1'b0;
chdr0_push_error_old <= 1'b0;
chdr_dropped <= 1'b0;
cpu_dropped <= 1'b0;
end else begin
// report dropped back at the end of packet when push_error is detected.
// 1st term counts the drop if ready lets up before the end of the packet
// 2nd term counts the drop if ready is held through then end of the packet
// NOTE: Drop counts don't have to be perfect. This gets pretty close though.
// I.e. Don't sweat this more in the future.
chdr_dropped <= (chdr0_push_error && chdr0.tlast && chdr0.tvalid && chdr0.tready) ||
(chdr0_push_error && in1.tlast && in1.tvalid);
cpu_dropped <= (cpu0_push_error && cpu0.tlast && cpu0.tvalid && cpu0.tready) ||
(cpu0_push_error && in1.tlast && in1.tvalid);
// don't clear till we discard a packet
if (cpu0.tlast && cpu0.tvalid && cpu0.tready) begin
cpu0_push_error_old <= 1'b0;
// remember if we saw an error
end else if (cpu0_push_error && cpu0.tvalid) begin
cpu0_push_error_old <= 1'b1;
end
// don't clear till we discard a packet
if (cpu0.tlast && cpu0.tvalid && cpu0.tready) begin
cpu0_error_old <= 1'b0;
// remember if we saw an error
end else if (cpu0_error && cpu0.tvalid) begin
cpu0_error_old <= 1'b1;
end
// don't clear till we discard a packet
if (chdr0.tlast && chdr0.tvalid && chdr0.tready) begin
chdr0_push_error_old <= 1'b0;
// remember if we saw an error
end else if (chdr0_push_error && chdr0.tvalid) begin
chdr0_push_error_old <= 1'b1;
end
// don't clear till we discard a packet
if (chdr0.tlast && chdr0.tvalid && chdr0.tready) begin
chdr0_error_old <= 1'b0;
// remember if we saw an error
end else if (chdr0_error && chdr0.tvalid) begin
chdr0_error_old <= 1'b1;
end
end
end
// We cannot make a CHDR/noCHDR routing decision until we are in the middle
// of a packet so we use a packet gate for the CPU path because we can rewind
// the write pointer and drop the packet in case it's destined for the CHDR
// path.
// path
//---------------------------------------
// CPU Output processing
//---------------------------------------
// NOTE: This also rejects packets with FCS failures.
// NOTE: The SIZE of this FIFO must accommodate a 9000 byte jumbo frame
// regardless of the CHDR MTU
// SIZED for 11 bit address when using a 64 bit word -> 16KByte
// SIZED for 8 bit address when using a 512 bit word -> 16KByte
axi4s_packet_gate #(
.SIZE(17-$clog2(ENET_W)), .USE_AS_BUFF(0)
.SIZE(14-$clog2(ENET_W/8)), .USE_AS_BUFF(0)
) cpu_out_gate_i (
.clear(1'b0), .error(cpu1.tuser[ERROR_BIT]),
.i(cpu1),.o(cpu2)
.clear(1'b0), .error(cpu0_error),
.i(cpu0),.o(cpu1)
);
// The CPU can be slow to respond (relative to packet wirespeed) so
// extra buffer for packets destined there so it doesn't back up.
axi4s_fifo #(
.SIZE(CPU_FIFO_SIZE)
.SIZE(CPU_FIFO_SIZE-$clog2(ENET_W/8))
) cpu_fifo_i (
.clear(),.space(),.occupied(),
.i(cpu2),.o(e2c)
.i(cpu1),.o(e2c)
);
//---------------------------------------
// CHDR Output processing
//---------------------------------------
// CHDR DATA GATE
// SIZED for 11 bit address when using a 64 bit word -> 16KByte
// SIZED for 8 bit address when using a 512 bit word -> 16KByte
axi4s_packet_gate #(
.SIZE(17-$clog2(ENET_W))
.SIZE(14-$clog2(ENET_W/8))
) chdr_out_gate_i (
.clear(1'b0),.error(chdr0_error),
.i(chdr0),.o(e2v)
.i(chdr0),.o(chdr1)
);
// The transport should hook up to a crossbar downstream, which
// may backpressure this module because it is in the middle of
// transferring a packet. To ensure that upstream logic is not
// blocked, we instantiate at laeast one packet of buffering here.
// The actual size is set by CHDR_FIFO_SIZE.
axi4s_fifo #(
.SIZE(CHDR_FIFO_SIZE-$clog2(ENET_W/8))
) chdr_fifo_i (
.clear(1'b0),.space(),.occupied(),
.i(chdr1),.o(e2v)
);
endmodule // eth_ipv4_chdr_dispatch
+54 -8
View File
@@ -11,14 +11,14 @@
//
// Parameters:
// - PROTOVER: RFNoC protocol version {8'd<major>, 8'd<minor>}
// - MTU: Log2 of the MTU of the packet in 64-bit words
// - CPU_FIFO_SIZE: Log2 of the FIFO depth (in 64-bit words) for the CPU egress path
// - CPU_FIFO_SIZE: Log2 of the FIFO depth (in bytes) for the CPU egress path
// - CHDR_FIFO_SIZE: Log2 of the FIFO depth (in bytes) for the CHDR egress path
// - RT_TBL_SIZE: Log2 of the depth of the return-address routing table
// - NODE_INST: The node type to return for a node-info discovery
// - DROP_UNKNOWN_MAC: Drop packets not addressed to us?
// - DROP_MIN_PACKET: Drop packets smaller than 64 bytes?
// - PREAMBLE_BYTES: Number of bytes of Preamble expected
// - ADD_SOF: Add a SOF indication into the tuser field
// - ADD_SOF: Add a SOF indication into the tuser field of e2c
// - SYNC: Set if MAC is not the same as bus_clk
// - ENET_W: Width of the link to the Ethernet MAC
// - CPU_W: Width of the CPU interface
@@ -27,8 +27,8 @@
module eth_ipv4_interface #(
logic [15:0] PROTOVER = {8'd1, 8'd0},
int MTU = 10,
int CPU_FIFO_SIZE = MTU,
int CPU_FIFO_SIZE = $clog2(8*1024),
int CHDR_FIFO_SIZE = $clog2(8*1024),
int NODE_INST = 0,
int RT_TBL_SIZE = 6,
int REG_AWIDTH = 14,
@@ -98,6 +98,10 @@ module eth_ipv4_interface #(
logic [31:0] bridge_ip_reg = DEFAULT_IP_ADDR;
logic [15:0] bridge_udp_port = DEFAULT_UDP_PORT;
logic bridge_en;
logic cpu_dropped;
logic chdr_dropped;
logic [31:0] chdr_drop_count = 0;
logic [31:0] cpu_drop_count = 0;
always_comb begin : bridge_mux
my_mac = bridge_en ? bridge_mac_reg : mac_reg;
@@ -153,8 +157,16 @@ module eth_ipv4_interface #(
if (bus_rst) begin
reg_rd_resp <= 1'b0;
reg_rd_data <= 32'd0;
chdr_drop_count <= 32'd0;
cpu_drop_count <= 32'd0;
end
else begin
if (chdr_dropped) begin
chdr_drop_count <= chdr_drop_count+1;
end
if (cpu_dropped) begin
cpu_drop_count <= cpu_drop_count+1;
end
if (reg_rd_req) begin
// Assert read response one cycle after read request
reg_rd_resp <= 1'b1;
@@ -185,7 +197,19 @@ module eth_ipv4_interface #(
REG_BRIDGE_ENABLE:
reg_rd_data <= {31'b0,bridge_en};
// Drop counts are used to debug situations
// Where the incoming data goes faster than
// chdr can consume it
REG_CHDR_DROPPED:
begin
reg_rd_data <= chdr_drop_count;
chdr_drop_count <= 0; // clear when read
end
REG_CPU_DROPPED:
begin
reg_rd_data <= cpu_drop_count;
cpu_drop_count <= 0; // clear when read
end
default:
reg_rd_resp <= 1'b0;
endcase
@@ -197,10 +221,30 @@ module eth_ipv4_interface #(
end
end
logic b_dropped_valid;
logic e_cpu_dropped, b_cpu_dropped;
logic e_chdr_dropped, b_chdr_dropped;
// push over the clock domain
// Sized to fit into 2 SRL's
axi_fifo_2clk #(.WIDTH(2), .SIZE(4)) fifo_i (
.reset(eth_rx.rst),
.i_aclk(eth_rx.clk),
.i_tdata({e_cpu_dropped, e_chdr_dropped}),
.i_tvalid(e_cpu_dropped || e_chdr_dropped), .i_tready(/*not used*/),
.o_aclk(bus_clk),
.o_tdata({b_cpu_dropped, b_chdr_dropped}),
.o_tvalid(b_dropped_valid), .o_tready(1'b1)
);
always_comb begin
cpu_dropped = b_cpu_dropped && b_dropped_valid;
chdr_dropped = b_chdr_dropped && b_dropped_valid;
end
eth_ipv4_chdr_adapter #(
.PROTOVER (PROTOVER),
.MTU (MTU),
.CPU_FIFO_SIZE (CPU_FIFO_SIZE),
.CHDR_FIFO_SIZE (CHDR_FIFO_SIZE),
.RT_TBL_SIZE (RT_TBL_SIZE),
.NODE_INST (NODE_INST),
.DROP_UNKNOWN_MAC(DROP_UNKNOWN_MAC),
@@ -221,7 +265,9 @@ module eth_ipv4_interface #(
.device_id (device_id),
.my_mac (my_mac ),
.my_ip (my_ip ),
.my_udp_chdr_port(my_udp_chdr_port )
.my_udp_chdr_port(my_udp_chdr_port),
.chdr_dropped (e_chdr_dropped),
.cpu_dropped (e_cpu_dropped)
);
+3
View File
@@ -27,3 +27,6 @@ localparam [REG_AWIDTH-1:0] REG_BRIDGE_MAC_MSB = BASE + 'h1014;
localparam [REG_AWIDTH-1:0] REG_BRIDGE_IP = BASE + 'h1018;
localparam [REG_AWIDTH-1:0] REG_BRIDGE_UDP = BASE + 'h101c;
localparam [REG_AWIDTH-1:0] REG_BRIDGE_ENABLE = BASE + 'h1020;
localparam [REG_AWIDTH-1:0] REG_CHDR_DROPPED = BASE + 'h1030;
localparam [REG_AWIDTH-1:0] REG_CPU_DROPPED = BASE + 'h1034;