aboutsummaryrefslogtreecommitdiffstats
path: root/simple_gemac
diff options
context:
space:
mode:
Diffstat (limited to 'simple_gemac')
-rw-r--r--simple_gemac/simple_gemac_rx.v184
-rw-r--r--simple_gemac/simple_gemac_tb.v48
2 files changed, 192 insertions, 40 deletions
diff --git a/simple_gemac/simple_gemac_rx.v b/simple_gemac/simple_gemac_rx.v
index 8650a69a9..64bf2104c 100644
--- a/simple_gemac/simple_gemac_rx.v
+++ b/simple_gemac/simple_gemac_rx.v
@@ -3,32 +3,172 @@
module simple_gemac_rx
(input clk125, input reset,
input GMII_RX_CLK, input GMII_RX_DV, input GMII_RX_ER, input [7:0] GMII_RXD,
- output rx_clk, output [7:0] rx_data, output rx_valid, output rx_error, output rx_ack,
- output reg [15:0] pause_quanta_rcvd, output reg pause_rcvd );
+ output rx_clk, output [7:0] rx_data, output reg rx_valid, output rx_error, output reg rx_ack,
+ input [47:0] ucast_addr, input [47:0] mcast_addr,
+ input pass_ucast, input pass_mcast, input pass_bcast, input pass_pause, input pass_all,
+ output reg [15:0] pause_quanta_rcvd, output pause_rcvd );
+ reg [7:0] rxd_d1;
+ reg rx_dv_d1, rx_er_d1;
+ assign rx_clk = GMII_RX_CLK;
-
- initial
+ always @(posedge rx_clk)
begin
- pause_rcvd <= 0;
- pause_quanta_rcvd = 10;
- #50000 pause_rcvd <= 1;
- @(posedge rx_clk)
- pause_rcvd <= 0;
- repeat (100)
- @(posedge rx_clk);
- pause_quanta_rcvd <= 15;
- pause_rcvd <= 1;
- @(posedge rx_clk)
- pause_rcvd <= 0;
- repeat (1200)
- @(posedge rx_clk);
- pause_rcvd <= 1;
- @(posedge rx_clk)
- pause_rcvd <= 0;
-
+ rx_dv_d1 <= GMII_RX_DV;
+ rx_er_d1 <= GMII_RX_ER;
+ rxd_d1 <= GMII_RXD;
end
+
+ wire [7:0] rxd_del;
+ wire rx_dv_del, rx_er_del;
+ reg go_filt;
+
+ localparam DELAY = 6;
+ delay_line #(.WIDTH(10)) rx_delay
+ (.clk(rx_clk), .delay(DELAY), .din({rx_dv_d1,rx_er_d1,rxd_d1}),.dout({rx_dv_del,rx_er_dl,rxd_del}));
+
+ assign rx_data = rxd_del;
+ assign rx_error = 0;
+
+ always @(posedge rx_clk)
+ if(reset)
+ rx_ack <= 0;
+ else
+ rx_ack <= (rx_state == RX_GOODFRAME);
+
+ wire is_ucast, is_bcast, is_mcast, is_pause;
+ wire keep_packet = (pass_ucast & is_ucast) | (pass_mcast & is_mcast) |
+ (pass_bcast & is_bcast) | (pass_pause & is_pause) | pass_all;
+
+ reg [7:0] rx_state;
+ always @(posedge rx_clk)
+ if(reset)
+ rx_valid <= 0;
+ else if(keep_packet)
+ rx_valid <= 1;
+ else if((rx_state == RX_IDLE))//|(rx_state == RX_GOODFRAME))
+ rx_valid <= 0;
+
+ address_filter af_ucast (.clk(rx_clk), .reset(reset), .go(go_filt), .data(rxd_d1),
+ .address(ucast_addr), .match(is_ucast), .done());
+ address_filter af_mcast (.clk(rx_clk), .reset(reset), .go(go_filt), .data(rxd_d1),
+ .address(mcast_addr), .match(is_mcast), .done());
+ address_filter af_bcast (.clk(rx_clk), .reset(reset), .go(go_filt), .data(rxd_d1),
+ .address(48'hFFFF_FFFF_FFFF), .match(is_bcast), .done());
+ address_filter af_pause (.clk(rx_clk), .reset(reset), .go(go_filt), .data(rxd_d1),
+ .address(48'h0180_c200_0001), .match(is_pause), .done());
+
+ localparam RX_IDLE = 0;
+ localparam RX_PREAMBLE = 1;
+ localparam RX_FRAME = 2;
+ localparam RX_GOODFRAME = 3;
+ localparam RX_DO_PAUSE = 4;
+ localparam RX_ERROR = 5;
+ localparam RX_DROP = 6;
+
+ localparam RX_PAUSE = 16;
+ localparam RX_PAUSE_CHK88 = RX_PAUSE + 5;
+ localparam RX_PAUSE_CHK08 = RX_PAUSE_CHK88 + 1;
+ localparam RX_PAUSE_CHK00 = RX_PAUSE_CHK08 + 1;
+ localparam RX_PAUSE_CHK01 = RX_PAUSE_CHK00 + 1;
+ localparam RX_PAUSE_STORE_MSB = RX_PAUSE_CHK01 + 1;
+ localparam RX_PAUSE_STORE_LSB = RX_PAUSE_STORE_MSB + 1;
+ localparam RX_PAUSE_WAIT_CRC = RX_PAUSE_STORE_LSB + 1;
+
+
+ always @(posedge rx_clk)
+ go_filt <= (rx_state==RX_PREAMBLE) & (rxd_d1 == 8'hD5);
+
+ reg [15:0] pkt_len_ctr;
+ always @(posedge rx_clk)
+ if(reset |(rx_state == RX_IDLE))
+ pkt_len_ctr <= 0;
+ else
+ pkt_len_ctr <= pkt_len_ctr + 1;
+
+ localparam MIN_PAUSE_LEN = 71; // 6
+ wire pkt_long_enough = (pkt_len_ctr >= MIN_PAUSE_LEN);
+ always @(posedge rx_clk)
+ if(reset)
+ rx_state <= RX_IDLE;
+ else
+ if(rx_er_d1) // | (~pkt_long_enough & ~rx_dv_d1) & (rx_state != RX_IDLE))
+ rx_state <= RX_ERROR;
+ else
+ case(rx_state)
+ RX_IDLE :
+ if(rx_dv_d1)
+ if(rxd_d1 == 8'h55)
+ rx_state <= RX_PREAMBLE;
+ else
+ rx_state <= RX_ERROR;
+ RX_PREAMBLE :
+ if(~rx_dv_d1)
+ rx_state <= RX_ERROR;
+ else if(rxd_d1 == 8'hD5)
+ rx_state <= RX_FRAME;
+ else if(rxd_d1 != 8'h55)
+ rx_state <= RX_ERROR;
+ RX_FRAME :
+ if(is_pause)
+ rx_state <= RX_PAUSE;
+ else if(~rx_dv_d1)
+ if(match_crc)
+ rx_state <= RX_GOODFRAME;
+ else
+ rx_state <= RX_ERROR;
+ RX_PAUSE_CHK88 :
+ if(rxd_d1 != 8'h88)
+ rx_state <= RX_DROP;
+ else
+ rx_state <= RX_PAUSE_CHK08;
+ RX_PAUSE_CHK08 :
+ if(rxd_d1 != 8'h08)
+ rx_state <= RX_DROP;
+ else
+ rx_state <= RX_PAUSE_CHK00;
+ RX_PAUSE_CHK00 :
+ if(rxd_d1 != 8'h00)
+ rx_state <= RX_DROP;
+ else
+ rx_state <= RX_PAUSE_CHK01;
+ RX_PAUSE_CHK01 :
+ if(rxd_d1 != 8'h01)
+ rx_state <= RX_DROP;
+ else
+ rx_state <= RX_PAUSE_STORE_MSB;
+ RX_PAUSE_WAIT_CRC :
+ if(pkt_long_enough)
+ if(match_crc)
+ rx_state <= RX_DO_PAUSE;
+ else
+ rx_state <= RX_DROP;
+ RX_DO_PAUSE :
+ rx_state <= RX_IDLE;
+ RX_GOODFRAME :
+ rx_state <= RX_IDLE;
+ RX_DROP, RX_ERROR :
+ if(~rx_dv_d1)
+ rx_state <= RX_IDLE;
+ default
+ rx_state <= rx_state + 1;
+ endcase // case (rx_state)
+
+ assign pause_rcvd = (rx_state == RX_DO_PAUSE);
+ wire match_crc;
+ wire clear_crc = rx_state == RX_IDLE;
+ wire calc_crc = (rx_state == RX_FRAME) | rx_state[7:4]==4'h1;
+ crc crc_check(.clk(rx_clk),.reset(reset),.clear(clear_crc),
+ .data(rxd_d1),.calc(calc_crc),.crc_out(),.match(match_crc));
+
+ always @(posedge rx_clk)
+ if(reset)
+ pause_quanta_rcvd <= 0;
+ else if(rx_state == RX_PAUSE_STORE_MSB)
+ pause_quanta_rcvd[15:8] <= rxd_d1;
+ else if(rx_state == RX_PAUSE_STORE_LSB)
+ pause_quanta_rcvd[7:0] <= rxd_d1;
- assign rx_clk = GMII_RX_CLK;
+ assign rx_clk = GMII_RX_CLK;
endmodule // simple_gemac_rx
diff --git a/simple_gemac/simple_gemac_tb.v b/simple_gemac/simple_gemac_tb.v
index 481c6ebab..434c84a4a 100644
--- a/simple_gemac/simple_gemac_tb.v
+++ b/simple_gemac/simple_gemac_tb.v
@@ -19,14 +19,19 @@ module simple_gemac_tb;
wire [7:0] rx_data;
reg [7:0] tx_data;
- wire [15:0] pause_time = 16'hBEEF;
+ reg [15:0] pause_time;
reg pause_req = 0;
- reg GMII_RX_CLK;
- always @(GMII_GTX_CLK)
- GMII_RX_CLK <= #30 GMII_GTX_CLK;
+// reg GMII_RX_CLK;
+// always @(GMII_GTX_CLK)
+// GMII_RX_CLK <= #30 GMII_GTX_CLK;
-// wire GMII_RX_CLK = #30 GMII_GTX_CLK;
+ wire GMII_RX_CLK = GMII_GTX_CLK;
+
+ // Loopback
+ assign GMII_RX_DV = GMII_TX_EN;
+ assign GMII_RX_ER = GMII_TX_ER;
+ assign GMII_RXD = GMII_TXD;
simple_gemac simple_gemac
(.clk125(clk), .reset(reset),
@@ -42,15 +47,17 @@ module simple_gemac_tb;
);
task SendFlowCtrl;
- begin
- $display("Sending Flow Control, %d", $time);
- @(posedge clk);
- pause_req <= 1;
- @(posedge clk);
- pause_req <= 0;
- end
+ input [15:0] fc_len;
+ begin
+ $display("Sending Flow Control, quanta = %d, time = %d", fc_len,$time);
+ pause_time = fc_len;
+ @(posedge clk);
+ pause_req <= 1;
+ @(posedge clk);
+ pause_req <= 0;
+ end
endtask // SendFlowCtrl
-
+
reg [31:0] count;
task SendPacket;
input [7:0] data_start;
@@ -115,13 +122,18 @@ module simple_gemac_tb;
@(negedge reset);
repeat (10)
@(posedge clk);
- SendFlowCtrl;
- repeat (20)
- @(posedge clk);
- SendPacket(8'hAA,10);
+ SendFlowCtrl(16'h0007); // Send flow control
+ #30000;
+ @(posedge clk);
+ SendFlowCtrl(16'h0009); // Increas flow control before it expires
+ #10000;
+ @(posedge clk);
+ SendFlowCtrl(16'h0000); // Cancel flow control befor it expires
+ @(posedge clk);
+ SendPacket(8'hAA,10); // This packet gets dropped by the filters
repeat (10)
@(posedge clk);
- SendPacketFromFile(60);
+ SendPacketFromFile(60); // The rest are valid packets
repeat (10)
@(posedge clk);
SendPacketFromFile(61);