diff options
author | Martin Braun <martin.braun@ettus.com> | 2020-01-23 16:10:22 -0800 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2020-01-28 09:35:36 -0800 |
commit | bafa9d95453387814ef25e6b6256ba8db2df612f (patch) | |
tree | 39ba24b5b67072d354775272e687796bb511848d /fpga/usrp3/lib/xge/rtl/verilog/rx_enqueue.v | |
parent | 3075b981503002df3115d5f1d0b97d2619ba30f2 (diff) | |
download | uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.tar.gz uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.tar.bz2 uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.zip |
Merge FPGA repository back into UHD repository
The FPGA codebase was removed from the UHD repository in 2014 to reduce
the size of the repository. However, over the last half-decade, the
split between the repositories has proven more burdensome than it has
been helpful. By merging the FPGA code back, it will be possible to
create atomic commits that touch both FPGA and UHD codebases. Continuous
integration testing is also simplified by merging the repositories,
because it was previously difficult to automatically derive the correct
UHD branch when testing a feature branch on the FPGA repository.
This commit also updates the license files and paths therein.
We are therefore merging the repositories again. Future development for
FPGA code will happen in the same repository as the UHD host code and
MPM code.
== Original Codebase and Rebasing ==
The original FPGA repository will be hosted for the foreseeable future
at its original local location: https://github.com/EttusResearch/fpga/
It can be used for bisecting, reference, and a more detailed history.
The final commit from said repository to be merged here is
05003794e2da61cabf64dd278c45685a7abad7ec. This commit is tagged as
v4.0.0.0-pre-uhd-merge.
If you have changes in the FPGA repository that you want to rebase onto
the UHD repository, simply run the following commands:
- Create a directory to store patches (this should be an empty
directory):
mkdir ~/patches
- Now make sure that your FPGA codebase is based on the same state as
the code that was merged:
cd src/fpga # Or wherever your FPGA code is stored
git rebase v4.0.0.0-pre-uhd-merge
Note: The rebase command may look slightly different depending on what
exactly you're trying to rebase.
- Create a patch set for your changes versus v4.0.0.0-pre-uhd-merge:
git format-patch v4.0.0.0-pre-uhd-merge -o ~/patches
Note: Make sure that only patches are stored in your output directory.
It should otherwise be empty. Make sure that you picked the correct
range of commits, and only commits you wanted to rebase were exported
as patch files.
- Go to the UHD repository and apply the patches:
cd src/uhd # Or wherever your UHD repository is stored
git am --directory fpga ~/patches/*
rm -rf ~/patches # This is for cleanup
== Contributors ==
The following people have contributed mainly to these files (this list
is not complete):
Co-authored-by: Alex Williams <alex.williams@ni.com>
Co-authored-by: Andrej Rode <andrej.rode@ettus.com>
Co-authored-by: Ashish Chaudhari <ashish@ettus.com>
Co-authored-by: Ben Hilburn <ben.hilburn@ettus.com>
Co-authored-by: Ciro Nishiguchi <ciro.nishiguchi@ni.com>
Co-authored-by: Daniel Jepson <daniel.jepson@ni.com>
Co-authored-by: Derek Kozel <derek.kozel@ettus.com>
Co-authored-by: EJ Kreinar <ej@he360.com>
Co-authored-by: Humberto Jimenez <humberto.jimenez@ni.com>
Co-authored-by: Ian Buckley <ian.buckley@gmail.com>
Co-authored-by: Jörg Hofrichter <joerg.hofrichter@ni.com>
Co-authored-by: Jon Kiser <jon.kiser@ni.com>
Co-authored-by: Josh Blum <josh@joshknows.com>
Co-authored-by: Jonathon Pendlum <jonathan.pendlum@ettus.com>
Co-authored-by: Martin Braun <martin.braun@ettus.com>
Co-authored-by: Matt Ettus <matt@ettus.com>
Co-authored-by: Michael West <michael.west@ettus.com>
Co-authored-by: Moritz Fischer <moritz.fischer@ettus.com>
Co-authored-by: Nick Foster <nick@ettus.com>
Co-authored-by: Nicolas Cuervo <nicolas.cuervo@ettus.com>
Co-authored-by: Paul Butler <paul.butler@ni.com>
Co-authored-by: Paul David <paul.david@ettus.com>
Co-authored-by: Ryan Marlow <ryan.marlow@ettus.com>
Co-authored-by: Sugandha Gupta <sugandha.gupta@ettus.com>
Co-authored-by: Sylvain Munaut <tnt@246tNt.com>
Co-authored-by: Trung Tran <trung.tran@ettus.com>
Co-authored-by: Vidush Vishwanath <vidush.vishwanath@ettus.com>
Co-authored-by: Wade Fife <wade.fife@ettus.com>
Diffstat (limited to 'fpga/usrp3/lib/xge/rtl/verilog/rx_enqueue.v')
-rw-r--r-- | fpga/usrp3/lib/xge/rtl/verilog/rx_enqueue.v | 763 |
1 files changed, 763 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/xge/rtl/verilog/rx_enqueue.v b/fpga/usrp3/lib/xge/rtl/verilog/rx_enqueue.v new file mode 100644 index 000000000..98a5ac660 --- /dev/null +++ b/fpga/usrp3/lib/xge/rtl/verilog/rx_enqueue.v @@ -0,0 +1,763 @@ +////////////////////////////////////////////////////////////////////// +//// //// +//// File name "rx_enqueue.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 rx_enqueue(/*AUTOARG*/ + // Outputs + rxdfifo_wdata, rxdfifo_wstatus, rxdfifo_wen, rxhfifo_ren, + rxhfifo_wdata, rxhfifo_wstatus, rxhfifo_wen, local_fault_msg_det, + remote_fault_msg_det, status_crc_error_tog, + status_fragment_error_tog, status_rxdfifo_ovflow_tog, + status_pause_frame_rx_tog, + // Inputs + clk_xgmii_rx, reset_xgmii_rx_n, xgmii_rxd, xgmii_rxc, rxdfifo_wfull, + rxhfifo_rdata, rxhfifo_rstatus, rxhfifo_rempty, + rxhfifo_ralmost_empty + ); + +`include "CRC32_D64.v" +`include "CRC32_D8.v" +`include "utils.v" + +input clk_xgmii_rx; +input reset_xgmii_rx_n; + +input [63:0] xgmii_rxd; +input [7:0] xgmii_rxc; + +input rxdfifo_wfull; + +input [63:0] rxhfifo_rdata; +input [7:0] rxhfifo_rstatus; +input rxhfifo_rempty; +input rxhfifo_ralmost_empty; + +output [63:0] rxdfifo_wdata; +output [7:0] rxdfifo_wstatus; +output rxdfifo_wen; + +output rxhfifo_ren; + +output [63:0] rxhfifo_wdata; +output [7:0] rxhfifo_wstatus; +output rxhfifo_wen; + +output [1:0] local_fault_msg_det; +output [1:0] remote_fault_msg_det; + +output status_crc_error_tog; +output status_fragment_error_tog; +output status_rxdfifo_ovflow_tog; + +output status_pause_frame_rx_tog; + + + + +/*AUTOREG*/ +// Beginning of automatic regs (for this module's undeclared outputs) +reg [1:0] local_fault_msg_det; +reg [1:0] remote_fault_msg_det; +reg [63:0] rxdfifo_wdata; +reg rxdfifo_wen; +reg [7:0] rxdfifo_wstatus; +reg rxhfifo_ren; +reg [63:0] rxhfifo_wdata; +reg rxhfifo_wen; +reg [7:0] rxhfifo_wstatus; +reg status_crc_error_tog; +reg status_fragment_error_tog; +reg status_pause_frame_rx_tog; +reg status_rxdfifo_ovflow_tog; +// End of automatics + +/*AUTOWIRE*/ + + +reg [63:32] xgmii_rxd_d1; +reg [7:4] xgmii_rxc_d1; + +reg [63:0] xgxs_rxd_barrel; +reg [7:0] xgxs_rxc_barrel; + +reg [63:0] xgxs_rxd_barrel_d1; +reg [7:0] xgxs_rxc_barrel_d1; + +reg barrel_shift; + +reg [31:0] crc32_d64; +reg [31:0] crc32_d8; + +reg [3:0] crc_bytes; +reg [3:0] next_crc_bytes; + +reg [63:0] crc_shift_data; +reg crc_start_8b; +reg crc_done; +reg crc_good; +reg crc_clear; + +reg [31:0] crc_rx; +reg [31:0] next_crc_rx; + +reg [2:0] curr_state; +reg [2:0] next_state; + +reg [13:0] curr_byte_cnt; +reg [13:0] next_byte_cnt; + +reg fragment_error; +reg rxd_ovflow_error; + +reg coding_error; +reg next_coding_error; + +reg [7:0] addmask; +reg [7:0] datamask; + +reg pause_frame; +reg next_pause_frame; +reg pause_frame_hold; + +reg good_pause_frame; + +reg drop_data; +reg next_drop_data; + +reg pkt_pending; + +reg rxhfifo_ren_d1; + +reg rxhfifo_ralmost_empty_d1; + + +parameter [2:0] + SM_IDLE = 3'd0, + SM_RX = 3'd1; + +always @(posedge clk_xgmii_rx or negedge reset_xgmii_rx_n) begin + + if (reset_xgmii_rx_n == 1'b0) begin + + xgmii_rxd_d1 <= 32'b0; + xgmii_rxc_d1 <= 4'b0; + + xgxs_rxd_barrel <= 64'b0; + xgxs_rxc_barrel <= 8'b0; + + xgxs_rxd_barrel_d1 <= 64'b0; + xgxs_rxc_barrel_d1 <= 8'b0; + + barrel_shift <= 1'b0; + + local_fault_msg_det <= 2'b0; + remote_fault_msg_det <= 2'b0; + + crc32_d64 <= 32'b0; + crc32_d8 <= 32'b0; + crc_bytes <= 4'b0; + + crc_shift_data <= 64'b0; + crc_done <= 1'b0; + crc_rx <= 32'b0; + + pause_frame_hold <= 1'b0; + + status_crc_error_tog <= 1'b0; + status_fragment_error_tog <= 1'b0; + status_rxdfifo_ovflow_tog <= 1'b0; + + status_pause_frame_rx_tog <= 1'b0; + + end + else begin + + //--- + // Link status RC layer + // Look for local/remote messages on lower 4 lanes and upper + // 4 lanes. This is a 64-bit interface but look at each 32-bit + // independantly. + + local_fault_msg_det[1] <= (xgmii_rxd[63:32] == + {`LOCAL_FAULT, 8'h0, 8'h0, `SEQUENCE} && + xgmii_rxc[7:4] == 4'b0001); + + local_fault_msg_det[0] <= (xgmii_rxd[31:0] == + {`LOCAL_FAULT, 8'h0, 8'h0, `SEQUENCE} && + xgmii_rxc[3:0] == 4'b0001); + + remote_fault_msg_det[1] <= (xgmii_rxd[63:32] == + {`REMOTE_FAULT, 8'h0, 8'h0, `SEQUENCE} && + xgmii_rxc[7:4] == 4'b0001); + + remote_fault_msg_det[0] <= (xgmii_rxd[31:0] == + {`REMOTE_FAULT, 8'h0, 8'h0, `SEQUENCE} && + xgmii_rxc[3:0] == 4'b0001); + + + //--- + // Rotating barrel. This function allow us to always align the start of + // a frame with LANE0. If frame starts in LANE4, it will be shifted 4 bytes + // to LANE0, thus reducing the amount of logic needed at the next stage. + + xgmii_rxd_d1[63:32] <= xgmii_rxd[63:32]; + xgmii_rxc_d1[7:4] <= xgmii_rxc[7:4]; + + if (xgmii_rxd[`LANE0] == `START && xgmii_rxc[0]) begin + + xgxs_rxd_barrel <= xgmii_rxd; + xgxs_rxc_barrel <= xgmii_rxc; + + barrel_shift <= 1'b0; + + end + else if (xgmii_rxd[`LANE4] == `START && xgmii_rxc[4]) begin + + xgxs_rxd_barrel <= {xgmii_rxd[31:0], xgmii_rxd_d1[63:32]}; + xgxs_rxc_barrel <= {xgmii_rxc[3:0], xgmii_rxc_d1[7:4]}; + + barrel_shift <= 1'b1; + + end + else if (barrel_shift) begin + + xgxs_rxd_barrel <= {xgmii_rxd[31:0], xgmii_rxd_d1[63:32]}; + xgxs_rxc_barrel <= {xgmii_rxc[3:0], xgmii_rxc_d1[7:4]}; + + end + else begin + + xgxs_rxd_barrel <= xgmii_rxd; + xgxs_rxc_barrel <= xgmii_rxc; + + end + + xgxs_rxd_barrel_d1 <= xgxs_rxd_barrel; + xgxs_rxc_barrel_d1 <= xgxs_rxc_barrel; + + + //--- + // When final CRC calculation begins we capture info relevant to + // current frame CRC claculation continues while next frame is + // being received. + + if (crc_start_8b) begin + + pause_frame_hold <= pause_frame; + + end + + //--- + // CRC Checking + + crc_rx <= next_crc_rx; + + if (crc_clear) begin + + // CRC is cleared at the beginning of the frame, calculate + // 64-bit at a time otherwise + + crc32_d64 <= 32'hffffffff; + + end + else begin + + crc32_d64 <= nextCRC32_D64(reverse_64b(xgxs_rxd_barrel_d1), crc32_d64); + + end + + if (crc_bytes != 4'b0) begin + + // When reaching the end of the frame we switch from 64-bit mode + // to 8-bit mode to accomodate odd number of bytes in the frame. + // crc_bytes indicated the number of remaining payload byte to + // compute CRC on. Calculate and decrement until it reaches 0. + + if (crc_bytes == 4'b1) begin + crc_done <= 1'b1; + end + + crc32_d8 <= nextCRC32_D8(reverse_8b(crc_shift_data[7:0]), crc32_d8); + crc_shift_data <= {8'h00, crc_shift_data[63:8]}; + crc_bytes <= crc_bytes - 4'b1; + + end + else if (crc_bytes == 4'b0) begin + + // Per Clause 46. Control code during data must be reported + // as a CRC error. Indicated here by coding_error. Corrupt CRC + // if coding error is detected. + + if (coding_error || next_coding_error) begin + crc32_d8 <= ~crc32_d64; + end + else begin + crc32_d8 <= crc32_d64; + end + + crc_done <= 1'b0; + + crc_shift_data <= xgxs_rxd_barrel_d1; + crc_bytes <= next_crc_bytes; + + end + + //--- + // Error detection + + if (crc_done && !crc_good) begin + status_crc_error_tog <= ~status_crc_error_tog; + end + + if (fragment_error) begin + status_fragment_error_tog <= ~status_fragment_error_tog; + end + + if (rxd_ovflow_error) begin + status_rxdfifo_ovflow_tog <= ~status_rxdfifo_ovflow_tog; + end + + //--- + // Frame receive indication + + if (good_pause_frame) begin + status_pause_frame_rx_tog <= ~status_pause_frame_rx_tog; + end + + end + +end + + +always @(/*AS*/crc32_d8 or crc_done or crc_rx or pause_frame_hold) begin + + + crc_good = 1'b0; + good_pause_frame = 1'b0; + + if (crc_done) begin + + // Check CRC. If this is a pause frame, report it to cpu. + + if (crc_rx == ~reverse_32b(crc32_d8)) begin + crc_good = 1'b1; + good_pause_frame = pause_frame_hold; + end + + end + +end + +always @(posedge clk_xgmii_rx or negedge reset_xgmii_rx_n) begin + + if (reset_xgmii_rx_n == 1'b0) begin + + curr_state <= SM_IDLE; + curr_byte_cnt <= 14'b0; + coding_error <= 1'b0; + pause_frame <= 1'b0; + + end + else begin + + curr_state <= next_state; + curr_byte_cnt <= next_byte_cnt; + coding_error <= next_coding_error; + pause_frame <= next_pause_frame; + + end + +end + + +always @(/*AS*/coding_error or crc_rx or curr_byte_cnt or curr_state + or pause_frame or xgxs_rxc_barrel or xgxs_rxc_barrel_d1 + or xgxs_rxd_barrel or xgxs_rxd_barrel_d1) begin + + next_state = curr_state; + + rxhfifo_wdata = xgxs_rxd_barrel_d1; + rxhfifo_wstatus = `RXSTATUS_NONE; + rxhfifo_wen = 1'b0; + + addmask[0] = !(xgxs_rxd_barrel_d1[`LANE0] == `TERMINATE && xgxs_rxc_barrel_d1[0]); + addmask[1] = !(xgxs_rxd_barrel_d1[`LANE1] == `TERMINATE && xgxs_rxc_barrel_d1[1]); + addmask[2] = !(xgxs_rxd_barrel_d1[`LANE2] == `TERMINATE && xgxs_rxc_barrel_d1[2]); + addmask[3] = !(xgxs_rxd_barrel_d1[`LANE3] == `TERMINATE && xgxs_rxc_barrel_d1[3]); + addmask[4] = !(xgxs_rxd_barrel_d1[`LANE4] == `TERMINATE && xgxs_rxc_barrel_d1[4]); + addmask[5] = !(xgxs_rxd_barrel_d1[`LANE5] == `TERMINATE && xgxs_rxc_barrel_d1[5]); + addmask[6] = !(xgxs_rxd_barrel_d1[`LANE6] == `TERMINATE && xgxs_rxc_barrel_d1[6]); + addmask[7] = !(xgxs_rxd_barrel_d1[`LANE7] == `TERMINATE && xgxs_rxc_barrel_d1[7]); + + datamask[0] = addmask[0]; + datamask[1] = &addmask[1:0]; + datamask[2] = &addmask[2:0]; + datamask[3] = &addmask[3:0]; + datamask[4] = &addmask[4:0]; + datamask[5] = &addmask[5:0]; + datamask[6] = &addmask[6:0]; + datamask[7] = &addmask[7:0]; + + next_crc_bytes = 4'b0; + next_crc_rx = crc_rx; + crc_start_8b = 1'b0; + crc_clear = 1'b0; + + next_byte_cnt = curr_byte_cnt; + + fragment_error = 1'b0; + + next_coding_error = coding_error; + next_pause_frame = pause_frame; + + case (curr_state) + + SM_IDLE: + begin + + next_byte_cnt = 14'b0; + crc_clear = 1'b1; + next_coding_error = 1'b0; + next_pause_frame = 1'b0; + + + // Detect the start of a frame + + if (xgxs_rxd_barrel_d1[`LANE0] == `START && xgxs_rxc_barrel_d1[0] && + xgxs_rxd_barrel_d1[`LANE1] == `PREAMBLE && !xgxs_rxc_barrel_d1[1] && + xgxs_rxd_barrel_d1[`LANE2] == `PREAMBLE && !xgxs_rxc_barrel_d1[2] && + xgxs_rxd_barrel_d1[`LANE3] == `PREAMBLE && !xgxs_rxc_barrel_d1[3] && + xgxs_rxd_barrel_d1[`LANE4] == `PREAMBLE && !xgxs_rxc_barrel_d1[4] && + xgxs_rxd_barrel_d1[`LANE5] == `PREAMBLE && !xgxs_rxc_barrel_d1[5] && + xgxs_rxd_barrel_d1[`LANE6] == `PREAMBLE && !xgxs_rxc_barrel_d1[6] && + xgxs_rxd_barrel_d1[`LANE7] == `SFD && !xgxs_rxc_barrel_d1[7]) begin + + next_state = SM_RX; + end + + end + + SM_RX: + begin + + // Pause frames are filtered + + rxhfifo_wen = !pause_frame; + + + if (xgxs_rxd_barrel_d1[`LANE0] == `START && xgxs_rxc_barrel_d1[0] && + xgxs_rxd_barrel_d1[`LANE7] == `SFD && !xgxs_rxc_barrel_d1[7]) begin + + // Fragment received, if we are still at SOP stage don't store + // the frame. If not, write a fake EOP and flag frame as bad. + + next_byte_cnt = 14'b0; + crc_clear = 1'b1; + next_coding_error = 1'b0; + + fragment_error = 1'b1; + rxhfifo_wstatus[`RXSTATUS_ERR] = 1'b1; + + if (curr_byte_cnt == 14'b0) begin + rxhfifo_wen = 1'b0; + end + else begin + rxhfifo_wstatus[`RXSTATUS_EOP] = 1'b1; + end + + end + else if (curr_byte_cnt > 14'd9900) begin + + // Frame too long, TERMMINATE must have been corrupted. + // Abort transfer, write a fake EOP, report as fragment. + + fragment_error = 1'b1; + rxhfifo_wstatus[`RXSTATUS_ERR] = 1'b1; + + rxhfifo_wstatus[`RXSTATUS_EOP] = 1'b1; + next_state = SM_IDLE; + + end + else begin + + // Pause frame receive, these frame will be filtered + + if (curr_byte_cnt == 14'd0 && + xgxs_rxd_barrel_d1[47:0] == `PAUSE_FRAME) begin + + rxhfifo_wen = 1'b0; + next_pause_frame = 1'b1; + end + + + // Control character during data phase, force CRC error + + if (|(xgxs_rxc_barrel_d1 & datamask)) begin + + next_coding_error = 1'b1; + end + + + // Write SOP to status bits during first byte + + if (curr_byte_cnt == 14'b0) begin + rxhfifo_wstatus[`RXSTATUS_SOP] = 1'b1; + end + + /* verilator lint_off WIDTH */ + next_byte_cnt = curr_byte_cnt + + addmask[0] + addmask[1] + addmask[2] + addmask[3] + + addmask[4] + addmask[5] + addmask[6] + addmask[7]; + /* verilator lint_on WIDTH */ + + + + // We will not write to the fifo if all is left + // are four or less bytes of crc. We also strip off the + // crc, which requires looking one cycle ahead + // wstatus: + // [2:0] modulus of packet length + + // Look one cycle ahead for TERMINATE in lanes 0 to 4 + + if (xgxs_rxd_barrel[`LANE4] == `TERMINATE && xgxs_rxc_barrel[4]) begin + + rxhfifo_wstatus[`RXSTATUS_EOP] = 1'b1; + rxhfifo_wstatus[2:0] = 3'd0; + + crc_start_8b = 1'b1; + next_crc_bytes = 4'd8; + next_crc_rx = xgxs_rxd_barrel[31:0]; + + next_state = SM_IDLE; + + end + + if (xgxs_rxd_barrel[`LANE3] == `TERMINATE && xgxs_rxc_barrel[3]) begin + + rxhfifo_wstatus[`RXSTATUS_EOP] = 1'b1; + rxhfifo_wstatus[2:0] = 3'd7; + + crc_start_8b = 1'b1; + next_crc_bytes = 4'd7; + next_crc_rx = {xgxs_rxd_barrel[23:0], xgxs_rxd_barrel_d1[63:56]}; + + next_state = SM_IDLE; + + end + + if (xgxs_rxd_barrel[`LANE2] == `TERMINATE && xgxs_rxc_barrel[2]) begin + + rxhfifo_wstatus[`RXSTATUS_EOP] = 1'b1; + rxhfifo_wstatus[2:0] = 3'd6; + + crc_start_8b = 1'b1; + next_crc_bytes = 4'd6; + next_crc_rx = {xgxs_rxd_barrel[15:0], xgxs_rxd_barrel_d1[63:48]}; + + next_state = SM_IDLE; + + end + + if (xgxs_rxd_barrel[`LANE1] == `TERMINATE && xgxs_rxc_barrel[1]) begin + + rxhfifo_wstatus[`RXSTATUS_EOP] = 1'b1; + rxhfifo_wstatus[2:0] = 3'd5; + + crc_start_8b = 1'b1; + next_crc_bytes = 4'd5; + next_crc_rx = {xgxs_rxd_barrel[7:0], xgxs_rxd_barrel_d1[63:40]}; + + next_state = SM_IDLE; + + end + + if (xgxs_rxd_barrel[`LANE0] == `TERMINATE && xgxs_rxc_barrel[0]) begin + + rxhfifo_wstatus[`RXSTATUS_EOP] = 1'b1; + rxhfifo_wstatus[2:0] = 3'd4; + + crc_start_8b = 1'b1; + next_crc_bytes = 4'd4; + next_crc_rx = xgxs_rxd_barrel_d1[63:32]; + + next_state = SM_IDLE; + + end + + // Look at current cycle for TERMINATE in lanes 5 to 7 + + if (xgxs_rxd_barrel_d1[`LANE7] == `TERMINATE && + xgxs_rxc_barrel_d1[7]) begin + + rxhfifo_wstatus[`RXSTATUS_EOP] = 1'b1; + rxhfifo_wstatus[2:0] = 3'd3; + + crc_start_8b = 1'b1; + next_crc_bytes = 4'd3; + next_crc_rx = xgxs_rxd_barrel_d1[55:24]; + + next_state = SM_IDLE; + + end + + if (xgxs_rxd_barrel_d1[`LANE6] == `TERMINATE && + xgxs_rxc_barrel_d1[6]) begin + + rxhfifo_wstatus[`RXSTATUS_EOP] = 1'b1; + rxhfifo_wstatus[2:0] = 3'd2; + + crc_start_8b = 1'b1; + next_crc_bytes = 4'd2; + next_crc_rx = xgxs_rxd_barrel_d1[47:16]; + + next_state = SM_IDLE; + + end + + if (xgxs_rxd_barrel_d1[`LANE5] == `TERMINATE && + xgxs_rxc_barrel_d1[5]) begin + + rxhfifo_wstatus[`RXSTATUS_EOP] = 1'b1; + rxhfifo_wstatus[2:0] = 3'd1; + + crc_start_8b = 1'b1; + next_crc_bytes = 4'd1; + next_crc_rx = xgxs_rxd_barrel_d1[39:8]; + + next_state = SM_IDLE; + + end + end + end + + default: + begin + next_state = SM_IDLE; + end + + endcase + +end + + +always @(posedge clk_xgmii_rx or negedge reset_xgmii_rx_n) begin + + if (reset_xgmii_rx_n == 1'b0) begin + + rxhfifo_ralmost_empty_d1 <= 1'b1; + + drop_data <= 1'b0; + + pkt_pending <= 1'b0; + + rxhfifo_ren_d1 <= 1'b0; + + end + else begin + + rxhfifo_ralmost_empty_d1 <= rxhfifo_ralmost_empty; + + drop_data <= next_drop_data; + + pkt_pending <= rxhfifo_ren; + + rxhfifo_ren_d1 <= rxhfifo_ren; + + end + +end + +always @(/*AS*/crc_done or crc_good or drop_data or pkt_pending + or rxdfifo_wfull or rxhfifo_ralmost_empty_d1 or rxhfifo_rdata + or rxhfifo_ren_d1 or rxhfifo_rstatus) begin + + rxd_ovflow_error = 1'b0; + + rxdfifo_wdata = rxhfifo_rdata; + rxdfifo_wstatus = rxhfifo_rstatus; + + next_drop_data = drop_data; + + + // There must be at least 8 words in holding FIFO before we start reading. + // This provides enough time for CRC calculation. + + rxhfifo_ren = !rxhfifo_ralmost_empty_d1 || + (pkt_pending && !rxhfifo_rstatus[`RXSTATUS_EOP]); + + + if (rxhfifo_ren_d1 && rxhfifo_rstatus[`RXSTATUS_SOP]) begin + + // Reset drop flag on SOP + + next_drop_data = 1'b0; + + end + + if (rxhfifo_ren_d1 && rxdfifo_wfull && !next_drop_data) begin + + // FIFO overflow, abort transfer. The rest of the frame + // will be dropped. Since we can't put an EOP indication + // in a fifo already full, there will be no EOP and receive + // side will need to sync on next SOP. + + rxd_ovflow_error = 1'b1; + next_drop_data = 1'b1; + + end + + + rxdfifo_wen = rxhfifo_ren_d1 && !next_drop_data; + + + + if (crc_done && !crc_good) begin + + // Flag packet with error when CRC error is detected + + rxdfifo_wstatus[`RXSTATUS_ERR] = 1'b1; + + end + +end + +endmodule + +
\ No newline at end of file |