1
0
mirror of https://github.com/KastnerRG/riffa.git synced 2024-12-24 22:58:54 +08:00
riffa/fpga/riffa_hdl/tx_multiplexer_128.v

371 lines
16 KiB
Verilog

`include "trellis.vh"
`define S_TXENGUPR128_MAIN_IDLE 1'b0
`define S_TXENGUPR128_MAIN_WR 1'b1
`define S_TXENGUPR128_CAP_RD_WR 4'b0001
`define S_TXENGUPR128_CAP_WR_RD 4'b0010
`define S_TXENGUPR128_CAP_CAP 4'b0100
`define S_TXENGUPR128_CAP_REL 4'b1000
`timescale 1ns/1ns
module tx_multiplexer_128
#(
parameter C_PCI_DATA_WIDTH = 128,
parameter C_NUM_CHNL = 12,
parameter C_TAG_WIDTH = 5, // Number of outstanding requests
parameter C_VENDOR = "ALTERA"
)
(
input CLK,
input RST_IN,
input [C_NUM_CHNL-1:0] WR_REQ, // Write request
input [(C_NUM_CHNL*`SIG_ADDR_W)-1:0] WR_ADDR, // Write address
input [(C_NUM_CHNL*`SIG_LEN_W)-1:0] WR_LEN, // Write data length
input [(C_NUM_CHNL*C_PCI_DATA_WIDTH)-1:0] WR_DATA, // Write data
output [C_NUM_CHNL-1:0] WR_DATA_REN, // Write data read enable
output [C_NUM_CHNL-1:0] WR_ACK, // Write request has been accepted
input [C_NUM_CHNL-1:0] RD_REQ, // Read request
input [(C_NUM_CHNL*2)-1:0] RD_SG_CHNL, // Read request channel for scatter gather lists
input [(C_NUM_CHNL*`SIG_ADDR_W)-1:0] RD_ADDR, // Read request address
input [(C_NUM_CHNL*`SIG_LEN_W)-1:0] RD_LEN, // Read request length
output [C_NUM_CHNL-1:0] RD_ACK, // Read request has been accepted
output [5:0] INT_TAG, // Internal tag to exchange with external
output INT_TAG_VALID, // High to signal tag exchange
input [C_TAG_WIDTH-1:0] EXT_TAG, // External tag to provide in exchange for internal tag
input EXT_TAG_VALID, // High to signal external tag is valid
output TX_ENG_RD_REQ_SENT, // Read completion request issued
input RXBUF_SPACE_AVAIL,
// Interface: TXR Engine
output TXR_DATA_VALID,
output [C_PCI_DATA_WIDTH-1:0] TXR_DATA,
output TXR_DATA_START_FLAG,
output [clog2s(C_PCI_DATA_WIDTH/32)-1:0] TXR_DATA_START_OFFSET,
output TXR_DATA_END_FLAG,
output [clog2s(C_PCI_DATA_WIDTH/32)-1:0] TXR_DATA_END_OFFSET,
input TXR_DATA_READY,
output TXR_META_VALID,
output [`SIG_FBE_W-1:0] TXR_META_FDWBE,
output [`SIG_LBE_W-1:0] TXR_META_LDWBE,
output [`SIG_ADDR_W-1:0] TXR_META_ADDR,
output [`SIG_LEN_W-1:0] TXR_META_LENGTH,
output [`SIG_TAG_W-1:0] TXR_META_TAG,
output [`SIG_TC_W-1:0] TXR_META_TC,
output [`SIG_ATTR_W-1:0] TXR_META_ATTR,
output [`SIG_TYPE_W-1:0] TXR_META_TYPE,
output TXR_META_EP,
input TXR_META_READY);
localparam C_DATA_DELAY = 6;
reg rMainState=`S_TXENGUPR128_MAIN_IDLE, _rMainState=`S_TXENGUPR128_MAIN_IDLE;
reg rCountIsWr=0, _rCountIsWr=0;
reg [9:0] rCountLen=0, _rCountLen=0;
reg [3:0] rCountChnl=0, _rCountChnl=0;
reg [C_TAG_WIDTH-1:0] rCountTag=0, _rCountTag=0;
reg [61:0] rCountAddr=62'd0, _rCountAddr=62'd0;
reg rCountAddr64=0, _rCountAddr64=0;
reg [9:0] rCount=0, _rCount=0;
reg rCountDone=0, _rCountDone=0;
reg rCountStart=0, _rCountStart=0;
reg rCountValid=0, _rCountValid=0;
reg [C_NUM_CHNL-1:0] rWrDataRen=0, _rWrDataRen=0;
reg rTxEngRdReqAck, _rTxEngRdReqAck;
wire wRdReq;
wire [3:0] wRdReqChnl;
wire wWrReq;
wire [3:0] wWrReqChnl;
wire wRdAck;
wire [3:0] wCountChnl;
wire [11:0] wCountChnlShiftDW = (wCountChnl*C_PCI_DATA_WIDTH); // Mult can exceed 9 bits, so make this a wire
wire [63:0] wRdAddr;
wire [9:0] wRdLen;
wire [1:0] wRdSgChnl;
wire [63:0] wWrAddr;
wire [9:0] wWrLen;
wire [C_PCI_DATA_WIDTH-1:0] wWrData;
wire [C_PCI_DATA_WIDTH-1:0] wWrDataSwap;
reg [3:0] rRdChnl=0, _rRdChnl=0;
reg [61:0] rRdAddr=62'd0, _rRdAddr=62'd0;
reg [9:0] rRdLen=0, _rRdLen=0;
reg [1:0] rRdSgChnl=0, _rRdSgChnl=0;
reg [3:0] rWrChnl=0, _rWrChnl=0;
reg [61:0] rWrAddr=62'd0, _rWrAddr=62'd0;
reg [9:0] rWrLen=0, _rWrLen=0;
reg [C_PCI_DATA_WIDTH-1:0] rWrData={C_PCI_DATA_WIDTH{1'd0}}, _rWrData={C_PCI_DATA_WIDTH{1'd0}};
assign wRdAddr = RD_ADDR[wRdReqChnl * `SIG_ADDR_W +: `SIG_ADDR_W];
assign wRdLen = RD_LEN[wRdReqChnl * `SIG_LEN_W +: `SIG_LEN_W];
assign wRdSgChnl = RD_SG_CHNL[wRdReqChnl * 2 +: 2];
assign wWrAddr = WR_ADDR[wWrReqChnl * `SIG_ADDR_W +: `SIG_ADDR_W];
assign wWrLen = WR_LEN[wWrReqChnl * `SIG_LEN_W +: `SIG_LEN_W];
assign wWrData = WR_DATA[wCountChnl * C_PCI_DATA_WIDTH +: C_PCI_DATA_WIDTH];
(* syn_encoding = "user" *)
(* fsm_encoding = "user" *)
reg [3:0] rCapState=`S_TXENGUPR128_CAP_RD_WR, _rCapState=`S_TXENGUPR128_CAP_RD_WR;
reg [C_NUM_CHNL-1:0] rRdAck=0, _rRdAck=0;
reg [C_NUM_CHNL-1:0] rWrAck=0, _rWrAck=0;
reg rIsWr=0, _rIsWr=0;
reg [5:0] rCapChnl=0, _rCapChnl=0;
reg [61:0] rCapAddr=62'd0, _rCapAddr=62'd0;
reg rCapAddr64=0, _rCapAddr64=0;
reg [9:0] rCapLen=0, _rCapLen=0;
reg rCapIsWr=0, _rCapIsWr=0;
reg rExtTagReq=0, _rExtTagReq=0;
reg [C_TAG_WIDTH-1:0] rExtTag=0, _rExtTag=0;
reg [C_DATA_DELAY-1:0] rWnR=0, _rWnR=0;
reg [(C_DATA_DELAY*4)-1:0] rChnl=0, _rChnl=0;
reg [(C_DATA_DELAY*8)-1:0] rTag=0, _rTag=0;
reg [(C_DATA_DELAY*62)-1:0] rAddr=0, _rAddr=0;
reg [C_DATA_DELAY-1:0] rAddr64=0, _rAddr64=0;
reg [(C_DATA_DELAY*10)-1:0] rLen=0, _rLen=0;
reg [C_DATA_DELAY-1:0] rLenEQ1=0, _rLenEQ1=0;
reg [C_DATA_DELAY-1:0] rValid=0, _rValid=0;
reg [C_DATA_DELAY-1:0] rDone=0, _rDone=0;
reg [C_DATA_DELAY-1:0] rStart=0, _rStart=0;
assign WR_DATA_REN = rWrDataRen;
assign WR_ACK = rWrAck;
assign RD_ACK = rRdAck;
assign INT_TAG = {rRdSgChnl, rRdChnl};
assign INT_TAG_VALID = rExtTagReq;
assign TX_ENG_RD_REQ_SENT = rTxEngRdReqAck;
assign wRdAck = (wRdReq & EXT_TAG_VALID & RXBUF_SPACE_AVAIL);
// Search for the next request so that we can move onto it immediately after
// the current channel has released its request.
tx_engine_selector #(.C_NUM_CHNL(C_NUM_CHNL)) selRd (.RST(RST_IN), .CLK(CLK), .REQ_ALL(RD_REQ), .REQ(wRdReq), .CHNL(wRdReqChnl));
tx_engine_selector #(.C_NUM_CHNL(C_NUM_CHNL)) selWr (.RST(RST_IN), .CLK(CLK), .REQ_ALL(WR_REQ), .REQ(wWrReq), .CHNL(wWrReqChnl));
// Buffer shift-selected channel request signals and FIFO data.
always @ (posedge CLK) begin
rRdChnl <= #1 _rRdChnl;
rRdAddr <= #1 _rRdAddr;
rRdLen <= #1 _rRdLen;
rRdSgChnl <= #1 _rRdSgChnl;
rWrChnl <= #1 _rWrChnl;
rWrAddr <= #1 _rWrAddr;
rWrLen <= #1 _rWrLen;
rWrData <= #1 _rWrData;
end
always @ (*) begin
_rRdChnl = wRdReqChnl;
_rRdAddr = wRdAddr[63:2];
_rRdLen = wRdLen;
_rRdSgChnl = wRdSgChnl;
_rWrChnl = wWrReqChnl;
_rWrAddr = wWrAddr[63:2];
_rWrLen = wWrLen;
_rWrData = wWrData;
end
// Accept requests when the selector indicates. Capture the buffered
// request parameters for hand-off to the formatting pipeline. Then
// acknowledge the receipt to the channel so it can deassert the
// request, and let the selector choose another channel.
always @ (posedge CLK) begin
rCapState <= #1 (RST_IN ? `S_TXENGUPR128_CAP_RD_WR : _rCapState);
rRdAck <= #1 (RST_IN ? {C_NUM_CHNL{1'd0}} : _rRdAck);
rWrAck <= #1 (RST_IN ? {C_NUM_CHNL{1'd0}} : _rWrAck);
rIsWr <= #1 _rIsWr;
rCapChnl <= #1 _rCapChnl;
rCapAddr <= #1 _rCapAddr;
rCapAddr64 <= #1 _rCapAddr64;
rCapLen <= #1 _rCapLen;
rCapIsWr <= #1 _rCapIsWr;
rExtTagReq <= #1 _rExtTagReq;
rExtTag <= #1 _rExtTag;
rTxEngRdReqAck <= #1 _rTxEngRdReqAck;
end
always @ (*) begin
_rCapState = rCapState;
_rRdAck = rRdAck;
_rWrAck = rWrAck;
_rIsWr = rIsWr;
_rCapChnl = rCapChnl;
_rCapAddr = rCapAddr;
_rCapAddr64 = rCapAddr64;
_rCapLen = rCapLen;
_rCapIsWr = rCapIsWr;
_rExtTagReq = rExtTagReq;
_rExtTag = rExtTag;
_rTxEngRdReqAck = rTxEngRdReqAck;
case (rCapState)
`S_TXENGUPR128_CAP_RD_WR : begin
_rIsWr = !wRdReq;
_rRdAck = ((wRdAck)<<wRdReqChnl);
_rTxEngRdReqAck = wRdAck;
_rExtTagReq = wRdAck;
_rCapState = (wRdAck ? `S_TXENGUPR128_CAP_CAP : `S_TXENGUPR128_CAP_WR_RD);
end
`S_TXENGUPR128_CAP_WR_RD : begin
_rIsWr = wWrReq;
_rWrAck = (wWrReq<<wWrReqChnl);
_rCapState = (wWrReq ? `S_TXENGUPR128_CAP_CAP : `S_TXENGUPR128_CAP_RD_WR);
end
`S_TXENGUPR128_CAP_CAP : begin
_rTxEngRdReqAck = 0;
_rRdAck = 0;
_rWrAck = 0;
_rCapIsWr = rIsWr;
_rExtTagReq = 0;
_rExtTag = EXT_TAG ^ {rIsWr,{(C_TAG_WIDTH-1){1'b0}}};
if (rIsWr) begin
_rCapChnl = {2'd0, rWrChnl};
_rCapAddr = rWrAddr;
_rCapAddr64 = (rWrAddr[61:30] != 0);
_rCapLen = rWrLen;
end
else begin
_rCapChnl = {rRdSgChnl, rRdChnl};
_rCapAddr = rRdAddr;
_rCapAddr64 = (rRdAddr[61:30] != 0);
_rCapLen = rRdLen;
end
_rCapState = `S_TXENGUPR128_CAP_REL;
end
`S_TXENGUPR128_CAP_REL : begin
// Push into the formatting pipeline when ready
if (TXR_META_READY & !rMainState) begin // S_TXENGUPR128_MAIN_IDLE
_rCapState = (`S_TXENGUPR128_CAP_WR_RD>>(rCapIsWr)); // Changes to S_TXENGUPR128_CAP_RD_WR
end
end
default : begin
_rCapState = `S_TXENGUPR128_CAP_RD_WR;
end
endcase
end
// Start the read/write when space is available in the output FIFO and when
// request parameters have been captured (i.e. a pending request).
always @ (posedge CLK) begin
rMainState <= #1 (RST_IN ? `S_TXENGUPR128_MAIN_IDLE : _rMainState);
rCountIsWr <= #1 _rCountIsWr;
rCountLen <= #1 _rCountLen;
rCountChnl <= #1 _rCountChnl;
rCountTag <= #1 _rCountTag;
rCountAddr <= #1 _rCountAddr;
rCountAddr64 <= #1 _rCountAddr64;
rCount <= #1 _rCount;
rCountDone <= #1 _rCountDone;
rCountStart <= #1 _rCountStart;
rCountValid <= #1 _rCountValid;
rWrDataRen <= #1 _rWrDataRen;
end
always @ (*) begin
_rMainState = rMainState;
_rCountIsWr = rCountIsWr;
_rCountLen = rCountLen;
_rCountChnl = rCountChnl;
_rCountTag = rCountTag;
_rCountAddr = rCountAddr;
_rCountAddr64 = rCountAddr64;
_rCount = rCount;
_rCountDone = rCountDone;
_rCountValid = rCountValid;
_rWrDataRen = rWrDataRen;
_rCountStart = 0;
case (rMainState)
`S_TXENGUPR128_MAIN_IDLE : begin
_rCountIsWr = rCapIsWr;
_rCountLen = rCapLen;
_rCountChnl = rCapChnl[3:0];
_rCountTag = rExtTag;
_rCountAddr = rCapAddr;
_rCountAddr64 = rCapAddr64;
_rCount = rCapLen;
_rCountDone = (rCapLen <= 3'd4);
_rWrDataRen = ((TXR_META_READY & rCapState[3] & rCapIsWr)<<(rCapChnl[3:0])); // S_TXENGUPR128_CAP_REL
_rCountValid = (TXR_META_READY & rCapState[3]);
_rCountStart = (TXR_META_READY & rCapState[3]);
if (TXR_META_READY && rCapState[3] && rCapIsWr && (rCapAddr64 || (rCapLen != 10'd1))) // S_TXENGUPR128_CAP_REL
_rMainState = `S_TXENGUPR128_MAIN_WR;
end
`S_TXENGUPR128_MAIN_WR : begin
_rCount = rCount - 3'd4;
_rCountDone = (rCount <= 4'd8);
if (rCountDone) begin
_rWrDataRen = 0;
_rCountValid = 0;
_rMainState = `S_TXENGUPR128_MAIN_IDLE;
end
end
endcase
end
// Shift in the captured parameters and valid signal every cycle.
// This pipeline will keep the formatter busy.
assign wCountChnl = rChnl[(C_DATA_DELAY-2)*4 +:4];
always @ (posedge CLK) begin
rWnR <= #1 _rWnR;
rChnl <= #1 _rChnl;
rTag <= #1 _rTag;
rAddr <= #1 _rAddr;
rAddr64 <= #1 _rAddr64;
rLen <= #1 _rLen;
rLenEQ1 <= #1 _rLenEQ1;
rValid <= #1 _rValid;
rDone <= #1 _rDone;
rStart <= #1 _rStart;
end
always @ (*) begin
_rWnR = {rWnR[((C_DATA_DELAY-1)*1)-1:0], rCountIsWr};
_rChnl = {rChnl[((C_DATA_DELAY-1)*4)-1:0], rCountChnl};
_rTag = {rTag[((C_DATA_DELAY-1)*8)-1:0], (8'd0 | rCountTag)};
_rAddr = {rAddr[((C_DATA_DELAY-1)*62)-1:0], rCountAddr};
_rAddr64 = {rAddr64[((C_DATA_DELAY-1)*1)-1:0], rCountAddr64};
_rLen = {rLen[((C_DATA_DELAY-1)*10)-1:0], rCountLen};
_rLenEQ1 = {rLenEQ1[((C_DATA_DELAY-1)*1)-1:0], (rCountLen == 10'd1)};
_rValid = {rValid[((C_DATA_DELAY-1)*1)-1:0], rCountValid & rCountIsWr};
_rDone = {rDone[((C_DATA_DELAY-1)*1)-1:0], rCountDone};
_rStart = {rStart[((C_DATA_DELAY-1)*1)-1:0], rCountStart};
end // always @ begin
assign TXR_DATA = rWrData;
assign TXR_DATA_VALID = rValid[(C_DATA_DELAY-1)*1 +:1];
assign TXR_DATA_START_FLAG = rStart[(C_DATA_DELAY-1)*1 +:1];
assign TXR_DATA_START_OFFSET = 0;
assign TXR_DATA_END_FLAG = rDone[(C_DATA_DELAY-1)*1 +:1];
assign TXR_DATA_END_OFFSET = rLen[(C_DATA_DELAY-1)*10 +:`SIG_OFFSET_W] - 1;
assign TXR_META_VALID = rCountStart;
assign TXR_META_TYPE = rCountIsWr ? `TRLS_REQ_WR : `TRLS_REQ_RD;
assign TXR_META_ADDR = {rCountAddr,2'b00};
assign TXR_META_LENGTH = rCountLen;
assign TXR_META_LDWBE = rCountLen == 10'd1 ? 0 : 4'b1111;
assign TXR_META_FDWBE = 4'b1111;
assign TXR_META_TAG = rCountTag;
assign TXR_META_EP = 1'b0;
assign TXR_META_ATTR = 3'b110;
assign TXR_META_TC = 0;
endmodule