aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/xge/rtl/verilog/tx_dequeue.v
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/lib/xge/rtl/verilog/tx_dequeue.v')
-rw-r--r--fpga/usrp3/lib/xge/rtl/verilog/tx_dequeue.v938
1 files changed, 938 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/xge/rtl/verilog/tx_dequeue.v b/fpga/usrp3/lib/xge/rtl/verilog/tx_dequeue.v
new file mode 100644
index 000000000..8444514ee
--- /dev/null
+++ b/fpga/usrp3/lib/xge/rtl/verilog/tx_dequeue.v
@@ -0,0 +1,938 @@
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// File name "tx_dequeue.v" ////
+//// ////
+//// This file is part of the "10GE MAC" project ////
+//// http://www.opencores.org/cores/xge_mac/ ////
+//// ////
+//// Author(s): ////
+//// - A. Tanguay (antanguay@opencores.org) ////
+//// ////
+//////////////////////////////////////////////////////////////////////
+//// ////
+//// Copyright (C) 2008 AUTHORS. All rights reserved. ////
+//// ////
+//// This source file may be used and distributed without ////
+//// restriction provided that this copyright statement is not ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer. ////
+//// ////
+//// This source file is free software; you can redistribute it ////
+//// and/or modify it under the terms of the GNU Lesser General ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any ////
+//// later version. ////
+//// ////
+//// This source is distributed in the hope that it will be ////
+//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
+//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
+//// PURPOSE. See the GNU Lesser General Public License for more ////
+//// details. ////
+//// ////
+//// You should have received a copy of the GNU Lesser General ////
+//// Public License along with this source; if not, download it ////
+//// from http://www.opencores.org/lgpl.shtml ////
+//// ////
+//////////////////////////////////////////////////////////////////////
+
+
+`include "defines.v"
+
+module tx_dequeue(/*AUTOARG*/
+ // Outputs
+ txdfifo_ren, txhfifo_ren, txhfifo_wdata, txhfifo_wstatus,
+ txhfifo_wen, xgmii_txd, xgmii_txc, status_txdfifo_udflow_tog,
+ // Inputs
+ clk_xgmii_tx, reset_xgmii_tx_n, ctrl_tx_enable_ctx,
+ status_local_fault_ctx, status_remote_fault_ctx, txdfifo_rdata,
+ txdfifo_rstatus, txdfifo_rempty, txdfifo_ralmost_empty,
+ txhfifo_rdata, txhfifo_rstatus, txhfifo_rempty,
+ txhfifo_ralmost_empty, txhfifo_wfull, txhfifo_walmost_full
+ );
+`include "CRC32_D64.v"
+`include "CRC32_D8.v"
+`include "utils.v"
+
+input clk_xgmii_tx;
+input reset_xgmii_tx_n;
+
+input ctrl_tx_enable_ctx;
+
+input status_local_fault_ctx;
+input status_remote_fault_ctx;
+
+input [63:0] txdfifo_rdata;
+input [7:0] txdfifo_rstatus;
+input txdfifo_rempty;
+input txdfifo_ralmost_empty;
+
+input [63:0] txhfifo_rdata;
+input [7:0] txhfifo_rstatus;
+input txhfifo_rempty;
+input txhfifo_ralmost_empty;
+
+input txhfifo_wfull;
+input txhfifo_walmost_full;
+
+output txdfifo_ren;
+
+output txhfifo_ren;
+
+output [63:0] txhfifo_wdata;
+output [7:0] txhfifo_wstatus;
+output txhfifo_wen;
+
+output [63:0] xgmii_txd;
+output [7:0] xgmii_txc;
+
+output status_txdfifo_udflow_tog;
+
+
+
+
+/*AUTOREG*/
+// Beginning of automatic regs (for this module's undeclared outputs)
+reg status_txdfifo_udflow_tog;
+reg txdfifo_ren;
+reg txhfifo_ren;
+reg [63:0] txhfifo_wdata;
+reg txhfifo_wen;
+reg [7:0] txhfifo_wstatus;
+reg [7:0] xgmii_txc;
+reg [63:0] xgmii_txd;
+// End of automatics
+
+/*AUTOWIRE*/
+
+
+reg [63:0] xgxs_txd;
+reg [7:0] xgxs_txc;
+
+reg [63:0] next_xgxs_txd;
+reg [7:0] next_xgxs_txc;
+
+reg [2:0] curr_state_enc;
+reg [2:0] next_state_enc;
+
+reg [0:0] curr_state_pad;
+reg [0:0] next_state_pad;
+
+reg start_on_lane0;
+reg next_start_on_lane0;
+
+reg [2:0] ifg_deficit;
+reg [2:0] next_ifg_deficit;
+
+reg ifg_4b_add;
+reg next_ifg_4b_add;
+
+reg ifg_8b_add;
+reg next_ifg_8b_add;
+
+reg ifg_8b2_add;
+reg next_ifg_8b2_add;
+
+reg [7:0] eop;
+reg [7:0] next_eop;
+
+reg [63:32] xgxs_txd_barrel;
+reg [7:4] xgxs_txc_barrel;
+
+reg [63:0] txhfifo_rdata_d1;
+
+reg [13:0] byte_cnt;
+
+reg [31:0] crc32_d64;
+reg [31:0] crc32_d8;
+reg [31:0] crc32_tx;
+
+reg [63:0] shift_crc_data;
+reg [3:0] shift_crc_eop;
+reg [3:0] shift_crc_cnt;
+
+reg [31:0] crc_data;
+
+reg frame_available;
+reg next_frame_available;
+
+reg [63:0] next_txhfifo_wdata;
+reg [7:0] next_txhfifo_wstatus;
+reg next_txhfifo_wen;
+
+reg txdfifo_ren_d1;
+
+parameter [2:0]
+ SM_IDLE = 3'd0,
+ SM_PREAMBLE = 3'd1,
+ SM_TX = 3'd2,
+ SM_EOP = 3'd3,
+ SM_TERM = 3'd4,
+ SM_TERM_FAIL = 3'd5,
+ SM_IFG = 3'd6;
+
+parameter [0:0]
+ SM_PAD_EQ = 1'd0,
+ SM_PAD_PAD = 1'd1;
+
+
+//---
+// RC layer
+
+always @(posedge clk_xgmii_tx or negedge reset_xgmii_tx_n) begin
+
+ if (reset_xgmii_tx_n == 1'b0) begin
+
+ xgmii_txd <= {8{`IDLE}};
+ xgmii_txc <= 8'hff;
+
+ end
+ else begin
+
+
+ //---
+ // RC Layer, insert local or remote fault messages based on status
+ // of fault state-machine
+
+ if (status_local_fault_ctx) begin
+
+ // If local fault detected, send remote fault message to
+ // link partner
+
+ xgmii_txd <= {`REMOTE_FAULT, 8'h0, 8'h0, `SEQUENCE,
+ `REMOTE_FAULT, 8'h0, 8'h0, `SEQUENCE};
+ xgmii_txc <= {4'b0001, 4'b0001};
+ end
+ else if (status_remote_fault_ctx) begin
+
+ // If remote fault detected, inhibit transmission and send
+ // idle codes
+
+ xgmii_txd <= {8{`IDLE}};
+ xgmii_txc <= 8'hff;
+ end
+ else begin
+ xgmii_txd <= xgxs_txd;
+ xgmii_txc <= xgxs_txc;
+ end
+ end
+
+end
+
+
+always @(posedge clk_xgmii_tx or negedge reset_xgmii_tx_n) begin
+
+ if (reset_xgmii_tx_n == 1'b0) begin
+
+ curr_state_enc <= SM_IDLE;
+
+ start_on_lane0 <= 1'b1;
+ ifg_deficit <= 3'b0;
+ ifg_4b_add <= 1'b0;
+ ifg_8b_add <= 1'b0;
+ ifg_8b2_add <= 1'b0;
+
+ eop <= 8'b0;
+
+ txhfifo_rdata_d1 <= 64'b0;
+
+ xgxs_txd_barrel <= {4{`IDLE}};
+ xgxs_txc_barrel <= 4'hf;
+
+ frame_available <= 1'b0;
+
+ xgxs_txd <= {8{`IDLE}};
+ xgxs_txc <= 8'hff;
+
+ status_txdfifo_udflow_tog <= 1'b0;
+
+ end
+ else begin
+
+ curr_state_enc <= next_state_enc;
+
+ start_on_lane0 <= next_start_on_lane0;
+ ifg_deficit <= next_ifg_deficit;
+ ifg_4b_add <= next_ifg_4b_add;
+ ifg_8b_add <= next_ifg_8b_add;
+ ifg_8b2_add <= next_ifg_8b2_add;
+
+ eop <= next_eop;
+
+ txhfifo_rdata_d1 <= txhfifo_rdata;
+
+ xgxs_txd_barrel <= next_xgxs_txd[63:32];
+ xgxs_txc_barrel <= next_xgxs_txc[7:4];
+
+ frame_available <= next_frame_available;
+
+ //---
+ // Barrel shifter. Previous stage always align packet with LANE0.
+ // This stage allow us to shift packet to align with LANE4 if needed
+ // for correct inter frame gap (IFG).
+
+ if (next_start_on_lane0) begin
+
+ xgxs_txd <= next_xgxs_txd;
+ xgxs_txc <= next_xgxs_txc;
+
+ end
+ else begin
+
+ xgxs_txd <= {next_xgxs_txd[31:0], xgxs_txd_barrel};
+ xgxs_txc <= {next_xgxs_txc[3:0], xgxs_txc_barrel};
+
+ end
+
+ //---
+ // FIFO errors, used to generate interrupts.
+
+ if (txdfifo_ren && txdfifo_rempty) begin
+ status_txdfifo_udflow_tog <= ~status_txdfifo_udflow_tog;
+ end
+
+ end
+
+end
+
+always @(/*AS*/crc32_tx or ctrl_tx_enable_ctx or curr_state_enc or eop
+ or frame_available or ifg_4b_add or ifg_8b2_add or ifg_8b_add
+ or ifg_deficit or start_on_lane0 or status_local_fault_ctx
+ or txhfifo_ralmost_empty or txhfifo_rdata_d1
+ or txhfifo_rempty or txhfifo_rstatus) begin
+
+ next_state_enc = curr_state_enc;
+
+ next_start_on_lane0 = start_on_lane0;
+ next_ifg_deficit = ifg_deficit;
+ next_ifg_4b_add = ifg_4b_add;
+ next_ifg_8b_add = ifg_8b_add;
+ next_ifg_8b2_add = ifg_8b2_add;
+
+ next_eop = eop;
+
+ next_xgxs_txd = {8{`IDLE}};
+ next_xgxs_txc = 8'hff;
+
+ txhfifo_ren = 1'b0;
+
+ next_frame_available = frame_available;
+
+ case (curr_state_enc)
+
+ SM_IDLE:
+ begin
+
+ // Wait for frame to be available. There should be a least N bytes in the
+ // data fifo or a crc in the control fifo. The N bytes in the data fifo
+ // give time to the enqueue engine to calculate crc and write it to the
+ // control fifo. If crc is already in control fifo we can start transmitting
+ // with no concern. Transmission is inhibited if local or remote faults
+ // are detected.
+
+ if (ctrl_tx_enable_ctx && frame_available &&
+ !status_local_fault_ctx && !status_local_fault_ctx) begin
+
+ txhfifo_ren = 1'b1;
+ next_state_enc = SM_PREAMBLE;
+
+ end
+ else begin
+
+ next_frame_available = !txhfifo_ralmost_empty;
+ next_ifg_4b_add = 1'b0;
+
+ end
+
+ end
+
+ SM_PREAMBLE:
+ begin
+
+ // On reading SOP from fifo, send SFD and preamble characters
+
+ if (txhfifo_rstatus[`TXSTATUS_SOP]) begin
+
+ next_xgxs_txd = {`SFD, {6{`PREAMBLE}}, `START};
+ next_xgxs_txc = 8'h01;
+
+ txhfifo_ren = 1'b1;
+
+ next_state_enc = SM_TX;
+
+ end
+ else begin
+
+ next_frame_available = 1'b0;
+ next_state_enc = SM_IDLE;
+
+ end
+
+
+ // Depending on deficit idle count calculations, add 4 bytes
+ // or IFG or not. This will determine on which lane start the
+ // next frame.
+
+ if (ifg_4b_add) begin
+ next_start_on_lane0 = 1'b0;
+ end
+ else begin
+ next_start_on_lane0 = 1'b1;
+ end
+
+ end
+
+ SM_TX:
+ begin
+
+ next_xgxs_txd = txhfifo_rdata_d1;
+ next_xgxs_txc = 8'h00;
+
+ txhfifo_ren = 1'b1;
+
+
+ // Wait for EOP indication to be read from the fifo, then
+ // transition to next state.
+
+ if (txhfifo_rstatus[`TXSTATUS_EOP]) begin
+
+ txhfifo_ren = 1'b0;
+ next_frame_available = !txhfifo_ralmost_empty;
+ next_state_enc = SM_EOP;
+
+ end
+ else if (txhfifo_rempty || txhfifo_rstatus[`TXSTATUS_SOP]) begin
+
+ // Failure condition, we did not see EOP and there
+ // is no more data in fifo or SOP, force end of packet transmit.
+
+ next_state_enc = SM_TERM_FAIL;
+
+ end
+
+ next_eop[0] = txhfifo_rstatus[2:0] == 3'd1;
+ next_eop[1] = txhfifo_rstatus[2:0] == 3'd2;
+ next_eop[2] = txhfifo_rstatus[2:0] == 3'd3;
+ next_eop[3] = txhfifo_rstatus[2:0] == 3'd4;
+ next_eop[4] = txhfifo_rstatus[2:0] == 3'd5;
+ next_eop[5] = txhfifo_rstatus[2:0] == 3'd6;
+ next_eop[6] = txhfifo_rstatus[2:0] == 3'd7;
+ next_eop[7] = txhfifo_rstatus[2:0] == 3'd0;
+
+ end
+
+ SM_EOP:
+ begin
+
+ // Insert TERMINATE character in correct lane depending on position
+ // of EOP read from fifo. Also insert CRC read from control fifo.
+
+ if (eop[0]) begin
+ next_xgxs_txd = {{2{`IDLE}}, `TERMINATE,
+ crc32_tx[31:0], txhfifo_rdata_d1[7:0]};
+ next_xgxs_txc = 8'b11100000;
+ end
+
+ if (eop[1]) begin
+ next_xgxs_txd = {`IDLE, `TERMINATE,
+ crc32_tx[31:0], txhfifo_rdata_d1[15:0]};
+ next_xgxs_txc = 8'b11000000;
+ end
+
+ if (eop[2]) begin
+ next_xgxs_txd = {`TERMINATE, crc32_tx[31:0], txhfifo_rdata_d1[23:0]};
+ next_xgxs_txc = 8'b10000000;
+ end
+
+ if (eop[3]) begin
+ next_xgxs_txd = {crc32_tx[31:0], txhfifo_rdata_d1[31:0]};
+ next_xgxs_txc = 8'b00000000;
+ end
+
+ if (eop[4]) begin
+ next_xgxs_txd = {crc32_tx[23:0], txhfifo_rdata_d1[39:0]};
+ next_xgxs_txc = 8'b00000000;
+ end
+
+ if (eop[5]) begin
+ next_xgxs_txd = {crc32_tx[15:0], txhfifo_rdata_d1[47:0]};
+ next_xgxs_txc = 8'b00000000;
+ end
+
+ if (eop[6]) begin
+ next_xgxs_txd = {crc32_tx[7:0], txhfifo_rdata_d1[55:0]};
+ next_xgxs_txc = 8'b00000000;
+ end
+
+ if (eop[7]) begin
+ next_xgxs_txd = {txhfifo_rdata_d1[63:0]};
+ next_xgxs_txc = 8'b00000000;
+ end
+
+ if (!frame_available) begin
+
+ // If there is not another frame ready to be transmitted, interface
+ // will go idle and idle deficit idle count calculation is irrelevant.
+ // Set deficit to 0.
+
+ next_ifg_deficit = 3'b0;
+
+ end
+ else begin
+
+ // Idle deficit count calculated based on number of "wasted" bytes
+ // between TERMINATE and alignment of next frame in LANE0.
+
+ next_ifg_deficit = ifg_deficit +
+ {2'b0, eop[0] | eop[4]} +
+ {1'b0, eop[1] | eop[5], 1'b0} +
+ {1'b0, eop[2] | eop[6],
+ eop[2] | eop[6]};
+ end
+
+ // IFG corrections based on deficit count and previous starting lane
+ // Calculated based on following table:
+ //
+ // DIC=0 DIC=1 DIC=2 DIC=3
+ // ------------- ------------- ------------- -------------
+ // PktLen IFG Next IFG Next IFG Next IFG Next
+ // Modulus Length DIC Length DIC Length DIC Length DIC
+ // -----------------------------------------------------------------------
+ // 0 12 0 12 1 12 2 12 3
+ // 1 11 1 11 2 11 3 15 0
+ // 2 10 2 10 3 14 0 14 1
+ // 3 9 3 13 0 13 1 13 2
+ //
+ //
+ // In logic it translates into adding 4, 8, or 12 bytes of IFG relative
+ // to LANE0.
+ // IFG and Add columns assume no deficit applied
+ // IFG+DIC and Add+DIC assume deficit must be applied
+ //
+ // Start lane 0 Start lane 4
+ // EOP Pads IFG IFG+DIC Add Add+DIC Add Add IFG
+ // 0 3 11 15 8 12 12 16
+ // 1 2 10 14 8 12 12 16
+ // 2 1 9 13 8 12 12 16
+ // 3 8 12 12 4 4 8 8
+ // 4 7 11 15 4 8 8 12
+ // 5 6 10 14 4 8 8 12
+ // 6 5 9 13 4 8 8 12
+ // 7 4 12 12 8 8 12 12
+
+ if (!frame_available) begin
+
+ // If there is not another frame ready to be transmitted, interface
+ // will go idle and idle deficit idle count calculation is irrelevant.
+
+ next_ifg_4b_add = 1'b0;
+ next_ifg_8b_add = 1'b0;
+ next_ifg_8b2_add = 1'b0;
+
+ end
+ else if (next_ifg_deficit[2] == ifg_deficit[2]) begin
+
+ // Add 4 bytes IFG
+
+ next_ifg_4b_add = (eop[0] & !start_on_lane0) |
+ (eop[1] & !start_on_lane0) |
+ (eop[2] & !start_on_lane0) |
+ (eop[3] & start_on_lane0) |
+ (eop[4] & start_on_lane0) |
+ (eop[5] & start_on_lane0) |
+ (eop[6] & start_on_lane0) |
+ (eop[7] & !start_on_lane0);
+
+ // Add 8 bytes IFG
+
+ next_ifg_8b_add = (eop[0]) |
+ (eop[1]) |
+ (eop[2]) |
+ (eop[3] & !start_on_lane0) |
+ (eop[4] & !start_on_lane0) |
+ (eop[5] & !start_on_lane0) |
+ (eop[6] & !start_on_lane0) |
+ (eop[7]);
+
+ // Add another 8 bytes IFG
+
+ next_ifg_8b2_add = 1'b0;
+
+ end
+ else begin
+
+ // Add 4 bytes IFG
+
+ next_ifg_4b_add = (eop[0] & start_on_lane0) |
+ (eop[1] & start_on_lane0) |
+ (eop[2] & start_on_lane0) |
+ (eop[3] & start_on_lane0) |
+ (eop[4] & !start_on_lane0) |
+ (eop[5] & !start_on_lane0) |
+ (eop[6] & !start_on_lane0) |
+ (eop[7] & !start_on_lane0);
+
+ // Add 8 bytes IFG
+
+ next_ifg_8b_add = (eop[0]) |
+ (eop[1]) |
+ (eop[2]) |
+ (eop[3] & !start_on_lane0) |
+ (eop[4]) |
+ (eop[5]) |
+ (eop[6]) |
+ (eop[7]);
+
+ // Add another 8 bytes IFG
+
+ next_ifg_8b2_add = (eop[0] & !start_on_lane0) |
+ (eop[1] & !start_on_lane0) |
+ (eop[2] & !start_on_lane0);
+
+ end
+
+ if (|eop[2:0]) begin
+
+ if (frame_available) begin
+
+ // Next state depends on number of IFG bytes to be inserted.
+ // Skip idle state if needed.
+
+ if (next_ifg_8b2_add) begin
+ next_state_enc = SM_IFG;
+ end
+ else if (next_ifg_8b_add) begin
+ next_state_enc = SM_IDLE;
+ end
+ else begin
+ txhfifo_ren = 1'b1;
+ next_state_enc = SM_PREAMBLE;
+ end
+
+ end
+ else begin
+ next_state_enc = SM_IFG;
+ end
+ end
+
+ if (|eop[7:3]) begin
+ next_state_enc = SM_TERM;
+ end
+
+ end
+
+ SM_TERM:
+ begin
+
+ // Insert TERMINATE character in correct lane depending on position
+ // of EOP read from fifo. Also insert CRC read from control fifo.
+
+ if (eop[3]) begin
+ next_xgxs_txd = {{7{`IDLE}}, `TERMINATE};
+ next_xgxs_txc = 8'b11111111;
+ end
+
+ if (eop[4]) begin
+ next_xgxs_txd = {{6{`IDLE}}, `TERMINATE, crc32_tx[31:24]};
+ next_xgxs_txc = 8'b11111110;
+ end
+
+ if (eop[5]) begin
+ next_xgxs_txd = {{5{`IDLE}}, `TERMINATE, crc32_tx[31:16]};
+ next_xgxs_txc = 8'b11111100;
+ end
+
+ if (eop[6]) begin
+ next_xgxs_txd = {{4{`IDLE}}, `TERMINATE, crc32_tx[31:8]};
+ next_xgxs_txc = 8'b11111000;
+ end
+
+ if (eop[7]) begin
+ next_xgxs_txd = {{3{`IDLE}}, `TERMINATE, crc32_tx[31:0]};
+ next_xgxs_txc = 8'b11110000;
+ end
+
+ // Next state depends on number of IFG bytes to be inserted.
+ // Skip idle state if needed.
+
+ if (frame_available && !ifg_8b_add) begin
+ txhfifo_ren = 1'b1;
+ next_state_enc = SM_PREAMBLE;
+ end
+ else if (frame_available) begin
+ next_state_enc = SM_IDLE;
+ end
+ else begin
+ next_state_enc = SM_IFG;
+ end
+
+ end
+
+ SM_TERM_FAIL:
+ begin
+
+ next_xgxs_txd = {{7{`IDLE}}, `TERMINATE};
+ next_xgxs_txc = 8'b11111111;
+ next_state_enc = SM_IFG;
+
+ end
+
+ SM_IFG:
+ begin
+
+ next_state_enc = SM_IDLE;
+
+ end
+
+ default:
+ begin
+ next_state_enc = SM_IDLE;
+ end
+
+ endcase
+
+end
+
+
+always @(/*AS*/crc32_d64 or txhfifo_wen or txhfifo_wstatus) begin
+
+ if (txhfifo_wen && txhfifo_wstatus[`TXSTATUS_SOP]) begin
+ crc_data = 32'hffffffff;
+ end
+ else begin
+ crc_data = crc32_d64;
+ end
+
+end
+
+always @(/*AS*/byte_cnt or curr_state_pad or txdfifo_rdata
+ or txdfifo_rempty or txdfifo_ren_d1 or txdfifo_rstatus
+ or txhfifo_walmost_full) begin
+
+ next_state_pad = curr_state_pad;
+
+ next_txhfifo_wdata = txdfifo_rdata;
+ next_txhfifo_wstatus = txdfifo_rstatus;
+
+ txdfifo_ren = 1'b0;
+ next_txhfifo_wen = 1'b0;
+
+ case (curr_state_pad)
+
+ SM_PAD_EQ: begin
+
+
+ //---
+ // If room availabe in hoding fifo and data available in
+ // data fifo, transfer data words. If transmit state machine
+ // is reading from fifo we can assume room will be available.
+
+ if (!txhfifo_walmost_full) begin
+
+ txdfifo_ren = !txdfifo_rempty;
+
+ end
+
+
+ //---
+ // This logic dependent on read during previous cycle.
+
+ if (txdfifo_ren_d1) begin
+
+ next_txhfifo_wen = 1'b1;
+
+ // On EOP, decide if padding is required for this packet.
+
+ if (txdfifo_rstatus[`TXSTATUS_EOP]) begin
+
+ if (byte_cnt < 14'd56) begin
+
+ next_txhfifo_wstatus = `TXSTATUS_NONE;
+ txdfifo_ren = 1'b0;
+ next_state_pad = SM_PAD_PAD;
+
+ end
+ else if (byte_cnt == 14'd56 &&
+ (txdfifo_rstatus[2:0] == 3'd1 ||
+ txdfifo_rstatus[2:0] == 3'd2 ||
+ txdfifo_rstatus[2:0] == 3'd3)) begin
+
+ // Pad up to LANE3, keep the other 4 bytes for crc that will
+ // be inserted by dequeue engine.
+
+ next_txhfifo_wstatus[2:0] = 3'd4;
+
+ // Pad end bytes with zeros.
+
+ if (txdfifo_rstatus[2:0] == 3'd1)
+ next_txhfifo_wdata[31:8] = 24'b0;
+ if (txdfifo_rstatus[2:0] == 3'd2)
+ next_txhfifo_wdata[31:16] = 16'b0;
+ if (txdfifo_rstatus[2:0] == 3'd3)
+ next_txhfifo_wdata[31:24] = 8'b0;
+
+ txdfifo_ren = 1'b0;
+
+ end
+ else begin
+
+ txdfifo_ren = 1'b0;
+
+ end
+
+ end
+
+ end
+
+ end
+
+ SM_PAD_PAD: begin
+
+ //---
+ // Pad packet to 64 bytes by writting zeros to holding fifo.
+
+ if (!txhfifo_walmost_full) begin
+
+ next_txhfifo_wdata = 64'b0;
+ next_txhfifo_wstatus = `TXSTATUS_NONE;
+ next_txhfifo_wen = 1'b1;
+
+ if (byte_cnt == 14'd56) begin
+
+
+ // Pad up to LANE3, keep the other 4 bytes for crc that will
+ // be inserted by dequeue engine.
+
+ next_txhfifo_wstatus[`TXSTATUS_EOP] = 1'b1;
+ next_txhfifo_wstatus[2:0] = 3'd4;
+
+ next_state_pad = SM_PAD_EQ;
+
+ end
+
+ end
+
+ end
+
+ default:
+ begin
+ next_state_pad = SM_PAD_EQ;
+ end
+
+ endcase
+
+end
+
+
+always @(posedge clk_xgmii_tx or negedge reset_xgmii_tx_n) begin
+
+ if (reset_xgmii_tx_n == 1'b0) begin
+
+ curr_state_pad <= SM_PAD_EQ;
+
+ txdfifo_ren_d1 <= 1'b0;
+
+ txhfifo_wdata <= 64'b0;
+ txhfifo_wstatus <= 8'b0;
+ txhfifo_wen <= 1'b0;
+
+ byte_cnt <= 14'b0;
+
+ shift_crc_data <= 64'b0;
+ shift_crc_eop <= 4'b0;
+ shift_crc_cnt <= 4'b0;
+
+ end
+ else begin
+
+ curr_state_pad <= next_state_pad;
+
+ txdfifo_ren_d1 <= txdfifo_ren;
+
+ txhfifo_wdata <= next_txhfifo_wdata;
+ txhfifo_wstatus <= next_txhfifo_wstatus;
+ txhfifo_wen <= next_txhfifo_wen;
+
+
+ //---
+ // Reset byte count on SOP
+
+ if (next_txhfifo_wen) begin
+
+ if (next_txhfifo_wstatus[`TXSTATUS_SOP]) begin
+
+ byte_cnt <= 14'd8;
+
+ end
+ else begin
+
+ byte_cnt <= byte_cnt + 14'd8;
+
+ end
+
+ end
+
+
+ //---
+ // Calculate CRC as data is written to holding fifo. The holding fifo creates
+ // a delay that allow the CRC calculation to complete before the end of the frame
+ // is ready to be transmited.
+
+ if (txhfifo_wen) begin
+
+ crc32_d64 <= nextCRC32_D64(reverse_64b(txhfifo_wdata), crc_data);
+
+ end
+
+ if (txhfifo_wen && txhfifo_wstatus[`TXSTATUS_EOP]) begin
+
+ // Last bytes calculated 8-bit at a time instead of 64-bit. Start
+ // this process at the end of the frame.
+
+ crc32_d8 <= crc32_d64;
+
+ shift_crc_data <= txhfifo_wdata;
+ shift_crc_cnt <= 4'd9;
+
+ if (txhfifo_wstatus[2:0] == 3'b0) begin
+ shift_crc_eop <= 4'd8;
+ end
+ else begin
+ shift_crc_eop <= {1'b0, txhfifo_wstatus[2:0]};
+ end
+
+ end
+ else if (shift_crc_eop != 4'b0) begin
+
+ // Complete crc calculation 8-bit at a time until finished. This can
+ // be 1 to 8 bytes long.
+
+ crc32_d8 <= nextCRC32_D8(reverse_8b(shift_crc_data[7:0]), crc32_d8);
+
+ shift_crc_data <= {8'b0, shift_crc_data[63:8]};
+ shift_crc_eop <= shift_crc_eop - 4'd1;
+
+ end
+
+
+ //---
+ // Update CRC register at the end of calculation. Always update after 8
+ // cycles for deterministic results, even if a single byte was present in
+ // last data word.
+
+ if (shift_crc_cnt == 4'b1) begin
+
+ crc32_tx <= ~reverse_32b(crc32_d8);
+
+ end
+ else begin
+
+ shift_crc_cnt <= shift_crc_cnt - 4'd1;
+
+ end
+
+ end
+
+end
+
+endmodule
+