Files
b210-k7-fpga/lib/xge/rtl/verilog/tx_dequeue.v
T
Ben Hilburn fbbc991a7d Pushing the bulk of UHD-3.7.0 code.
Original-commit: ff1546f8137f7f92bb250f685561b0c34cc0e053
2014-02-14 12:05:07 -08:00

939 lines
28 KiB
Verilog

//////////////////////////////////////////////////////////////////////
//// ////
//// 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