fpga: lib: add pause support to ethernet xport
Original-commit: d099fc3b032250bcc70e4c24f78d5eb6508850e1
This commit is contained in:
committed by
Aaron Rossetto
parent
feb849051f
commit
d7acf31a38
@@ -22,7 +22,7 @@ module axi4s_fifo #(
|
|||||||
);
|
);
|
||||||
|
|
||||||
`include "axi4s.vh"
|
`include "axi4s.vh"
|
||||||
|
|
||||||
// Parameter Checks
|
// Parameter Checks
|
||||||
initial begin
|
initial begin
|
||||||
assert (i.DATA_WIDTH == o.DATA_WIDTH) else
|
assert (i.DATA_WIDTH == o.DATA_WIDTH) else
|
||||||
|
|||||||
@@ -65,11 +65,14 @@ module eth_ipv4_chdr_adapter #(
|
|||||||
input logic [47:0] my_mac,
|
input logic [47:0] my_mac,
|
||||||
input logic [31:0] my_ip,
|
input logic [31:0] my_ip,
|
||||||
input logic [15:0] my_udp_chdr_port,
|
input logic [15:0] my_udp_chdr_port,
|
||||||
|
input logic [15:0] my_pause_set,
|
||||||
|
input logic [15:0] my_pause_clear,
|
||||||
|
|
||||||
output logic chdr_dropped,
|
output logic chdr_dropped,
|
||||||
output logic cpu_dropped,
|
output logic cpu_dropped,
|
||||||
|
|
||||||
// Ethernet MAC
|
// Ethernet MAC
|
||||||
|
output logic eth_pause_req,
|
||||||
AxiStreamIf.master eth_tx, // tUser = {1'b0,trailing bytes};
|
AxiStreamIf.master eth_tx, // tUser = {1'b0,trailing bytes};
|
||||||
AxiStreamIf.slave eth_rx, // tUser = {error,trailing bytes};
|
AxiStreamIf.slave eth_rx, // tUser = {error,trailing bytes};
|
||||||
// CHDR router interface
|
// CHDR router interface
|
||||||
@@ -90,7 +93,7 @@ module eth_ipv4_chdr_adapter #(
|
|||||||
localparam CPU_USER_W = $clog2(CPU_W/8)+1;
|
localparam CPU_USER_W = $clog2(CPU_W/8)+1;
|
||||||
localparam CHDR_USER_W = $clog2(CHDR_W/8);
|
localparam CHDR_USER_W = $clog2(CHDR_W/8);
|
||||||
localparam MAX_PACKET_BYTES = 2**16;
|
localparam MAX_PACKET_BYTES = 2**16;
|
||||||
localparam DEBUG = 1;
|
localparam DEBUG = 0;
|
||||||
|
|
||||||
`include "eth_constants.vh"
|
`include "eth_constants.vh"
|
||||||
|
|
||||||
@@ -137,12 +140,15 @@ module eth_ipv4_chdr_adapter #(
|
|||||||
.DROP_MIN_PACKET(DROP_MIN_PACKET),
|
.DROP_MIN_PACKET(DROP_MIN_PACKET),
|
||||||
.ENET_W(ENET_W)
|
.ENET_W(ENET_W)
|
||||||
) eth_dispatch_i (
|
) eth_dispatch_i (
|
||||||
|
.eth_pause_req (eth_pause_req),
|
||||||
.eth_rx (eth_rx1),
|
.eth_rx (eth_rx1),
|
||||||
.e2v (e2v1),
|
.e2v (e2v1),
|
||||||
.e2c (e2c1),
|
.e2c (e2c1),
|
||||||
.my_mac (my_mac),
|
.my_mac (my_mac),
|
||||||
.my_ip (my_ip),
|
.my_ip (my_ip),
|
||||||
.my_udp_chdr_port (my_udp_chdr_port),
|
.my_udp_chdr_port (my_udp_chdr_port),
|
||||||
|
.my_pause_set (my_pause_set),
|
||||||
|
.my_pause_clear (my_pause_clear),
|
||||||
.chdr_dropped (chdr_dropped),
|
.chdr_dropped (chdr_dropped),
|
||||||
.cpu_dropped (cpu_dropped)
|
.cpu_dropped (cpu_dropped)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -34,6 +34,9 @@
|
|||||||
// - my_ip : The IPv4 address of this endpoint
|
// - my_ip : The IPv4 address of this endpoint
|
||||||
// - my_udp_chdr_port : The UDP port allocated for CHDR traffic on this endpoint
|
// - my_udp_chdr_port : The UDP port allocated for CHDR traffic on this endpoint
|
||||||
//
|
//
|
||||||
|
// - my pause set : number of word of fullness on CHDR_FIFO before requesting a pause
|
||||||
|
// - my pause clear : number of word of fullness on CHDR_FIFO before clearing a pause request
|
||||||
|
//
|
||||||
|
|
||||||
module eth_ipv4_chdr_dispatch #(
|
module eth_ipv4_chdr_dispatch #(
|
||||||
int CPU_FIFO_SIZE = $clog2(8*1024),
|
int CPU_FIFO_SIZE = $clog2(8*1024),
|
||||||
@@ -46,6 +49,7 @@ module eth_ipv4_chdr_dispatch #(
|
|||||||
)(
|
)(
|
||||||
|
|
||||||
// AXI-Stream interfaces
|
// AXI-Stream interfaces
|
||||||
|
output logic eth_pause_req,
|
||||||
AxiStreamIf.slave eth_rx, // tUser={error,trailing bytes};
|
AxiStreamIf.slave eth_rx, // tUser={error,trailing bytes};
|
||||||
AxiStreamIf.master e2v, // tUser={1'b0,trailing bytes};
|
AxiStreamIf.master e2v, // tUser={1'b0,trailing bytes};
|
||||||
AxiStreamIf.master e2c, // tUser={1'b0,trailing bytes};
|
AxiStreamIf.master e2c, // tUser={1'b0,trailing bytes};
|
||||||
@@ -54,6 +58,9 @@ module eth_ipv4_chdr_dispatch #(
|
|||||||
input logic [47:0] my_mac,
|
input logic [47:0] my_mac,
|
||||||
input logic [31:0] my_ip,
|
input logic [31:0] my_ip,
|
||||||
input logic [15:0] my_udp_chdr_port,
|
input logic [15:0] my_udp_chdr_port,
|
||||||
|
// Pause control
|
||||||
|
input logic [15:0] my_pause_set,
|
||||||
|
input logic [15:0] my_pause_clear,
|
||||||
|
|
||||||
output logic chdr_dropped,
|
output logic chdr_dropped,
|
||||||
output logic cpu_dropped
|
output logic cpu_dropped
|
||||||
@@ -63,15 +70,17 @@ module eth_ipv4_chdr_dispatch #(
|
|||||||
logic [47:0] e_my_mac;
|
logic [47:0] e_my_mac;
|
||||||
logic [31:0] e_my_ip;
|
logic [31:0] e_my_ip;
|
||||||
logic [15:0] e_my_udp_chdr_port;
|
logic [15:0] e_my_udp_chdr_port;
|
||||||
|
logic [15:0] e_pause_set;
|
||||||
|
logic [15:0] e_pause_clear;
|
||||||
// crossing clock boundaries.
|
// crossing clock boundaries.
|
||||||
// my_mac, my_ip,,my_udp_chdr_port must be written
|
// my_mac, my_ip,,my_udp_chdr_port must be written
|
||||||
// prior to traffic, or an inconsistent version will
|
// prior to traffic, or an inconsistent version will
|
||||||
// exist for a clock period or 2. This would be better
|
// exist for a clock period or 2. This would be better
|
||||||
// done with a full handshake.
|
// done with a full handshake.
|
||||||
synchronizer #(.WIDTH(96),.STAGES(1))
|
synchronizer #(.WIDTH(96+32),.STAGES(1))
|
||||||
e_info_sync (.clk(eth_rx.clk),.rst(eth_rx.rst),
|
e_info_sync (.clk(eth_rx.clk),.rst(eth_rx.rst),
|
||||||
.in({my_mac,my_ip,my_udp_chdr_port}),
|
.in({my_mac,my_ip,my_udp_chdr_port,my_pause_set,my_pause_clear}),
|
||||||
.out({e_my_mac,e_my_ip,e_my_udp_chdr_port}));
|
.out({e_my_mac,e_my_ip,e_my_udp_chdr_port,e_pause_set,e_pause_clear}));
|
||||||
|
|
||||||
|
|
||||||
localparam ENET_USER_W = $clog2(ENET_W/8)+1;
|
localparam ENET_USER_W = $clog2(ENET_W/8)+1;
|
||||||
@@ -515,11 +524,72 @@ module eth_ipv4_chdr_dispatch #(
|
|||||||
// transferring a packet. To ensure that upstream logic is not
|
// transferring a packet. To ensure that upstream logic is not
|
||||||
// blocked, we instantiate at laeast one packet of buffering here.
|
// blocked, we instantiate at laeast one packet of buffering here.
|
||||||
// The actual size is set by CHDR_FIFO_SIZE.
|
// The actual size is set by CHDR_FIFO_SIZE.
|
||||||
|
logic [15:0] chdr_occupied;
|
||||||
|
logic [15:0] chdr_occupied_q;
|
||||||
|
localparam CHDR_FIFO_WORD_SIZE = CHDR_FIFO_SIZE-$clog2(ENET_W/8);
|
||||||
axi4s_fifo #(
|
axi4s_fifo #(
|
||||||
.SIZE(CHDR_FIFO_SIZE-$clog2(ENET_W/8))
|
.SIZE(CHDR_FIFO_WORD_SIZE)
|
||||||
) chdr_fifo_i (
|
) chdr_fifo_i (
|
||||||
.clear(1'b0),.space(),.occupied(),
|
.clear(1'b0),.space(),.occupied(chdr_occupied),
|
||||||
.i(chdr1),.o(e2v)
|
.i(chdr1),.o(e2v)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// documentation requires pause requests to be set for a minimum of 16 clocks.
|
||||||
|
// I'm providing the same gauranteed min time in the set and clear direction
|
||||||
|
logic [3:0] pause_timer;
|
||||||
|
typedef enum logic [1:0] {
|
||||||
|
ST_IDLE = 2'd0,
|
||||||
|
ST_MIN_DELAY_SET = 2'd1,
|
||||||
|
ST_REQUESTING = 2'd2,
|
||||||
|
ST_MIN_DELAY_CLR = 2'd3
|
||||||
|
} pause_state_t;
|
||||||
|
pause_state_t pause_state = ST_IDLE;
|
||||||
|
|
||||||
|
always_ff @(posedge eth_rx.clk) begin : pause_req_ff
|
||||||
|
if (eth_rx.rst) begin
|
||||||
|
chdr_occupied_q <= 0;
|
||||||
|
eth_pause_req <= 1'b0;
|
||||||
|
pause_state <= ST_IDLE;
|
||||||
|
pause_timer <= 0;
|
||||||
|
end else begin
|
||||||
|
chdr_occupied_q <= chdr_occupied;
|
||||||
|
|
||||||
|
case (pause_state)
|
||||||
|
|
||||||
|
ST_IDLE: begin
|
||||||
|
pause_timer <= 0;
|
||||||
|
if (chdr_occupied_q >= e_pause_set) begin
|
||||||
|
eth_pause_req <= 1'b1;
|
||||||
|
pause_state <= ST_MIN_DELAY_SET;
|
||||||
|
pause_timer <= pause_timer-1; // Wrap counter to max value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ST_MIN_DELAY_SET: begin
|
||||||
|
pause_timer <= pause_timer-1;
|
||||||
|
if (pause_timer == 1) begin
|
||||||
|
pause_state <= ST_REQUESTING;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ST_REQUESTING: begin
|
||||||
|
pause_timer <= 0;
|
||||||
|
if (chdr_occupied_q <= e_pause_clear) begin
|
||||||
|
eth_pause_req <= 1'b0;
|
||||||
|
pause_state <= ST_MIN_DELAY_CLR;
|
||||||
|
pause_timer <= pause_timer-1; // Wrap counter to max value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ST_MIN_DELAY_CLR: begin
|
||||||
|
pause_timer <= pause_timer-1;
|
||||||
|
if (pause_timer == 1) begin
|
||||||
|
pause_state <= ST_IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
endmodule // eth_ipv4_chdr_dispatch
|
endmodule // eth_ipv4_chdr_dispatch
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ module eth_ipv4_interface #(
|
|||||||
int PREAMBLE_BYTES = 6,
|
int PREAMBLE_BYTES = 6,
|
||||||
bit ADD_SOF = 1,
|
bit ADD_SOF = 1,
|
||||||
bit SYNC = 0,
|
bit SYNC = 0,
|
||||||
|
bit PAUSE_EN = 0,
|
||||||
int ENET_W = 64,
|
int ENET_W = 64,
|
||||||
int CPU_W = 64,
|
int CPU_W = 64,
|
||||||
int CHDR_W = 64
|
int CHDR_W = 64
|
||||||
@@ -63,6 +64,7 @@ module eth_ipv4_interface #(
|
|||||||
output logic [15:0] my_udp_chdr_port,
|
output logic [15:0] my_udp_chdr_port,
|
||||||
|
|
||||||
// Ethernet MAC
|
// Ethernet MAC
|
||||||
|
output logic eth_pause_req,
|
||||||
AxiStreamIf.master eth_tx, // tUser = {1'b0,trailing bytes};
|
AxiStreamIf.master eth_tx, // tUser = {1'b0,trailing bytes};
|
||||||
AxiStreamIf.slave eth_rx, // tUser = {error,trailing bytes};
|
AxiStreamIf.slave eth_rx, // tUser = {error,trailing bytes};
|
||||||
// CHDR router interface
|
// CHDR router interface
|
||||||
@@ -77,6 +79,8 @@ module eth_ipv4_interface #(
|
|||||||
localparam [47:0] DEFAULT_MAC_ADDR = {8'h00, 8'h80, 8'h2f, 8'h16, 8'hc5, 8'h2f};
|
localparam [47:0] DEFAULT_MAC_ADDR = {8'h00, 8'h80, 8'h2f, 8'h16, 8'hc5, 8'h2f};
|
||||||
localparam [31:0] DEFAULT_IP_ADDR = {8'd192, 8'd168, 8'd10, 8'd2};
|
localparam [31:0] DEFAULT_IP_ADDR = {8'd192, 8'd168, 8'd10, 8'd2};
|
||||||
localparam [31:0] DEFAULT_UDP_PORT = 16'd49153;
|
localparam [31:0] DEFAULT_UDP_PORT = 16'd49153;
|
||||||
|
localparam [15:0] DEFAULT_PAUSE_SET = 16'd00040;
|
||||||
|
localparam [15:0] DEFAULT_PAUSE_CLEAR = 16'd00020;
|
||||||
|
|
||||||
//---------------------------------------------------------
|
//---------------------------------------------------------
|
||||||
// Registers
|
// Registers
|
||||||
@@ -102,6 +106,8 @@ module eth_ipv4_interface #(
|
|||||||
logic chdr_dropped;
|
logic chdr_dropped;
|
||||||
logic [31:0] chdr_drop_count = 0;
|
logic [31:0] chdr_drop_count = 0;
|
||||||
logic [31:0] cpu_drop_count = 0;
|
logic [31:0] cpu_drop_count = 0;
|
||||||
|
logic [15:0] my_pause_set = DEFAULT_PAUSE_SET;
|
||||||
|
logic [15:0] my_pause_clear = DEFAULT_PAUSE_CLEAR;
|
||||||
|
|
||||||
always_comb begin : bridge_mux
|
always_comb begin : bridge_mux
|
||||||
my_mac = bridge_en ? bridge_mac_reg : mac_reg;
|
my_mac = bridge_en ? bridge_mac_reg : mac_reg;
|
||||||
@@ -118,6 +124,8 @@ module eth_ipv4_interface #(
|
|||||||
bridge_mac_reg <= DEFAULT_MAC_ADDR;
|
bridge_mac_reg <= DEFAULT_MAC_ADDR;
|
||||||
bridge_ip_reg <= DEFAULT_IP_ADDR;
|
bridge_ip_reg <= DEFAULT_IP_ADDR;
|
||||||
bridge_udp_port <= DEFAULT_UDP_PORT;
|
bridge_udp_port <= DEFAULT_UDP_PORT;
|
||||||
|
my_pause_set <= DEFAULT_PAUSE_SET;
|
||||||
|
my_pause_clear <= DEFAULT_PAUSE_CLEAR;
|
||||||
end
|
end
|
||||||
else begin
|
else begin
|
||||||
if (reg_wr_req)
|
if (reg_wr_req)
|
||||||
@@ -149,6 +157,14 @@ module eth_ipv4_interface #(
|
|||||||
|
|
||||||
REG_BRIDGE_ENABLE:
|
REG_BRIDGE_ENABLE:
|
||||||
bridge_en <= reg_wr_data[0];
|
bridge_en <= reg_wr_data[0];
|
||||||
|
|
||||||
|
REG_PAUSE:
|
||||||
|
begin
|
||||||
|
if (PAUSE_EN) begin
|
||||||
|
my_pause_set <= reg_wr_data[15:0];
|
||||||
|
my_pause_clear <= reg_wr_data[31:16];
|
||||||
|
end
|
||||||
|
end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -210,6 +226,14 @@ module eth_ipv4_interface #(
|
|||||||
reg_rd_data <= cpu_drop_count;
|
reg_rd_data <= cpu_drop_count;
|
||||||
cpu_drop_count <= 0; // clear when read
|
cpu_drop_count <= 0; // clear when read
|
||||||
end
|
end
|
||||||
|
|
||||||
|
REG_PAUSE:
|
||||||
|
begin
|
||||||
|
if (PAUSE_EN) begin
|
||||||
|
reg_rd_data[15:0] <= my_pause_set;
|
||||||
|
reg_rd_data[31:16] <= my_pause_clear;
|
||||||
|
end
|
||||||
|
end
|
||||||
default:
|
default:
|
||||||
reg_rd_resp <= 1'b0;
|
reg_rd_resp <= 1'b0;
|
||||||
endcase
|
endcase
|
||||||
@@ -256,6 +280,7 @@ module eth_ipv4_interface #(
|
|||||||
.CPU_W (CPU_W),
|
.CPU_W (CPU_W),
|
||||||
.CHDR_W (CHDR_W)
|
.CHDR_W (CHDR_W)
|
||||||
) eth_adapter_i (
|
) eth_adapter_i (
|
||||||
|
.eth_pause_req (eth_pause_req),
|
||||||
.eth_rx (eth_rx ),
|
.eth_rx (eth_rx ),
|
||||||
.eth_tx (eth_tx ),
|
.eth_tx (eth_tx ),
|
||||||
.v2e (v2e ),
|
.v2e (v2e ),
|
||||||
@@ -266,6 +291,8 @@ module eth_ipv4_interface #(
|
|||||||
.my_mac (my_mac ),
|
.my_mac (my_mac ),
|
||||||
.my_ip (my_ip ),
|
.my_ip (my_ip ),
|
||||||
.my_udp_chdr_port(my_udp_chdr_port),
|
.my_udp_chdr_port(my_udp_chdr_port),
|
||||||
|
.my_pause_set (my_pause_set),
|
||||||
|
.my_pause_clear (my_pause_clear),
|
||||||
.chdr_dropped (e_chdr_dropped),
|
.chdr_dropped (e_chdr_dropped),
|
||||||
.cpu_dropped (e_cpu_dropped)
|
.cpu_dropped (e_cpu_dropped)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -365,6 +365,7 @@ module eth_ipv4_internal #(
|
|||||||
.reg_rd_addr (reg_rd_addr),
|
.reg_rd_addr (reg_rd_addr),
|
||||||
.reg_rd_resp (reg_rd_resp_eth_if),
|
.reg_rd_resp (reg_rd_resp_eth_if),
|
||||||
.reg_rd_data (reg_rd_data_eth_if),
|
.reg_rd_data (reg_rd_data_eth_if),
|
||||||
|
.eth_pause_req (),
|
||||||
.eth_tx (e2h_chdr),
|
.eth_tx (e2h_chdr),
|
||||||
.eth_rx (h2e_chdr),
|
.eth_rx (h2e_chdr),
|
||||||
.e2v (e2v_chdr),
|
.e2v (e2v_chdr),
|
||||||
|
|||||||
@@ -30,3 +30,4 @@ 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_CHDR_DROPPED = BASE + 'h1030;
|
||||||
localparam [REG_AWIDTH-1:0] REG_CPU_DROPPED = BASE + 'h1034;
|
localparam [REG_AWIDTH-1:0] REG_CPU_DROPPED = BASE + 'h1034;
|
||||||
|
localparam [REG_AWIDTH-1:0] REG_PAUSE = BASE + 'h1038;
|
||||||
|
|||||||
Reference in New Issue
Block a user