eth_mac->miimoder = 25; // divider from CPU clock (50MHz/25 = 2MHz)
eth_mac_set_addr(src);
- eth_mac->settings = MAC_SET_PAUSE_EN | MAC_SET_PASS_BCAST | MAC_SET_PASS_UCAST; // 0x39;
+ eth_mac->settings = MAC_SET_PAUSE_EN | MAC_SET_PASS_BCAST | MAC_SET_PASS_UCAST | MAC_SET_PAUSE_SEND_EN;
+
+ eth_mac->pause_time = 38;
+ eth_mac->pause_thresh = 1200;
// set rx flow control high and low water marks
// unsigned int lwmark = (2*2048 + 64)/4; // 2 * 2048-byte frames + 1 * 64-byte pause frame
volatile int miicommand;
volatile int miistatus;
volatile int miirx_data;
+ volatile int pause_time;
+ volatile int pause_thresh;
} eth_mac_regs_t;
// settings register
#define MAC_SET_PASS_BCAST (1 << 3) // Sends broadcast frames through (normally on)
#define MAC_SET_PASS_MCAST (1 << 4) // Sends multicast frames that match mcast addr (normally off)
#define MAC_SET_PASS_UCAST (1 << 5) // Sends unicast (normal) frames through if they hit in address filter (normally on)
+#define MAC_SET_PAUSE_SEND_EN (1 << 6) // Enables sending pause frames
// miicommand register
#define MIIC_SCANSSTAT (1 << 0) // Scan status
// RX side of flow control -- when we are running out of RX space, send a PAUSE\r
\r
module flow_ctrl_rx\r
- (input rst,\r
- //host processor\r
- input pause_frame_send_en,\r
- input [15:0] pause_quanta_set,\r
- input [15:0] fc_hwmark,\r
- input [15:0] fc_lwmark,\r
- // From MAC_rx_ctrl\r
- input rx_clk,\r
- input [15:0] rx_fifo_space,\r
- // MAC_tx_ctrl\r
- input tx_clk,\r
- output reg xoff_gen,\r
- output reg xon_gen,\r
- input xoff_gen_complete,\r
- input xon_gen_complete\r
+ (input pause_request_en, input [15:0] pause_time, input [15:0] pause_thresh,\r
+ input rx_clk, input rx_reset, input [15:0] rx_fifo_space,\r
+ input tx_clk, input tx_reset, output reg pause_req, output reg [15:0] pause_time_req\r
);\r
\r
// ****************************************************************************** \r
// Force our TX to send a PAUSE frame because our RX is nearly full\r
// ******************************************************************************\r
\r
- reg xon_int, xoff_int;\r
+ // RX Clock Domain\r
+ reg xon, xoff;\r
reg [21:0] countdown;\r
- \r
- always @(posedge rx_clk or posedge rst)\r
- if(rst)\r
- begin\r
- xon_int <= 0;\r
- xoff_int <= 0;\r
- end\r
- else \r
- begin\r
- xon_int <= 0;\r
- xoff_int <= 0;\r
- if(pause_frame_send_en)\r
- if(countdown == 0)\r
- if(rx_fifo_space < fc_lwmark)\r
- xoff_int <= 1;\r
- else\r
- ;\r
- else\r
- if(rx_fifo_space > fc_hwmark)\r
- xon_int <= 1;\r
- end // else: !if(rst)\r
- \r
- reg xoff_int_d1, xon_int_d1;\r
\r
- always @(posedge rx_clk)\r
- xon_int_d1 <= xon_int;\r
- always @(posedge rx_clk)\r
- xoff_int_d1 <= xoff_int;\r
+ wire [15:0] pause_low_thresh = pause_thresh;\r
+ wire [15:0] pause_hi_thresh = 16'hFFFF;\r
+ wire [21:0] pq_reduced = {pause_time,6'd0} - 1700;\r
\r
- always @ (posedge tx_clk or posedge rst)\r
- if (rst)\r
- xoff_gen <=0;\r
- else if (xoff_gen_complete)\r
- xoff_gen <=0;\r
- else if (xoff_int | xoff_int_d1)\r
- xoff_gen <=1;\r
+ always @(posedge rx_clk)\r
+ if(rx_reset)\r
+ xoff <= 0;\r
+ else\r
+ xoff <= (pause_request_en & (countdown==0) & (rx_fifo_space < pause_low_thresh));\r
\r
- always @ (posedge tx_clk or posedge rst)\r
- if (rst)\r
- xon_gen <=0;\r
- else if (xon_gen_complete)\r
- xon_gen <=0;\r
- else if (xon_int | xon_int_d1)\r
- xon_gen <=1; \r
-\r
- wire [15:0] pq_reduced = pause_quanta_set - 2;\r
+ always @(posedge rx_clk)\r
+ if(rx_reset)\r
+ xon <= 0;\r
+ else\r
+ xon <= ((countdown!=0) & (rx_fifo_space > pause_hi_thresh));\r
\r
- always @(posedge tx_clk or posedge rst)\r
- if(rst)\r
+ always @(posedge rx_clk)\r
+ if(rx_reset)\r
countdown <= 0;\r
- else if(xoff_gen)\r
- countdown <= {pq_reduced,6'd0};\r
- else if(xon_gen)\r
+ else if(xoff)\r
+ countdown <= pq_reduced;\r
+ else if(xon)\r
countdown <= 0;\r
else if(countdown != 0)\r
countdown <= countdown - 1;\r
+\r
+ // Cross clock domains\r
+ oneshot_2clk send_xon (.clk_in(rx_clk), .in(xon), .clk_out(tx_clk), .out(xon_tx));\r
+ oneshot_2clk send_xoff (.clk_in(rx_clk), .in(xoff), .clk_out(tx_clk), .out(xoff_tx));\r
+ \r
+ always @(posedge tx_clk)\r
+ if(xoff_tx)\r
+ pause_time_req <= pause_time;\r
+ else if(xon_tx)\r
+ pause_time_req <= 0;\r
+\r
+ always @(posedge tx_clk)\r
+ if(tx_reset)\r
+ pause_req <= 0;\r
+ else \r
+ pause_req <= xon_tx | xoff_tx;\r
\r
-endmodule // flow_ctrl\r
+endmodule // flow_ctrl_rx\r
input GMII_RX_CLK, input GMII_RX_DV, input GMII_RX_ER, input [7:0] GMII_RXD,
// Flow Control Interface
- input pause_req, input [15:0] pause_time, input pause_en,
+ input pause_req, input [15:0] pause_time_req, input pause_respect_en,
// Settings
input [47:0] ucast_addr, input [47:0] mcast_addr,
.GMII_TX_ER(GMII_TX_ER), .GMII_TXD(GMII_TXD),
.tx_clk(tx_clk), .tx_data(tx_data), .tx_valid(tx_valid), .tx_error(tx_error), .tx_ack(tx_ack),
.ifg(SGE_IFG), .mac_addr(ucast_addr),
- .pause_req(pause_req), .pause_time(pause_time), // We request flow control
+ .pause_req(pause_req), .pause_time(pause_time_req), // We request flow control
.pause_apply(pause_apply), .paused(paused) // We respect flow control
);
flow_ctrl_tx flow_ctrl_tx
(.rst(rst_txclk), .tx_clk(tx_clk),
- .tx_pause_en(pause_en),
+ .tx_pause_en(pause_respect_en),
.pause_quanta(pause_quanta_rcvd), // 16 bit value
.pause_quanta_val(pause_rcvd),
.pause_apply(pause_apply),
inout mdio, output mdc,
output [47:0] ucast_addr, output [47:0] mcast_addr,
output pass_ucast, output pass_mcast, output pass_bcast,
- output pass_pause, output pass_all, output pause_en );
+ output pass_pause, output pass_all,
+ output pause_respect_en, output pause_request_en,
+ output [15:0] pause_time, output [15:0] pause_thresh );
wire acc = wb_cyc & wb_stb;
wire wr_acc = wb_cyc & wb_stb & wb_we;
else
wb_ack <= acc & ~wb_ack;
- wire [5:0] misc_settings;
- assign {pass_ucast, pass_mcast, pass_bcast, pass_pause, pass_all, pause_en} = misc_settings;
+ wire [6:0] misc_settings;
+ assign {pause_request_en, pass_ucast, pass_mcast, pass_bcast, pass_pause, pass_all, pause_respect_en} = misc_settings;
- wb_reg #(.ADDR(0),.DEFAULT(6'b111001))
+ wb_reg #(.ADDR(0),.DEFAULT(7'b0111001))
wb_reg_settings (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc),
.dat_i(wb_dat_i), .dat_o(misc_settings) );
wb_reg #(.ADDR(1),.DEFAULT(0))
.WCtrlDataStart(WCtrlDataStart), .RStatStart(RStatStart),
.UpdateMIIRX_DATAReg(UpdateMIIRX_DATAReg) );
+ wb_reg #(.ADDR(11),.DEFAULT(0))
+ wb_reg_pausetime (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc),
+ .dat_i(wb_dat_i), .dat_o(pause_time) );
+
+ wb_reg #(.ADDR(12),.DEFAULT(0))
+ wb_reg_pausethresh (.clk(wb_clk), .rst(wb_rst), .adr(wb_adr[7:2]), .wr_acc(wr_acc),
+ .dat_i(wb_dat_i), .dat_o(pause_thresh) );
+
always @(posedge wb_clk)
case(wb_adr[7:2])
0 : wb_dat_o <= misc_settings;
8 : wb_dat_o <= MIICOMMAND;
9 : wb_dat_o <= MIISTATUS;
10: wb_dat_o <= MIIRX_DATA;
+ 11: wb_dat_o <= pause_time;
+ 12: wb_dat_o <= pause_thresh;
endcase // case (wb_adr[7:2])
endmodule // simple_gemac_wb
.ll_src_rdy(tx_ll_src_rdy), .ll_dst_rdy(tx_ll_dst_rdy),
.tx_data(tx_data), .tx_valid(tx_valid), .tx_error(tx_error), .tx_ack(tx_ack));
- wire [31:0] debug_tx, debug_rx;
+ flow_ctrl_rx flow_ctrl_rx
+ (.pause_request_en(pause_request_en), .pause_time(pause_time), .pause_thresh(pause_thresh),
+ .rx_clk(rx_clk), .rx_reset(rx_reset), .rx_fifo_space(rx_fifo_space),
+ .tx_clk(tx_clk), .tx_reset(tx_reset), .pause_req(pause_req), .pause_time_req(pause_time_req));
+
+ wire [31:0] debug_tx, debug_rx;
assign debug_tx = { { tx_ll_data },
{ tx_ll_sof, tx_ll_eof, tx_ll_src_rdy, tx_ll_dst_rdy,
simple_gemac/crc.v \
simple_gemac/delay_line.v \
simple_gemac/flow_ctrl_tx.v \
+simple_gemac/flow_ctrl_rx.v \
simple_gemac/address_filter.v \
simple_gemac/ll8_to_txmac.v \
simple_gemac/rxmac_to_ll8.v \