mirror of
https://github.com/KastnerRG/riffa.git
synced 2025-01-30 23:02:54 +08:00
543 lines
18 KiB
Verilog
543 lines
18 KiB
Verilog
// ----------------------------------------------------------------------
|
|
// Copyright (c) 2015, The Regents of the University of California All
|
|
// rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
//
|
|
// * Redistributions in binary form must reproduce the above
|
|
// copyright notice, this list of conditions and the following
|
|
// disclaimer in the documentation and/or other materials provided
|
|
// with the distribution.
|
|
//
|
|
// * Neither the name of The Regents of the University of California
|
|
// nor the names of its contributors may be used to endorse or
|
|
// promote products derived from this software without specific
|
|
// prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL REGENTS OF THE
|
|
// UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
|
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
|
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
// DAMAGE.
|
|
// ----------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------
|
|
// Filename: rx_port_reader.v
|
|
// Version: 1.00.a
|
|
// Verilog Standard: Verilog-2001
|
|
// Description: Handles the RX lifecycle and issuing requests for receiving
|
|
// data input.
|
|
// for the RIFFA channel.
|
|
// Author: Matt Jacobsen
|
|
// History: @mattj: Version 2.0
|
|
//-----------------------------------------------------------------------------
|
|
`define S_RXPORTRD_MAIN_IDLE 6'b00_0001
|
|
`define S_RXPORTRD_MAIN_CHECK 6'b00_0010
|
|
`define S_RXPORTRD_MAIN_READ 6'b00_0100
|
|
`define S_RXPORTRD_MAIN_FLUSH 6'b00_1000
|
|
`define S_RXPORTRD_MAIN_DONE 6'b01_0000
|
|
`define S_RXPORTRD_MAIN_RESET 6'b10_0000
|
|
|
|
`define S_RXPORTRD_RX_IDLE 8'b0000_0001
|
|
`define S_RXPORTRD_RX_BUF 8'b0000_0010
|
|
`define S_RXPORTRD_RX_ADJ_0 8'b0000_0100
|
|
`define S_RXPORTRD_RX_ADJ_1 8'b0000_1000
|
|
`define S_RXPORTRD_RX_ISSUE 8'b0001_0000
|
|
`define S_RXPORTRD_RX_WAIT_0 8'b0010_0000
|
|
`define S_RXPORTRD_RX_WAIT_1 8'b0100_0000
|
|
`define S_RXPORTRD_RX_DONE 8'b1000_0000
|
|
|
|
`timescale 1ns/1ns
|
|
module rx_port_reader #(
|
|
parameter C_DATA_WIDTH = 9'd64,
|
|
parameter C_FIFO_DEPTH = 1024,
|
|
parameter C_MAX_READ_REQ = 2, // Max read: 000=128B, 001=256B, 010=512B, 011=1024B, 100=2048B, 101=4096B
|
|
// Local parameters
|
|
parameter C_DATA_WORD_WIDTH = clog2((C_DATA_WIDTH/32)+1),
|
|
parameter C_FIFO_WORDS = (C_DATA_WIDTH/32)*C_FIFO_DEPTH
|
|
)
|
|
(
|
|
input CLK,
|
|
input RST,
|
|
input [2:0] CONFIG_MAX_READ_REQUEST_SIZE, // Maximum read payload: 000=128B, 001=256B, 010=512B, 011=1024B, 100=2048B, 101=4096B
|
|
|
|
input [31:0] TXN_DATA, // Read transaction data
|
|
input TXN_LEN_VALID, // Read transaction length valid
|
|
input TXN_OFF_LAST_VALID, // Read transaction offset/last valid
|
|
output [31:0] TXN_DONE_LEN, // Read transaction actual transfer length
|
|
output TXN_DONE, // Read transaction done
|
|
output TXN_ERR, // Read transaction completed with error
|
|
input TXN_DONE_ACK, // Read transaction actual transfer length read
|
|
|
|
output TXN_DATA_FLUSH, // Request that all data in the packer be flushed
|
|
input TXN_DATA_FLUSHED, // All data in the packer has been flushed
|
|
|
|
output RX_REQ, // Issue a read request
|
|
output [63:0] RX_ADDR, // Request address
|
|
output [9:0] RX_LEN, // Request length
|
|
input RX_REQ_ACK, // Request has been accepted
|
|
|
|
input [C_DATA_WORD_WIDTH-1:0] RX_DATA_EN, // Incoming read data enable
|
|
input RX_DONE, // Incoming read completed
|
|
input RX_ERR, // Incoming read completed with error
|
|
input SG_DONE, // Incoming scatter gather read completed
|
|
input SG_ERR, // Incoming scatter gather read completed with error
|
|
|
|
input [63:0] SG_ELEM_ADDR, // Scatter gather element address
|
|
input [31:0] SG_ELEM_LEN, // Scatter gather element length (in words)
|
|
input SG_ELEM_RDY, // Scatter gather element ready
|
|
output SG_ELEM_REN, // Scatter gather element read enable
|
|
output SG_RST, // Scatter gather reset
|
|
|
|
output CHNL_RX, // Signal channel RX
|
|
output [31:0] CHNL_RX_LEN, // Channel RX length
|
|
output CHNL_RX_LAST, // Channel RX last
|
|
output [30:0] CHNL_RX_OFF, // Channel RX offset
|
|
input CHNL_RX_RECVD, // Channel RX received
|
|
input CHNL_RX_ACK_RECVD, // Channel RX acknowledgment received
|
|
input [31:0] CHNL_RX_CONSUMED // Channel words consumed in current RX
|
|
);
|
|
|
|
`include "functions.vh"
|
|
|
|
|
|
reg [31:0] rTxnData=0, _rTxnData=0;
|
|
reg rTxnOffLastValid=0, _rTxnOffLastValid=0;
|
|
reg rTxnLenValid=0, _rTxnLenValid=0;
|
|
reg [C_DATA_WORD_WIDTH-1:0] rRxDataEn=0, _rRxDataEn=0;
|
|
|
|
(* syn_encoding = "user" *)
|
|
(* fsm_encoding = "user" *)
|
|
reg [5:0] rMainState=`S_RXPORTRD_MAIN_IDLE, _rMainState=`S_RXPORTRD_MAIN_IDLE;
|
|
reg [31:0] rOffLast=0, _rOffLast=0;
|
|
reg [31:0] rReadWords=0, _rReadWords=0;
|
|
reg rReadWordsZero=0, _rReadWordsZero=0;
|
|
reg [0:0] rStart=0, _rStart=0;
|
|
reg [3:0] rFlushed=0, _rFlushed=0;
|
|
reg [31:0] rDoneLen=0, _rDoneLen=0;
|
|
reg rTxnDone=0, _rTxnDone=0;
|
|
|
|
(* syn_encoding = "user" *)
|
|
(* fsm_encoding = "user" *)
|
|
reg [7:0] rRxState=`S_RXPORTRD_RX_IDLE, _rRxState=`S_RXPORTRD_RX_IDLE;
|
|
reg rSgRen=0, _rSgRen=0;
|
|
reg [31:0] rWords=0, _rWords=0;
|
|
reg [31:0] rBufWords=0, _rBufWords=0;
|
|
reg [31:0] rBufWordsInit=0, _rBufWordsInit=0;
|
|
reg rLargeBuf=0, _rLargeBuf=0;
|
|
reg [63:0] rAddr=64'd0, _rAddr=64'd0;
|
|
reg [3:0] rValsProp=0, _rValsProp=0;
|
|
reg [2:0] rCarry=0, _rCarry=0;
|
|
reg rCopyBufWords=0, _rCopyBufWords=0;
|
|
reg rUseInit=0, _rUseInit=0;
|
|
reg [10:0] rPageRem=0, _rPageRem=0;
|
|
reg rPageSpill=0, _rPageSpill=0;
|
|
reg rPageSpillInit=0, _rPageSpillInit=0;
|
|
reg [10:0] rPreLen=0, _rPreLen=0;
|
|
reg [2:0] rMaxPayloadTrain=0, _rMaxPayloadTrain=0;
|
|
reg [2:0] rMaxPayloadShift=0, _rMaxPayloadShift=0;
|
|
reg [9:0] rMaxPayload=0, _rMaxPayload=0;
|
|
reg rPayloadSpill=0, _rPayloadSpill=0;
|
|
reg rMaxLen=0, _rMaxLen=0;
|
|
reg [9:0] rLen=0, _rLen=0;
|
|
reg rLenEQWordsHi=0, _rLenEQWordsHi=0;
|
|
reg rLenEQWordsLo=0, _rLenEQWordsLo=0;
|
|
reg rLenEQBufWordsHi=0, _rLenEQBufWordsHi=0;
|
|
reg rLenEQBufWordsLo=0, _rLenEQBufWordsLo=0;
|
|
|
|
reg [31:0] rRecvdWords=0, _rRecvdWords=0;
|
|
reg [31:0] rReqdWords=0, _rReqdWords=0;
|
|
reg [31:0] rRequestingWords=0, _rRequestingWords=0;
|
|
reg [31:0] rAvailWords=0, _rAvailWords=0;
|
|
reg [31:0] rPartWords=0, _rPartWords=0;
|
|
reg [10:0] rAckCount=0, _rAckCount=0;
|
|
reg rAckCountEQ0=0, _rAckCountEQ0=0;
|
|
reg rLastDoneRead=1, _rLastDoneRead=1;
|
|
reg rTxnDoneAck=0, _rTxnDoneAck=0;
|
|
reg rPartWordsRecvd=0, _rPartWordsRecvd=0;
|
|
reg rCarryInv=0, _rCarryInv=0;
|
|
reg rSpaceAvail=0, _rSpaceAvail=0;
|
|
|
|
reg rPartialDone=0, _rPartialDone=0;
|
|
reg rReqPartialDone=0, _rReqPartialDone=0;
|
|
|
|
reg rErr=0, _rErr=0;
|
|
|
|
|
|
assign TXN_DONE_LEN = rDoneLen;
|
|
assign TXN_DONE = (rTxnDone | rPartialDone);
|
|
assign TXN_ERR = rErr;
|
|
|
|
assign TXN_DATA_FLUSH = rMainState[3]; // S_RXPORTRD_MAIN_FLUSH
|
|
|
|
assign RX_REQ = (rRxState[4] & rSpaceAvail); // S_RXPORTRD_RX_ISSUE
|
|
assign RX_ADDR = rAddr;
|
|
assign RX_LEN = rLen;
|
|
|
|
assign SG_ELEM_REN = rSgRen;
|
|
assign SG_RST = rMainState[1]; // S_RXPORTRD_MAIN_CHECK
|
|
|
|
assign CHNL_RX = (rMainState[2] | rMainState[3] | rMainState[4]); // S_RXPORTRD_MAIN_READ | S_RXPORTRD_MAIN_FLUSH | S_RXPORTRD_MAIN_DONE
|
|
assign CHNL_RX_LEN = rReadWords;
|
|
assign CHNL_RX_LAST = rOffLast[0];
|
|
assign CHNL_RX_OFF = rOffLast[31:1];
|
|
|
|
|
|
// Buffer signals that come from outside the rx_port.
|
|
always @ (posedge CLK) begin
|
|
rTxnData <= #1 _rTxnData;
|
|
rTxnOffLastValid <= #1 _rTxnOffLastValid;
|
|
rTxnLenValid <= #1 _rTxnLenValid;
|
|
rTxnDoneAck <= #1 (RST ? 1'd0 : _rTxnDoneAck);
|
|
rRxDataEn <= #1 _rRxDataEn;
|
|
end
|
|
|
|
always @ (*) begin
|
|
_rTxnData = TXN_DATA;
|
|
_rTxnOffLastValid = TXN_OFF_LAST_VALID;
|
|
_rTxnLenValid = TXN_LEN_VALID;
|
|
_rTxnDoneAck = TXN_DONE_ACK;
|
|
_rRxDataEn = RX_DATA_EN;
|
|
end
|
|
|
|
|
|
// Handle RX lifecycle.
|
|
always @ (posedge CLK) begin
|
|
rMainState <= #1 (RST ? `S_RXPORTRD_MAIN_IDLE : _rMainState);
|
|
rOffLast <= #1 _rOffLast;
|
|
rReadWords <= #1 _rReadWords;
|
|
rReadWordsZero <= #1 _rReadWordsZero;
|
|
rStart <= #1 _rStart;
|
|
rFlushed <= #1 _rFlushed;
|
|
rDoneLen <= #1 (RST ? 0 : _rDoneLen);
|
|
rTxnDone <= #1 _rTxnDone;
|
|
end
|
|
|
|
always @ (*) begin
|
|
_rMainState = rMainState;
|
|
_rDoneLen = rDoneLen;
|
|
_rTxnDone = rTxnDone;
|
|
|
|
_rOffLast = (rTxnOffLastValid ? rTxnData : rOffLast);
|
|
_rReadWords = (rMainState[0] & rTxnLenValid ? rTxnData : rReadWords);
|
|
_rReadWordsZero = (rReadWords == 0);
|
|
_rStart = ((rStart<<1) | rTxnLenValid);
|
|
_rFlushed = ((rFlushed<<1) | TXN_DATA_FLUSHED);
|
|
|
|
case (rMainState)
|
|
|
|
`S_RXPORTRD_MAIN_IDLE: begin // Wait for new read transaction offset/last & length
|
|
_rTxnDone = 0;
|
|
if (rStart[0])
|
|
_rMainState = `S_RXPORTRD_MAIN_CHECK;
|
|
end
|
|
|
|
`S_RXPORTRD_MAIN_CHECK: begin // See if we should start a transaction
|
|
if (!rReadWordsZero)
|
|
_rMainState = `S_RXPORTRD_MAIN_READ;
|
|
else if (rOffLast[0])
|
|
_rMainState = `S_RXPORTRD_MAIN_FLUSH;
|
|
else
|
|
_rMainState = `S_RXPORTRD_MAIN_IDLE;
|
|
end
|
|
|
|
`S_RXPORTRD_MAIN_READ: begin // Issue read transfers, wait for data to arrive
|
|
if (rRxState[7] & rLastDoneRead) begin // S_RXPORTRD_RX_DONE
|
|
_rDoneLen = rRecvdWords;
|
|
_rMainState = `S_RXPORTRD_MAIN_FLUSH;
|
|
end
|
|
end
|
|
|
|
`S_RXPORTRD_MAIN_FLUSH: begin // Wait for data to be flushed
|
|
if (rFlushed[3])
|
|
_rMainState = `S_RXPORTRD_MAIN_DONE;
|
|
end
|
|
|
|
`S_RXPORTRD_MAIN_DONE: begin // Wait for RX to be received and ackd in the channel
|
|
if (CHNL_RX_RECVD & CHNL_RX_ACK_RECVD)
|
|
_rMainState = `S_RXPORTRD_MAIN_RESET;
|
|
end
|
|
|
|
`S_RXPORTRD_MAIN_RESET: begin // Wait until RX has dropped in the channel
|
|
if (!CHNL_RX_RECVD) begin
|
|
_rTxnDone = 1;
|
|
_rMainState = `S_RXPORTRD_MAIN_IDLE;
|
|
end
|
|
end
|
|
|
|
default: begin
|
|
_rMainState = `S_RXPORTRD_MAIN_IDLE;
|
|
end
|
|
|
|
endcase
|
|
end
|
|
|
|
|
|
// Issue the read requests at the buffer level. Decrement the amount requested
|
|
// after every request. Continue until all words have been requested.
|
|
wire [9:0] wAddrLoInv = ~rAddr[11:2];
|
|
always @ (posedge CLK) begin
|
|
rRxState <= #1 (RST ? `S_RXPORTRD_RX_IDLE : _rRxState);
|
|
rSgRen <= #1 (RST ? 1'd0: _rSgRen);
|
|
rWords <= #1 _rWords;
|
|
rBufWords <= #1 _rBufWords;
|
|
rBufWordsInit <= #1 _rBufWordsInit;
|
|
rLargeBuf <= #1 _rLargeBuf;
|
|
rAddr <= #1 _rAddr;
|
|
rCarry <= #1 _rCarry;
|
|
rValsProp <= #1 _rValsProp;
|
|
rPageRem <= #1 _rPageRem;
|
|
rPageSpill <= #1 _rPageSpill;
|
|
rPageSpillInit <= #1 _rPageSpillInit;
|
|
rCopyBufWords <= #1 _rCopyBufWords;
|
|
rUseInit <= #1 _rUseInit;
|
|
rPreLen <= #1 _rPreLen;
|
|
rMaxPayloadTrain <= #1 _rMaxPayloadTrain;
|
|
rMaxPayloadShift <= #1 _rMaxPayloadShift;
|
|
rMaxPayload <= #1 _rMaxPayload;
|
|
rPayloadSpill <= #1 _rPayloadSpill;
|
|
rMaxLen <= #1 _rMaxLen;
|
|
rLen <= #1 _rLen;
|
|
rLenEQWordsHi <= #1 _rLenEQWordsHi;
|
|
rLenEQWordsLo <= #1 _rLenEQWordsLo;
|
|
rLenEQBufWordsHi <= #1 _rLenEQBufWordsHi;
|
|
rLenEQBufWordsLo <= #1 _rLenEQBufWordsLo;
|
|
end
|
|
|
|
always @ (*) begin
|
|
_rRxState = rRxState;
|
|
_rCopyBufWords = rCopyBufWords;
|
|
_rUseInit = rUseInit;
|
|
_rSgRen = rSgRen;
|
|
|
|
_rValsProp = ((rValsProp<<1) | rRxState[2]); // S_RXPORTRD_RX_ADJ_0
|
|
_rLargeBuf = (SG_ELEM_LEN > rWords);
|
|
{_rCarry[0], _rAddr[15:0]} = (rRxState[1] ? SG_ELEM_ADDR[15:0] : (rAddr[15:0] + ({12{RX_REQ_ACK}} & {rLen,2'd0})));
|
|
{_rCarry[1], _rAddr[31:16]} = (rRxState[1] ? SG_ELEM_ADDR[31:16] : (rAddr[31:16] + rCarry[0]));
|
|
{_rCarry[2], _rAddr[47:32]} = (rRxState[1] ? SG_ELEM_ADDR[47:32] : (rAddr[47:32] + rCarry[1]));
|
|
_rAddr[63:48] = (rRxState[1] ? SG_ELEM_ADDR[63:48] : (rAddr[63:48] + rCarry[2]));
|
|
_rWords = (rRxState[0] ? rReadWords : (rWords - ({10{RX_REQ_ACK}} & rLen)));
|
|
_rBufWordsInit = (rLargeBuf ? rWords : SG_ELEM_LEN);
|
|
_rBufWords = (rCopyBufWords ? rBufWordsInit : rBufWords) - ({10{RX_REQ_ACK}} & rLen);
|
|
_rPageRem = (wAddrLoInv + 1'd1);
|
|
_rPageSpillInit = (rBufWordsInit > rPageRem);
|
|
_rPageSpill = (rBufWords > rPageRem);
|
|
_rPreLen = ((rPageSpillInit & rUseInit) | (rPageSpill & !rUseInit) ? rPageRem : rBufWords[10:0]);
|
|
_rMaxPayloadTrain = (CONFIG_MAX_READ_REQUEST_SIZE > 3'd4 ? 3'd4 : CONFIG_MAX_READ_REQUEST_SIZE);
|
|
_rMaxPayloadShift = (C_MAX_READ_REQ[2:0] < rMaxPayloadTrain ? C_MAX_READ_REQ[2:0] : rMaxPayloadTrain);
|
|
_rMaxPayload = (6'd32<<rMaxPayloadShift);
|
|
_rPayloadSpill = (rPreLen > rMaxPayload);
|
|
_rMaxLen = ((rMaxLen & !rValsProp[2]) | RX_REQ_ACK);
|
|
_rLen = (rPayloadSpill | rMaxLen ? rMaxPayload : rPreLen[9:0]);
|
|
_rLenEQWordsHi = (16'd0 == rWords[31:16]);
|
|
_rLenEQWordsLo = ({6'd0, rLen} == rWords[15:0]);
|
|
_rLenEQBufWordsHi = (16'd0 == rBufWords[31:16]);
|
|
_rLenEQBufWordsLo = ({6'd0, rLen} == rBufWords[15:0]);
|
|
|
|
case (rRxState)
|
|
|
|
`S_RXPORTRD_RX_IDLE: begin // Wait for a new read transaction
|
|
if (rMainState[2]) // S_RXPORTRD_MAIN_READ
|
|
_rRxState = `S_RXPORTRD_RX_BUF;
|
|
end
|
|
|
|
`S_RXPORTRD_RX_BUF: begin // Wait for buffer length and address
|
|
if (SG_ELEM_RDY) begin
|
|
_rSgRen = 1;
|
|
_rRxState = `S_RXPORTRD_RX_ADJ_0;
|
|
end
|
|
else if (rErr) begin
|
|
_rRxState = `S_RXPORTRD_RX_WAIT_0;
|
|
end
|
|
end
|
|
|
|
`S_RXPORTRD_RX_ADJ_0: begin // Fix for large buffer
|
|
_rSgRen = 0;
|
|
_rCopyBufWords = rSgRen;
|
|
_rRxState = `S_RXPORTRD_RX_ADJ_1;
|
|
end
|
|
|
|
// (bufwords and pagerem valid here)
|
|
`S_RXPORTRD_RX_ADJ_1: begin // Wait for the value to propagate
|
|
// Check for page boundary crossing
|
|
// Fix for page boundary crossing
|
|
// Check for max read payload
|
|
// Fix for max read payload
|
|
_rCopyBufWords = 0;
|
|
_rUseInit = rCopyBufWords;
|
|
if (rValsProp[3])
|
|
_rRxState = `S_RXPORTRD_RX_ISSUE;
|
|
end
|
|
|
|
`S_RXPORTRD_RX_ISSUE: begin // Wait for the request to be accepted
|
|
if (RX_REQ_ACK) begin
|
|
if (rErr | (rLenEQWordsHi & rLenEQWordsLo))
|
|
_rRxState = `S_RXPORTRD_RX_WAIT_0;
|
|
else if (rLenEQBufWordsHi & rLenEQBufWordsLo)
|
|
_rRxState = `S_RXPORTRD_RX_BUF;
|
|
else
|
|
_rRxState = `S_RXPORTRD_RX_ADJ_0;
|
|
end
|
|
end
|
|
|
|
`S_RXPORTRD_RX_WAIT_0: begin // Wait for rAckCount to update
|
|
_rRxState = `S_RXPORTRD_RX_WAIT_1;
|
|
end
|
|
|
|
`S_RXPORTRD_RX_WAIT_1: begin // Wait for requested data to arrive
|
|
if (rAckCountEQ0)
|
|
_rRxState = `S_RXPORTRD_RX_DONE;
|
|
end
|
|
|
|
`S_RXPORTRD_RX_DONE: begin // Signal done
|
|
if (rMainState[3]) // S_RXPORTRD_MAIN_FLUSH
|
|
_rRxState = `S_RXPORTRD_RX_IDLE;
|
|
end
|
|
|
|
default: begin
|
|
_rRxState = `S_RXPORTRD_RX_IDLE;
|
|
end
|
|
|
|
endcase
|
|
end
|
|
|
|
|
|
// Count the data.
|
|
always @ (posedge CLK) begin
|
|
rRecvdWords <= #1 _rRecvdWords;
|
|
rReqdWords <= #1 _rReqdWords;
|
|
rPartWords <= #1 _rPartWords;
|
|
rAckCount <= #1 _rAckCount;
|
|
rAckCountEQ0 <= #1 _rAckCountEQ0;
|
|
rPartWordsRecvd <= #1 _rPartWordsRecvd;
|
|
rRequestingWords <= #1 _rRequestingWords;
|
|
rAvailWords <= #1 _rAvailWords;
|
|
rCarryInv <= #1 _rCarryInv;
|
|
rSpaceAvail <= #1 _rSpaceAvail;
|
|
rLastDoneRead <= #1 (RST ? 1'd1 : _rLastDoneRead);
|
|
end
|
|
|
|
always @ (*) begin
|
|
// Count words as they arrive (words from the rx_engine directly).
|
|
if (rMainState[0]) // S_RXPORTRD_MAIN_IDLE
|
|
_rRecvdWords = #1 0;
|
|
else
|
|
_rRecvdWords = #1 rRecvdWords + rRxDataEn;
|
|
|
|
// Count words as they are requested.
|
|
if (rMainState[0]) // S_RXPORTRD_MAIN_IDLE
|
|
_rReqdWords = #1 0;
|
|
else
|
|
_rReqdWords = #1 rReqdWords + ({10{RX_REQ_ACK}} & rLen);
|
|
|
|
// Track outstanding requests
|
|
if (rMainState[0]) // S_RXPORTRD_MAIN_IDLE
|
|
_rAckCount = 0;
|
|
else
|
|
_rAckCount = rAckCount + RX_REQ_ACK - RX_DONE;
|
|
_rAckCountEQ0 = (rAckCount == 11'd0);
|
|
|
|
// Track when the user reads the actual transfer amount.
|
|
_rLastDoneRead = (rTxnDone ? 1'd0 : (rLastDoneRead | rTxnDoneAck));
|
|
|
|
// Track the amount of words that are expected to arrive.
|
|
_rPartWords = #1 (rTxnLenValid ? rTxnData : rPartWords);
|
|
|
|
// Compare counts.
|
|
_rPartWordsRecvd = (rRecvdWords >= rPartWords);
|
|
_rRequestingWords = rReqdWords + rLen;
|
|
{_rCarryInv, _rAvailWords[15:0]} = {1'd1, rRequestingWords[15:0]} - CHNL_RX_CONSUMED[15:0];
|
|
_rAvailWords[31:16] = rRequestingWords[31:16] - CHNL_RX_CONSUMED[31:16] - !rCarryInv;
|
|
_rSpaceAvail = (rAvailWords <= C_FIFO_WORDS);
|
|
end
|
|
|
|
|
|
// Facilitate sending a TXN_DONE when we receive a TXN_ACK after the transaction
|
|
// has begun sending. This will happen when the workstation detects that it has
|
|
// sent/used all its currently mapped scatter gather elements, but it's not enough
|
|
// to complete the transaction. The TXN_DONE will let the workstation know it can
|
|
// release the current scatter gather mappings and allocate new ones.
|
|
always @ (posedge CLK) begin
|
|
rPartialDone <= #1 _rPartialDone;
|
|
rReqPartialDone <= #1 (RST ? 1'd0 : _rReqPartialDone);
|
|
end
|
|
|
|
always @ (*) begin
|
|
// Signal TXN_DONE after we've recieved the (seemingly superfluous) TXN_ACK
|
|
// and received the corresponding amount of words.
|
|
_rPartialDone = (rReqPartialDone & rPartWordsRecvd);
|
|
|
|
// Keep track of (seemingly superfluous) TXN_ACK requests.
|
|
if ((rReqPartialDone & rPartWordsRecvd) | rMainState[0]) // S_RXPORTRD_MAIN_IDLE
|
|
_rReqPartialDone = 0;
|
|
else
|
|
_rReqPartialDone = (rReqPartialDone | rTxnLenValid);
|
|
end
|
|
|
|
|
|
// Handle errors in the main data or scatter gather data.
|
|
always @ (posedge CLK) begin
|
|
rErr <= #1 (RST ? 1'd0 : _rErr);
|
|
end
|
|
|
|
always @ (*) begin
|
|
// Keep track of errors if we encounter them.
|
|
if (rMainState[0]) // S_RXPORTRD_MAIN_IDLE
|
|
_rErr = 0;
|
|
else
|
|
_rErr = (rErr | (RX_DONE & RX_ERR) | (SG_DONE & SG_ERR));
|
|
end
|
|
|
|
|
|
|
|
/*
|
|
wire [35:0] wControl0;
|
|
chipscope_icon_1 cs_icon(
|
|
.CONTROL0(wControl0)
|
|
);
|
|
|
|
chipscope_ila_t8_512 a0(
|
|
.CLK(CLK),
|
|
.CONTROL(wControl0),
|
|
.TRIG0({TXN_LEN_VALID | TXN_DONE_ACK | TXN_DONE | TXN_ERR, 1'd0, rMainState}),
|
|
.DATA({176'd0,
|
|
64'd0, // 64
|
|
rAddr, // 64
|
|
SG_ELEM_RDY, // 1
|
|
1'd0, // 1
|
|
1'd0, // 1
|
|
1'd0, // 1
|
|
rSgRen, // 1
|
|
1'd0, // 1
|
|
rLastDoneRead, // 1
|
|
rLen, // 10
|
|
rWords, // 32
|
|
rAckCount, // 11
|
|
rPartWords, // 32
|
|
rPartWordsRecvd, // 1
|
|
rReqPartialDone, // 1
|
|
rPartialDone, // 1
|
|
rTxnDone, // 1
|
|
rRxState, // 8
|
|
rRecvdWords, // 32
|
|
rReadWords, // 32
|
|
TXN_LEN_VALID, // 1
|
|
TXN_DONE_ACK, // 1
|
|
rDoneLen, // 32
|
|
rMainState}) // 6
|
|
);
|
|
*/
|
|
|
|
endmodule
|