diff options
Diffstat (limited to 'simple_gemac')
-rw-r--r-- | simple_gemac/simple_gemac_rx.v | 184 | ||||
-rw-r--r-- | simple_gemac/simple_gemac_tb.v | 48 |
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); |