diff --git a/lib/blue-wrapper b/lib/blue-wrapper index a0d0fcc..3fd7e89 160000 --- a/lib/blue-wrapper +++ b/lib/blue-wrapper @@ -1 +1 @@ -Subproject commit a0d0fccccaa6b64bfae14f317773d08888d527a6 +Subproject commit 3fd7e89bc81b1bf934e1a38889cf3f803f9414b4 diff --git a/src/PriorityFlowControl.bsv b/src/PriorityFlowControl.bsv index 2e8cbaa..f8cade9 100644 --- a/src/PriorityFlowControl.bsv +++ b/src/PriorityFlowControl.bsv @@ -13,13 +13,18 @@ import EthernetTypes :: *; typedef enum { FLOW_CTRL_STOP, FLOW_CTRL_PASS -} FlowControlState deriving(Bits, Eq, FShow); - -typedef struct { - VirtualChannelIndex channelIdx; - FlowControlState channelState; } FlowControlRequest deriving(Bits, Eq, FShow); +typedef Vector#(VIRTUAL_CHANNEL_NUM, Maybe#(FlowControlRequest)) FlowControlReqVec; + +function VirtualChannelIndex mapDscpToChannelIdx(IpDscp ipDscp); + return truncateLSB(ipDscp); +endfunction + +function IpDscp mapChannelIdxToDscp(VirtualChannelIndex channelIdx); + return {channelIdx, 0}; +endfunction + module mkPipeOutFairArbiter#(Vector#(clientNum, PipeOut#(dType)) clients)(PipeOut#(dType)) provisos( Bits#(dType, dSize), @@ -68,15 +73,16 @@ interface PriorityFlowControlRx#( numeric type pfcThreshold ); // pause and resume request from receiver - interface Get#(FlowControlRequest) flowControlReqOut; + interface PipeOut#(FlowControlReqVec) flowControlReqVecOut; - interface Vector#(VIRTUAL_CHANNEL_NUM, Get#(UdpIpMetaData)) udpIpMetaDataOutVec; interface Vector#(VIRTUAL_CHANNEL_NUM, Get#(DataStream)) dataStreamOutVec; - interface Put#(UdpIpMetaDataAndChannelIdx) udpIpMetaAndChannelIdxIn; - interface Put#(DataStream) dataStreamIn; + interface Vector#(VIRTUAL_CHANNEL_NUM, Get#(UdpIpMetaData)) udpIpMetaDataOutVec; endinterface -module mkPriorityFlowControlRx(PriorityFlowControlRx#(bufPacketNum, maxPacketFrameNum, pfcThreshold)) +module mkPriorityFlowControlRx#( + DataStreamPipeOut dataStreamIn, + UdpIpMetaDataPipeOut udpIpMetaDataIn +)(PriorityFlowControlRx#(bufPacketNum, maxPacketFrameNum, pfcThreshold)) provisos( Add#(pfcThreshold, __a, bufPacketNum), Mul#(bufPacketNum, maxPacketFrameNum, bufFrameNum), @@ -86,22 +92,20 @@ module mkPriorityFlowControlRx(PriorityFlowControlRx#(bufPacketNum, maxPacketFra Integer udpIpMetaBufDepth = valueOf(bufPacketNum); Integer dataStreamBufDepth = valueOf(bufFrameNum); Integer flowCtrlThreshold = valueOf(pfcThreshold); - FIFOF#(UdpIpMetaDataAndChannelIdx) udpIpMetaAndChannelIdxInBuf <- mkFIFOF; - FIFOF#(DataStream) dataStreamInBuf <- mkFIFOF; - + FIFOF#(FlowControlReqVec) flowControlReqVecOutBuf <- mkFIFOF; Vector#(VIRTUAL_CHANNEL_NUM, Count#(Bit#(packetCountWidth))) packetNumCountVec <- replicateM(mkCount(0)); - Vector#(VIRTUAL_CHANNEL_NUM, Reg#(FlowControlState)) flowCtrlStateVec <- replicateM(mkReg(FLOW_CTRL_PASS)); + Vector#(VIRTUAL_CHANNEL_NUM, Reg#(FlowControlRequest)) flowCtrlStateVec <- replicateM(mkReg(FLOW_CTRL_PASS)); Vector#(VIRTUAL_CHANNEL_NUM, FIFOF#(UdpIpMetaData)) udpIpMetaDataOutBufVec <- replicateM(mkSizedFIFOF(udpIpMetaBufDepth)); Vector#(VIRTUAL_CHANNEL_NUM, FIFOF#(DataStream)) dataStreamOutBufVec <- replicateM(mkSizedBRAMFIFOF(dataStreamBufDepth)); - Vector#(VIRTUAL_CHANNEL_NUM, FIFOF#(FlowControlRequest)) flowControlReqBufVec <- replicateM(mkFIFOF); + FIFOF#(VirtualChannelIndex) dataStreamPassIdxBuf <- mkFIFOF; rule passUdpIpMetaData; - let udpIpMetaAndChannelIdx = udpIpMetaAndChannelIdxInBuf.first; - udpIpMetaAndChannelIdxInBuf.deq; - let channelIdx = udpIpMetaAndChannelIdx.channelIdx; - let udpIpMetaData = udpIpMetaAndChannelIdx.udpIpMetaData; + let udpIpMetaData = udpIpMetaDataIn.first; + udpIpMetaDataIn.deq; + VirtualChannelIndex channelIdx = mapDscpToChannelIdx(udpIpMetaData.ipDscp); + udpIpMetaData.ipDscp = 0; udpIpMetaDataOutBufVec[channelIdx].enq(udpIpMetaData); packetNumCountVec[channelIdx].incr(1); dataStreamPassIdxBuf.enq(channelIdx); @@ -109,45 +113,46 @@ module mkPriorityFlowControlRx(PriorityFlowControlRx#(bufPacketNum, maxPacketFra rule passDataStream; let channelIdx = dataStreamPassIdxBuf.first; - let dataStream = dataStreamInBuf.first; - dataStreamInBuf.deq; + let dataStream = dataStreamIn.first; + dataStreamIn.deq; dataStreamOutBufVec[channelIdx].enq(dataStream); if (dataStream.isLast) begin dataStreamPassIdxBuf.deq; end endrule - for (Integer i = 0; i < virtualChannelNum; i = i + 1) begin - rule genFlowControlReq; - let flowControlReq = FlowControlRequest { - channelIdx: fromInteger(i), - channelState: FLOW_CTRL_STOP - }; + rule genFlowControlReq; + FlowControlReqVec flowControlReqVec = replicate(tagged Invalid); + Bool hasRequest = False; + for (Integer i = 0; i < virtualChannelNum; i = i + 1) begin if (packetNumCountVec[i] >= fromInteger(flowCtrlThreshold)) begin if (flowCtrlStateVec[i] == FLOW_CTRL_PASS) begin - flowControlReqBufVec[i].enq(flowControlReq); + flowControlReqVec[i] = tagged Valid FLOW_CTRL_STOP; flowCtrlStateVec[i] <= FLOW_CTRL_STOP; + hasRequest = True; + $display("PriorityFlowControlRx: channel %d send pause request", i); end end else begin if (flowCtrlStateVec[i] == FLOW_CTRL_STOP) begin - flowControlReq.channelState = FLOW_CTRL_PASS; - flowControlReqBufVec[i].enq(flowControlReq); + flowControlReqVec[i] = tagged Valid FLOW_CTRL_PASS; flowCtrlStateVec[i] <= FLOW_CTRL_PASS; + hasRequest = True; + $display("PriorityFlowControlRx: channel %d send resume request", i); end end - endrule - end + end + if (hasRequest) begin + flowControlReqVecOutBuf.enq(flowControlReqVec); + end + endrule - let flowControlReqPipeOut <- mkPipeOutFairArbiter( - map(convertFifoToPipeOut, flowControlReqBufVec) - ); - Vector#(VIRTUAL_CHANNEL_NUM, Get#(DataStream)) dataStreamPorts = newVector; - Vector#(VIRTUAL_CHANNEL_NUM, Get#(UdpIpMetaData)) udpIpMetaDataPorts = newVector; + Vector#(VIRTUAL_CHANNEL_NUM, Get#(DataStream)) dataStreamVec = newVector; + Vector#(VIRTUAL_CHANNEL_NUM, Get#(UdpIpMetaData)) udpIpMetaDataVec = newVector; for (Integer i = 0; i < virtualChannelNum; i = i + 1) begin - udpIpMetaDataPorts[i] = toGet(udpIpMetaDataOutBufVec[i]); - dataStreamPorts[i] = ( + udpIpMetaDataVec[i] = toGet(udpIpMetaDataOutBufVec[i]); + dataStreamVec[i] = ( interface Get#(DataStream) method ActionValue#(DataStream) get; let dataStream = dataStreamOutBufVec[i].first; @@ -161,99 +166,73 @@ module mkPriorityFlowControlRx(PriorityFlowControlRx#(bufPacketNum, maxPacketFra ); end - interface flowControlReqOut = toGet(flowControlReqPipeOut); - interface dataStreamOutVec = dataStreamPorts; - interface udpIpMetaDataOutVec = udpIpMetaDataPorts; - interface udpIpMetaAndChannelIdxIn = toPut(udpIpMetaAndChannelIdxInBuf); - interface dataStreamIn = toPut(dataStreamInBuf); + interface flowControlReqVecOut = convertFifoToPipeOut(flowControlReqVecOutBuf); + interface dataStreamOutVec = dataStreamVec; + interface udpIpMetaDataOutVec = udpIpMetaDataVec; endmodule -interface PriorityFlowControlTx#( - numeric type bufPacketNum, - numeric type maxPacketFrameNum -); - // - interface Put#(FlowControlRequest) flowControlReqIn; - // - interface Vector#(VIRTUAL_CHANNEL_NUM, Put#(UdpIpMetaData)) udpIpMetaDataInVec; - interface Vector#(VIRTUAL_CHANNEL_NUM, Put#(DataStream)) dataStreamInVec; - - interface Get#(UdpIpMetaDataAndChannelIdx) udpIpMetaAndChannelIdxOut; +interface PriorityFlowControlTx; + interface Get#(UdpIpMetaData) udpIpMetaDataOut; interface Get#(DataStream) dataStreamOut; endinterface -module mkPriorityFlowControlTx(PriorityFlowControlTx#(bufPacketNum, maxPacketFrameNum)) - provisos(Mul#(bufPacketNum, maxPacketFrameNum, bufFrameNum)); - Integer udpIpMetaBufDepth = valueOf(bufPacketNum); - Integer dataStreamBufDepth = valueOf(bufFrameNum); +module mkPriorityFlowControlTx#( + PipeOut#(FlowControlReqVec) flowControlReqVecIn, + Vector#(VIRTUAL_CHANNEL_NUM, DataStreamPipeOut) dataStreamInVec, + Vector#(VIRTUAL_CHANNEL_NUM, UdpIpMetaDataPipeOut) udpIpMetaDataInVec +)(PriorityFlowControlTx); + Integer virtualChannelNum = valueOf(VIRTUAL_CHANNEL_NUM); - Vector#(VIRTUAL_CHANNEL_NUM, FIFOF#(DataStream)) dataStreamInBufVec <- replicateM(mkSizedBRAMFIFOF(dataStreamBufDepth)); - Vector#(VIRTUAL_CHANNEL_NUM, FIFOF#(UdpIpMetaData)) udpIpMetaDataInBufVec <- replicateM(mkSizedBRAMFIFOF(udpIpMetaBufDepth)); - Vector#(VIRTUAL_CHANNEL_NUM, FIFOF#(UdpIpMetaDataAndChannelIdx)) udpIpMetaAndChannelIdxBufVec <- replicateM(mkFIFOF); - Vector#(VIRTUAL_CHANNEL_NUM, Reg#(FlowControlState)) channelStateVec <- replicateM(mkReg(FLOW_CTRL_PASS)); - - FIFOF#(FlowControlRequest) flowControlReqBufVec <- mkFIFOF; - FIFOF#(DataStream) dataStreamOutBufVec <- mkFIFOF; - FIFOF#(UdpIpMetaDataAndChannelIdx) udpIpMetaAndChannelIdxOutBuf <- mkFIFOF; + Vector#(VIRTUAL_CHANNEL_NUM, FIFOF#(UdpIpMetaData)) udpIpMetaDataInterBufVec <- replicateM(mkFIFOF); + Vector#(VIRTUAL_CHANNEL_NUM, Reg#(FlowControlRequest)) channelStateVec <- replicateM(mkReg(FLOW_CTRL_PASS)); + FIFOF#(DataStream) dataStreamOutBuf <- mkFIFOF; FIFOF#(VirtualChannelIndex) dataStreamPassIdxBuf <- mkFIFOF; - rule setChannelState; - let request = flowControlReqBufVec.first; - flowControlReqBufVec.deq; - channelStateVec[request.channelIdx] <= request.channelState; + rule updateChannelState; + let flowCtrlReqVec = flowControlReqVecIn.first; + flowControlReqVecIn.deq; + for (Integer i = 0; i < virtualChannelNum; i = i + 1) begin + if (flowCtrlReqVec[i] matches tagged Valid .newState) begin + channelStateVec[i] <= newState; + String newStateStr = (newState == FLOW_CTRL_PASS) ? "Pass" : "Pause"; + $display("PriorityFlowControlTx: Channel %d switch to ", i, newStateStr); + end + end endrule for (Integer idx = 0; idx < virtualChannelNum; idx = idx + 1) begin rule passUdpIpMetaData if (channelStateVec[idx] == FLOW_CTRL_PASS); - let udpIpMetaData = udpIpMetaDataInBufVec[idx].first; - udpIpMetaDataInBufVec[idx].deq; - udpIpMetaAndChannelIdxBufVec[idx].enq( - UdpIpMetaDataAndChannelIdx { - udpIpMetaData: udpIpMetaData, - channelIdx: fromInteger(idx) - } - ); + let udpIpMetaData = udpIpMetaDataInVec[idx].first; + udpIpMetaDataInVec[idx].deq; + udpIpMetaData.ipDscp = mapChannelIdxToDscp(fromInteger(idx)); + udpIpMetaDataInterBufVec[idx].enq(udpIpMetaData); endrule end - let udpIpMetaAndChannelIdxPipeOut <- mkPipeOutFairArbiter( - map(convertFifoToPipeOut, udpIpMetaAndChannelIdxBufVec) + let udpIpMetaDataArbitrated <- mkPipeOutFairArbiter( + map(convertFifoToPipeOut, udpIpMetaDataInterBufVec) ); - rule passUdpIpMetaAndChannelIdx; - let udpIpMetaAndChannelIdx = udpIpMetaAndChannelIdxPipeOut.first; - udpIpMetaAndChannelIdxPipeOut.deq; - let channelIdx = udpIpMetaAndChannelIdx.channelIdx; - udpIpMetaAndChannelIdxOutBuf.enq(udpIpMetaAndChannelIdx); - dataStreamPassIdxBuf.enq(channelIdx); - endrule rule passDataStream; let channelIdx = dataStreamPassIdxBuf.first; - let dataStream = dataStreamInBufVec[channelIdx].first; - dataStreamInBufVec[channelIdx].deq; - dataStreamOutBufVec.enq(dataStream); + let dataStream = dataStreamInVec[channelIdx].first; + dataStreamInVec[channelIdx].deq; + dataStreamOutBuf.enq(dataStream); if (dataStream.isLast) begin dataStreamPassIdxBuf.deq; end endrule - Vector#(VIRTUAL_CHANNEL_NUM, Put#(DataStream)) dataStreamPorts = newVector; - Vector#(VIRTUAL_CHANNEL_NUM, Put#(UdpIpMetaData)) udpIpMetaDataPorts = newVector; - for (Integer i = 0; i < virtualChannelNum; i = i + 1) begin - dataStreamPorts[i] = toPut(dataStreamInBufVec[i]); - udpIpMetaDataPorts[i] = toPut(udpIpMetaDataInBufVec[i]); - end - - interface flowControlReqIn = toPut(flowControlReqBufVec); - interface dataStreamInVec = dataStreamPorts; - interface udpIpMetaDataInVec = udpIpMetaDataPorts; - interface udpIpMetaAndChannelIdxOut = toGet(udpIpMetaAndChannelIdxOutBuf); - interface dataStreamOut = toGet(dataStreamOutBufVec); + interface Get udpIpMetaDataOut; + method ActionValue#(UdpIpMetaData) get(); + let udpIpMetaData = udpIpMetaDataArbitrated.first; + udpIpMetaDataArbitrated.deq; + dataStreamPassIdxBuf.enq(mapDscpToChannelIdx(udpIpMetaData.ipDscp)); + return udpIpMetaData; + endmethod + endinterface + interface dataStreamOut = toGet(dataStreamOutBuf); endmodule - - - - diff --git a/src/RdmaUdpArpEthRxTx.bsv b/src/RdmaUdpIpArpEthRxTx.bsv similarity index 97% rename from src/RdmaUdpArpEthRxTx.bsv rename to src/RdmaUdpIpArpEthRxTx.bsv index 275e6eb..719279f 100644 --- a/src/RdmaUdpArpEthRxTx.bsv +++ b/src/RdmaUdpIpArpEthRxTx.bsv @@ -9,7 +9,7 @@ import ArpCache :: *; import UdpIpLayer :: *; import ArpProcessor :: *; import EthernetTypes :: *; -import UdpArpEthRxTx :: *; +import UdpIpArpEthRxTx :: *; import PortConversion :: *; import UdpIpLayerForRdma :: *; @@ -18,7 +18,7 @@ import AxiStreamTypes :: *; import BusConversion :: *; (* synthesize *) -module mkRdmaUdpArpEthRxTx(UdpArpEthRxTx); +module mkRdmaUdpIpArpEthRxTx(UdpIpArpEthRxTx); Reg#(Maybe#(UdpConfig)) udpConfigReg <- mkReg(Invalid); let udpConfigVal = fromMaybe(?, udpConfigReg); @@ -189,8 +189,8 @@ module mkRdmaUdpArpEthRxTx(UdpArpEthRxTx); endmodule -module mkRawRdmaUdpArpEthRxTx(RawUdpArpEthRxTx); - UdpArpEthRxTx rdmaUdpRxTx <- mkRdmaUdpArpEthRxTx; +module mkRawRdmaUdpIpArpEthRxTx(RawUdpIpArpEthRxTx); + UdpIpArpEthRxTx rdmaUdpRxTx <- mkRdmaUdpIpArpEthRxTx; let rawConfig <- mkRawUdpConfigBusSlave(rdmaUdpRxTx.udpConfig); let rawUdpIpMetaDataTx <- mkRawUdpIpMetaDataBusSlave(rdmaUdpRxTx.udpIpMetaDataInTx); diff --git a/src/UdpArpEthRxTx.bsv b/src/UdpIpArpEthRxTx.bsv similarity index 73% rename from src/UdpArpEthRxTx.bsv rename to src/UdpIpArpEthRxTx.bsv index 8a3532f..34fe0a8 100644 --- a/src/UdpArpEthRxTx.bsv +++ b/src/UdpIpArpEthRxTx.bsv @@ -1,28 +1,34 @@ -import GetPut :: *; import FIFOF :: *; +import GetPut :: *; +import Clocks :: *; +import BRAMFIFO :: *; +import Connectable :: *; -import UdpIpLayer :: *; +import Utils :: *; +import Ports :: *; +import ArpCache :: *; import MacLayer :: *; +import UdpIpLayer :: *; import ArpProcessor :: *; -import ArpCache :: *; -import Ports :: *; -import PortConversion :: *; import EthernetTypes :: *; -import Utils :: *; +import PortConversion :: *; +import PriorityFlowControl :: *; +import XilinxCmacRxTxWrapper :: *; + import SemiFifo :: *; import AxiStreamTypes :: *; import BusConversion :: *; -interface UdpArpEthRxTx; +interface UdpIpArpEthRxTx; interface Put#(UdpConfig) udpConfig; // Tx interface Put#(UdpIpMetaData) udpIpMetaDataInTx; interface Put#(DataStream) dataStreamInTx; - interface AxiStream512PipeOut axiStreamOutTx; + interface AxiStream512PipeOut axiStreamOutTx; // Rx - interface Put#(AxiStream512) axiStreamInRx; + interface Put#(AxiStream512) axiStreamInRx; interface UdpIpMetaDataPipeOut udpIpMetaDataOutRx; interface DataStreamPipeOut dataStreamOutRx; endinterface @@ -33,7 +39,7 @@ typedef enum{ typedef MuxState DemuxState; (* synthesize *) -module mkUdpArpEthRxTx(UdpArpEthRxTx); +module mkUdpIpArpEthRxTx(UdpIpArpEthRxTx); Reg#(Maybe#(UdpConfig)) udpConfigReg <- mkReg(Invalid); let udpConfigVal = fromMaybe(?, udpConfigReg); @@ -61,10 +67,10 @@ module mkUdpArpEthRxTx(UdpArpEthRxTx); // Tx datapath DataStreamPipeOut ipUdpStreamTx <- mkUdpIpStream( - genUdpIpHeader, - convertFifoToPipeOut(udpMetaDataTxBuf), + udpConfigVal, convertFifoToPipeOut(dataStreamInTxBuf), - udpConfigVal + convertFifoToPipeOut(udpMetaDataTxBuf), + genUdpIpHeader ); rule doMux; @@ -164,9 +170,9 @@ module mkUdpArpEthRxTx(UdpArpEthRxTx); endrule UdpIpMetaDataAndDataStream udpIpMetaDataAndDataStream <- mkUdpIpMetaDataAndDataStream( - extractUdpIpMetaData, - convertFifoToPipeOut(ipUdpStreamRxBuf), - udpConfigVal + udpConfigVal, + convertFifoToPipeOut(ipUdpStreamRxBuf), + extractUdpIpMetaData ); @@ -206,7 +212,7 @@ module mkUdpArpEthRxTx(UdpArpEthRxTx); endmodule -interface RawUdpArpEthRxTx; +interface RawUdpIpArpEthRxTx; interface RawUdpConfigBusSlave rawUdpConfig; // Tx interface RawUdpIpMetaDataBusSlave rawUdpIpMetaDataInTx; @@ -219,8 +225,8 @@ interface RawUdpArpEthRxTx; endinterface -module mkRawUdpArpEthRxTx(RawUdpArpEthRxTx); - UdpArpEthRxTx udpRxTx <- mkUdpArpEthRxTx; +module mkRawUdpIpArpEthRxTx(RawUdpIpArpEthRxTx); + UdpIpArpEthRxTx udpRxTx <- mkUdpIpArpEthRxTx; let rawConfig <- mkRawUdpConfigBusSlave(udpRxTx.udpConfig); let rawUdpIpMetaDataTx <- mkRawUdpIpMetaDataBusSlave(udpRxTx.udpIpMetaDataInTx); @@ -242,4 +248,79 @@ module mkRawUdpArpEthRxTx(RawUdpArpEthRxTx); interface rawAxiStreamInRx = rawAxiStreamRx; endmodule +// UdpIpArpEthRxTx module with wrapper of Xilinx 100Gb CMAC IP +interface UdpIpArpEthCmacRxTx; + // Interface with CMAC IP + (* prefix = "" *) + interface XilinxCmacRxTxWrapper cmacRxTxWrapper; + + // Configuration Interface + interface Put#(UdpConfig) udpConfig; + + // Tx + interface Put#(UdpIpMetaData) udpIpMetaDataInTx; + interface Put#(DataStream) dataStreamInTx; + + // Rx + interface UdpIpMetaDataPipeOut udpIpMetaDataOutRx; + interface DataStreamPipeOut dataStreamOutRx; +endinterface + +module mkUdpIpArpEthCmacRxTx#( + Bool isCmacTxWaitRxAligned, + Integer syncBramBufDepth +)( + Clock cmacRxTxClk, + Reset cmacRxReset, + Reset cmacTxReset, + UdpIpArpEthCmacRxTx ifc +); + let isEnableFlowControl = False; + let currentClock <- exposeCurrentClock; + let currentReset <- exposeCurrentReset; + SyncFIFOIfc#(AxiStream512) txSyncBuf <- mkSyncBRAMFIFO( + syncBramBufDepth, + currentClock, + currentReset, + cmacRxTxClk, + cmacTxReset + ); + + SyncFIFOIfc#(AxiStream512) rxSyncBuf <- mkSyncBRAMFIFO( + syncBramBufDepth, + cmacRxTxClk, + cmacRxReset, + currentClock, + currentReset + ); + + PipeOut#(FlowControlReqVec) txFlowCtrlReqVec <- mkDummyPipeOut; + PipeIn#(FlowControlReqVec) rxFlowCtrlReqVec <- mkDummyPipeIn; + let cmacWrapper <- mkXilinxCmacRxTxWrapper( + isEnableFlowControl, + isCmacTxWaitRxAligned, + convertSyncFifoToPipeOut(txSyncBuf), + convertSyncFifoToPipeIn(rxSyncBuf), + txFlowCtrlReqVec, + rxFlowCtrlReqVec, + cmacRxReset, + cmacTxReset, + clocked_by cmacRxTxClk + ); + + let udpIpArpEthRxTx <- mkUdpIpArpEthRxTx; + mkConnection(convertSyncFifoToPipeIn(txSyncBuf), udpIpArpEthRxTx.axiStreamOutTx); + mkConnection(toGet(convertSyncFifoToPipeOut(rxSyncBuf)), udpIpArpEthRxTx.axiStreamInRx); + + + interface cmacRxTxWrapper = cmacWrapper; + interface udpConfig = udpIpArpEthRxTx.udpConfig; + interface udpIpMetaDataInTx = udpIpArpEthRxTx.udpIpMetaDataInTx; + interface dataStreamInTx = udpIpArpEthRxTx.dataStreamInTx; + interface udpIpMetaDataOutRx = udpIpArpEthRxTx.udpIpMetaDataOutRx; + interface dataStreamOutRx = udpIpArpEthRxTx.dataStreamOutRx; +endmodule + + + diff --git a/src/UdpIpArpEthRxTxWithPfc.bsv b/src/UdpIpArpEthRxTxWithPfc.bsv new file mode 100644 index 0000000..e6ef053 --- /dev/null +++ b/src/UdpIpArpEthRxTxWithPfc.bsv @@ -0,0 +1,173 @@ +import FIFOF :: *; +import GetPut :: *; +import Vector :: *; +import Clocks :: *; +import Connectable :: *; +import BRAMFIFO :: *; + +import Ports :: *; +import EthernetTypes :: *; +import UdpIpArpEthRxTx :: *; +import XilinxCmacRxTxWrapper :: *; +import PriorityFlowControl :: *; + +import SemiFifo :: *; + + +interface UdpIpArpEthRxTxWithPfc#( + numeric type bufPacketNum, + numeric type maxPacketFrameNum, + numeric type pfcThreshold +); + // Udp Config + interface Put#(UdpConfig) udpConfig; + + // Tx Channels + interface AxiStream512PipeOut axiStreamOutTx; + interface Vector#(VIRTUAL_CHANNEL_NUM, Put#(DataStream)) dataStreamInTxVec; + interface Vector#(VIRTUAL_CHANNEL_NUM, Put#(UdpIpMetaData)) udpIpMetaDataInTxVec; + + // Rx Channels + interface Put#(AxiStream512) axiStreamInRx; + interface Vector#(VIRTUAL_CHANNEL_NUM, Get#(DataStream)) dataStreamOutRxVec; + interface Vector#(VIRTUAL_CHANNEL_NUM, Get#(UdpIpMetaData)) udpIpMetaDataOutRxVec; + + // PFC Request + interface Put#(FlowControlReqVec) flowControlReqVecIn; + interface PipeOut#(FlowControlReqVec) flowControlReqVecOut; + +endinterface + +module mkUdpIpArpEthRxTxWithPfc(UdpIpArpEthRxTxWithPfc#(bufPacketNum, maxPacketFrameNum, pfcThreshold)) + provisos(Add#(pfcThreshold, a__, bufPacketNum)); + + FIFOF#(FlowControlReqVec) flowControlReqVecInBuf <- mkFIFOF; + Vector#(VIRTUAL_CHANNEL_NUM, FIFOF#(UdpIpMetaData)) udpIpMetaDataInTxBufVec <- replicateM(mkFIFOF); + Vector#(VIRTUAL_CHANNEL_NUM, FIFOF#(DataStream)) dataStreamInTxBufVec <- replicateM(mkFIFOF); + + let udpIpArpEthRxTx <- mkUdpIpArpEthRxTx; + + let pfcTx <- mkPriorityFlowControlTx( + convertFifoToPipeOut(flowControlReqVecInBuf), + map(convertFifoToPipeOut, dataStreamInTxBufVec), + map(convertFifoToPipeOut, udpIpMetaDataInTxBufVec) + ); + mkConnection(pfcTx.udpIpMetaDataOut, udpIpArpEthRxTx.udpIpMetaDataInTx); + mkConnection(pfcTx.dataStreamOut, udpIpArpEthRxTx.dataStreamInTx); + + PriorityFlowControlRx#(bufPacketNum, maxPacketFrameNum, pfcThreshold) pfcRx <- mkPriorityFlowControlRx( + udpIpArpEthRxTx.dataStreamOutRx, + udpIpArpEthRxTx.udpIpMetaDataOutRx + ); + + interface udpConfig = udpIpArpEthRxTx.udpConfig; + + interface axiStreamOutTx = udpIpArpEthRxTx.axiStreamOutTx; + interface dataStreamInTxVec = map(toPut, dataStreamInTxBufVec); + interface udpIpMetaDataInTxVec = map(toPut, udpIpMetaDataInTxBufVec); + + interface axiStreamInRx = udpIpArpEthRxTx.axiStreamInRx; + interface dataStreamOutRxVec = pfcRx.dataStreamOutVec; + interface udpIpMetaDataOutRxVec = pfcRx.udpIpMetaDataOutVec; + + interface flowControlReqVecIn = toPut(flowControlReqVecInBuf); + interface flowControlReqVecOut = pfcRx.flowControlReqVecOut; +endmodule + +interface UdpIpArpEthCmacRxTxWithPfc#( + numeric type bufPacketNum, + numeric type maxPacketFrameNum, + numeric type pfcThreshold +); + // Interface with CMAC IP + (* prefix = "" *) + interface XilinxCmacRxTxWrapper cmacRxTxWrapper; + + // Configuration Interface + interface Put#(UdpConfig) udpConfig; + + // Tx Channels + interface Vector#(VIRTUAL_CHANNEL_NUM, Put#(DataStream)) dataStreamInTxVec; + interface Vector#(VIRTUAL_CHANNEL_NUM, Put#(UdpIpMetaData)) udpIpMetaDataInTxVec; + + // Rx Channels + interface Vector#(VIRTUAL_CHANNEL_NUM, Get#(DataStream)) dataStreamOutRxVec; + interface Vector#(VIRTUAL_CHANNEL_NUM, Get#(UdpIpMetaData)) udpIpMetaDataOutRxVec; +endinterface + +module mkUdpIpArpEthCmacRxTxWithPfc#( + Bool isCmacTxWaitRxAligned, + Integer syncBramBufDepth +)( + Clock cmacRxTxClk, + Reset cmacRxReset, + Reset cmacTxReset, + UdpIpArpEthCmacRxTxWithPfc#(bufPacketNum, maxPacketFrameNum, pfcThreshold) ifc +) provisos(Add#(pfcThreshold, a__, bufPacketNum)); + + let isEnableFlowControl = True; + let currentClock <- exposeCurrentClock; + let currentReset <- exposeCurrentReset; + + SyncFIFOIfc#(AxiStream512) txAxiStreamSyncBuf <- mkSyncBRAMFIFO( + syncBramBufDepth, + currentClock, + currentReset, + cmacRxTxClk, + cmacTxReset + ); + + SyncFIFOIfc#(AxiStream512) rxAxiStreamSyncBuf <- mkSyncBRAMFIFO( + syncBramBufDepth, + cmacRxTxClk, + cmacRxReset, + currentClock, + currentReset + ); + + SyncFIFOIfc#(FlowControlReqVec) txFlowCtrlReqVecSyncBuf <- mkSyncBRAMFIFO( + syncBramBufDepth, + currentClock, + currentReset, + cmacRxTxClk, + cmacTxReset + ); + + SyncFIFOIfc#(FlowControlReqVec) rxFlowCtrlReqVecSyncBuf <- mkSyncBRAMFIFO( + syncBramBufDepth, + cmacRxTxClk, + cmacRxReset, + currentClock, + currentReset + ); + + let cmacWrapper <- mkXilinxCmacRxTxWrapper( + isEnableFlowControl, + isCmacTxWaitRxAligned, + convertSyncFifoToPipeOut(txAxiStreamSyncBuf), + convertSyncFifoToPipeIn(rxAxiStreamSyncBuf), + convertSyncFifoToPipeOut(txFlowCtrlReqVecSyncBuf), + convertSyncFifoToPipeIn(rxFlowCtrlReqVecSyncBuf), + cmacRxReset, + cmacTxReset, + clocked_by cmacRxTxClk + ); + + UdpIpArpEthRxTxWithPfc#(bufPacketNum, maxPacketFrameNum, pfcThreshold) udpIpArpEthRxTxWithPfc <- mkUdpIpArpEthRxTxWithPfc; + mkConnection(convertSyncFifoToPipeIn(txAxiStreamSyncBuf), udpIpArpEthRxTxWithPfc.axiStreamOutTx); + mkConnection(toGet(convertSyncFifoToPipeOut(rxAxiStreamSyncBuf)), udpIpArpEthRxTxWithPfc.axiStreamInRx); + mkConnection(convertSyncFifoToPipeIn(txFlowCtrlReqVecSyncBuf), udpIpArpEthRxTxWithPfc.flowControlReqVecOut); + mkConnection(toGet(convertSyncFifoToPipeOut(rxFlowCtrlReqVecSyncBuf)), udpIpArpEthRxTxWithPfc.flowControlReqVecIn); + + + interface cmacRxTxWrapper = cmacWrapper; + interface udpConfig = udpIpArpEthRxTxWithPfc.udpConfig; + interface udpIpMetaDataInTxVec = udpIpArpEthRxTxWithPfc.udpIpMetaDataInTxVec; + interface dataStreamInTxVec = udpIpArpEthRxTxWithPfc.dataStreamInTxVec; + interface udpIpMetaDataOutRxVec = udpIpArpEthRxTxWithPfc.udpIpMetaDataOutRxVec; + interface dataStreamOutRxVec = udpIpArpEthRxTxWithPfc.dataStreamOutRxVec; +endmodule + + + + diff --git a/src/UdpIpEthRx.bsv b/src/UdpIpEthRx.bsv index dcce69e..0530cfb 100644 --- a/src/UdpIpEthRx.bsv +++ b/src/UdpIpEthRx.bsv @@ -40,9 +40,9 @@ module mkUdpIpEthRx (UdpIpEthRx); ); UdpIpMetaDataAndDataStream udpIpMetaAndDataStream <- mkUdpIpMetaDataAndDataStream( - extractUdpIpMetaData, - macMetaAndUdpIpStream.udpIpStreamOut, - udpConfigVal + udpConfigVal, + macMetaAndUdpIpStream.udpIpStreamOut, + extractUdpIpMetaData ); interface Put udpConfig; diff --git a/src/UdpIpEthTx.bsv b/src/UdpIpEthTx.bsv index 7892343..8786d02 100644 --- a/src/UdpIpEthTx.bsv +++ b/src/UdpIpEthTx.bsv @@ -21,18 +21,18 @@ endinterface (* synthesize *) module mkUdpIpEthTx(UdpIpEthTx); - FIFOF#( DataStream) dataStreamInBuf <- mkFIFOF; + FIFOF#( DataStream) dataStreamInBuf <- mkFIFOF; FIFOF#(UdpIpMetaData) udpIpMetaDataInBuf <- mkFIFOF; - FIFOF#(MacMetaData) macMetaDataInBuf <- mkFIFOF; + FIFOF#( MacMetaData) macMetaDataInBuf <- mkFIFOF; Reg#(Maybe#(UdpConfig)) udpConfigReg <- mkReg(Invalid); let udpConfigVal = fromMaybe(?, udpConfigReg); DataStreamPipeOut ipUdpStream <- mkUdpIpStream( - genUdpIpHeader, - convertFifoToPipeOut(udpIpMetaDataInBuf), + udpConfigVal, convertFifoToPipeOut(dataStreamInBuf), - udpConfigVal + convertFifoToPipeOut(udpIpMetaDataInBuf), + genUdpIpHeader ); DataStreamPipeOut macStream <- mkMacStream( diff --git a/src/UdpIpLayer.bsv b/src/UdpIpLayer.bsv index e3efb9a..a36f2b7 100644 --- a/src/UdpIpLayer.bsv +++ b/src/UdpIpLayer.bsv @@ -9,6 +9,7 @@ import Ports :: *; import SemiFifo :: *; import EthernetTypes :: *; + module mkIpHdrCheckSumServer(Server#(IpHeader, IpCheckSum)) provisos( NumAlias#(TDiv#(IP_HDR_WORD_WIDTH, 4), firstStageOutNum), @@ -53,35 +54,35 @@ module mkIpHdrCheckSumServer(Server#(IpHeader, IpCheckSum)) endinterface endmodule -function UdpIpHeader genUdpIpHeader(UdpIpMetaData meta, UdpConfig udpConfig, IpID ipId); - - UdpLength udpLen = meta.dataLen + fromInteger(valueOf(UDP_HDR_BYTE_WIDTH)); +function UdpIpHeader genUdpIpHeader(UdpIpMetaData metaData, UdpConfig udpConfig, IpID ipId); + // Calculate packet length + UdpLength udpLen = metaData.dataLen + fromInteger(valueOf(UDP_HDR_BYTE_WIDTH)); IpTL ipLen = udpLen + fromInteger(valueOf(IP_HDR_BYTE_WIDTH)); // generate ipHeader IpHeader ipHeader = IpHeader { - ipVersion: fromInteger(valueOf(IP_VERSION_VAL)), - ipIHL: fromInteger(valueOf(IP_IHL_VAL)), - ipDS: fromInteger(valueOf(IP_DS_VAL)), - ipTL: ipLen, - ipID: ipId, - ipFlag: fromInteger(valueOf(IP_FLAGS_VAL)), - ipOffset: fromInteger(valueOf(IP_OFFSET_VAL)), - ipTTL: fromInteger(valueOf(IP_TTL_VAL)), - ipProtocol:fromInteger(valueOf(IP_PROTOCOL_VAL)), - ipChecksum:0, - srcIpAddr :udpConfig.ipAddr, - dstIpAddr :meta.ipAddr + ipVersion : fromInteger(valueOf(IP_VERSION_VAL)), + ipIHL : fromInteger(valueOf(IP_IHL_VAL)), + ipDscp : metaData.ipDscp, + ipEcn : metaData.ipEcn, + ipTL : ipLen, + ipID : ipId, + ipFlag : fromInteger(valueOf(IP_FLAGS_VAL)), + ipOffset : fromInteger(valueOf(IP_OFFSET_VAL)), + ipTTL : fromInteger(valueOf(IP_TTL_VAL)), + ipProtocol: fromInteger(valueOf(IP_PROTOCOL_VAL)), + ipChecksum: 0, + srcIpAddr : udpConfig.ipAddr, + dstIpAddr : metaData.ipAddr }; - // generate udpHeader - UdpHeader udpHeader = UdpHeader{ - srcPort: meta.srcPort, - dstPort: meta.dstPort, - length: udpLen, - checksum:0 + UdpHeader udpHeader = UdpHeader { + srcPort : metaData.srcPort, + dstPort : metaData.dstPort, + length : udpLen, + checksum: 0 }; - - UdpIpHeader udpIpHeader = UdpIpHeader{ + // generate udpIpHeader + UdpIpHeader udpIpHeader = UdpIpHeader { ipHeader: ipHeader, udpHeader: udpHeader }; @@ -89,11 +90,12 @@ function UdpIpHeader genUdpIpHeader(UdpIpMetaData meta, UdpConfig udpConfig, IpI endfunction module mkUdpIpStream#( - function UdpIpHeader genHeader(UdpIpMetaData meta, UdpConfig udpConfig, IpID ipId), - UdpIpMetaDataPipeOut udpIpMetaDataIn, + UdpConfig udpConfig, DataStreamPipeOut dataStreamIn, - UdpConfig udpConfig + UdpIpMetaDataPipeOut udpIpMetaDataIn, + function UdpIpHeader genHeader(UdpIpMetaData meta, UdpConfig udpConfig, IpID ipId) )(DataStreamPipeOut); + IpID defaultIpId = 1; Reg#(IpID) ipIdCounter <- mkReg(0); FIFOF#(UdpIpHeader) interUdpIpHeaderBuf <- mkFIFOF; @@ -103,7 +105,7 @@ module mkUdpIpStream#( rule doCheckSumReq; let metaData = udpIpMetaDataIn.first; udpIpMetaDataIn.deq; - UdpIpHeader udpIpHeader = genHeader(metaData, udpConfig, 1); + UdpIpHeader udpIpHeader = genHeader(metaData, udpConfig, defaultIpId); interUdpIpHeaderBuf.enq(udpIpHeader); checkSumServer.request.put(udpIpHeader.ipHeader); endrule @@ -127,18 +129,20 @@ endmodule function UdpIpMetaData extractUdpIpMetaData(UdpIpHeader hdr); UdpLength dataLen = hdr.udpHeader.length - fromInteger(valueOf(UDP_HDR_BYTE_WIDTH)); - UdpIpMetaData meta = UdpIpMetaData { + UdpIpMetaData metaData = UdpIpMetaData { dataLen: dataLen, ipAddr : hdr.ipHeader.srcIpAddr, + ipDscp : hdr.ipHeader.ipDscp, + ipEcn : hdr.ipHeader.ipEcn, dstPort: hdr.udpHeader.dstPort, srcPort: hdr.udpHeader.srcPort }; - return meta; + return metaData; endfunction -function Bool checkUdpIp(UdpIpHeader hdr, UdpConfig udpConfig); - // To be modified!!! - Vector#(IP_HDR_WORD_WIDTH, Word) ipHdrVec = unpack(pack(hdr.ipHeader)); +function Bool checkUdpIpHeader(UdpIpHeader hdr, UdpConfig udpConfig); + // TODO: To be modified!!! + //Vector#(IP_HDR_WORD_WIDTH, Word) ipHdrVec = unpack(pack(hdr.ipHeader)); // let ipChecksum = getCheckSum(ipHdrVec); // Skip checksum of udp header @@ -157,9 +161,9 @@ interface UdpIpMetaDataAndDataStream; endinterface module mkUdpIpMetaDataAndDataStream#( - function UdpIpMetaData extractMetaData(UdpIpHeader hdr), + UdpConfig udpConfig, DataStreamPipeOut udpIpStreamIn, - UdpConfig udpConfig + function UdpIpMetaData extractMetaData(UdpIpHeader hdr) )(UdpIpMetaDataAndDataStream); FIFOF#(DataStream) interDataStreamBuf <- mkFIFOF; FIFOF#(DataStream) dataStreamOutBuf <- mkFIFOF; @@ -175,7 +179,7 @@ module mkUdpIpMetaDataAndDataStream#( rule doCheckSumReq; let udpIpHeader = udpIpExtractor.extractDataOut.first; udpIpExtractor.extractDataOut.deq; - let checkRes = checkUdpIp(udpIpHeader, udpConfig); + let checkRes = checkUdpIpHeader(udpIpHeader, udpConfig); checkSumServer.request.put(udpIpHeader.ipHeader); interCheckRes <= checkRes; let metaData = extractMetaData(udpIpHeader); @@ -215,3 +219,4 @@ module mkUdpIpMetaDataAndDataStream#( interface PipeOut udpIpMetaDataOut = convertFifoToPipeOut(udpIpMetaDataOutBuf); endmodule + diff --git a/src/UdpIpLayerForRdma.bsv b/src/UdpIpLayerForRdma.bsv index 74f64cd..0612637 100644 --- a/src/UdpIpLayerForRdma.bsv +++ b/src/UdpIpLayerForRdma.bsv @@ -9,8 +9,8 @@ import SemiFifo :: *; import CrcDefines :: *; import AxiStreamTypes :: *; -function UdpIpHeader genUdpIpHeaderForRoCE(UdpIpMetaData meta, UdpConfig udpConfig, IpID ipId); - let udpIpHeader = genUdpIpHeader(meta, udpConfig, ipId); +function UdpIpHeader genUdpIpHeaderForRoCE(UdpIpMetaData metaData, UdpConfig udpConfig, IpID ipId); + let udpIpHeader = genUdpIpHeader(metaData, udpConfig, ipId); let crc32ByteWidth = valueOf(CRC32_BYTE_WIDTH); let udpLen = udpIpHeader.udpHeader.length; @@ -21,11 +21,11 @@ function UdpIpHeader genUdpIpHeaderForRoCE(UdpIpMetaData meta, UdpConfig udpConf return udpIpHeader; endfunction -function UdpIpHeader genUdpIpHeaderForICrc(UdpIpMetaData meta, UdpConfig udpConfig, IpID ipId); +function UdpIpHeader genUdpIpHeaderForICrc(UdpIpMetaData metaData, UdpConfig udpConfig, IpID ipId); + let udpIpHeader = genUdpIpHeaderForRoCE(metaData, udpConfig, ipId); - let udpIpHeader = genUdpIpHeaderForRoCE(meta, udpConfig, ipId); - - udpIpHeader.ipHeader.ipDS = setAllBits; + udpIpHeader.ipHeader.ipDscp = setAllBits; + udpIpHeader.ipHeader.ipEcn = setAllBits; udpIpHeader.ipHeader.ipTTL = setAllBits; udpIpHeader.ipHeader.ipChecksum = setAllBits; @@ -35,7 +35,7 @@ function UdpIpHeader genUdpIpHeaderForICrc(UdpIpMetaData meta, UdpConfig udpConf endfunction -module mkUdpIpStreamForICrcGen#( +module mkUdpIpStreamForGenICrc#( UdpIpMetaDataPipeOut udpIpMetaDataIn, DataStreamPipeOut dataStreamIn, UdpConfig udpConfig @@ -122,13 +122,13 @@ module mkUdpIpStreamForRdma#( endrule DataStreamPipeOut udpIpStream <- mkUdpIpStream( - genUdpIpHeaderForRoCE, - convertFifoToPipeOut(udpIpMetaDataBuf), + udpConfig, convertFifoToPipeOut(dataStreamBuf), - udpConfig + convertFifoToPipeOut(udpIpMetaDataBuf), + genUdpIpHeaderForRoCE ); - DataStreamPipeOut udpIpStreamForICrc <- mkUdpIpStreamForICrcGen( + DataStreamPipeOut udpIpStreamForICrc <- mkUdpIpStreamForGenICrc( convertFifoToPipeOut(udpIpMetaDataCrcBuf), convertFifoToPipeOut(dataStreamCrcBuf), udpConfig @@ -151,7 +151,6 @@ module mkUdpIpStreamForRdma#( endmodule - function UdpIpMetaData extractUdpIpMetaDataForRoCE(UdpIpHeader hdr); let meta = extractUdpIpMetaData(hdr); meta.dataLen = meta.dataLen - fromInteger(valueOf(CRC32_BYTE_WIDTH)); @@ -189,7 +188,8 @@ module mkUdpIpStreamForICrcCheck#( bthUdpIpHdr.bth.becn = setAllBits; bthUdpIpHdr.bth.resv6 = setAllBits; bthUdpIpHdr.udpHeader.checksum = setAllBits; - bthUdpIpHdr.ipHeader.ipDS = setAllBits; + bthUdpIpHdr.ipHeader.ipDscp = setAllBits; + bthUdpIpHdr.ipHeader.ipEcn = setAllBits; bthUdpIpHdr.ipHeader.ipTTL = setAllBits; bthUdpIpHdr.ipHeader.ipChecksum = setAllBits; tData = {pack(bthUdpIpHdr), truncate(tData)}; @@ -306,9 +306,9 @@ module mkUdpIpMetaDataAndDataStreamForRdma#( ); UdpIpMetaDataAndDataStream udpIpMetaAndDataStream <- mkUdpIpMetaDataAndDataStream( - extractUdpIpMetaDataForRoCE, + udpConfig, convertFifoToPipeOut(udpIpStreamBuf), - udpConfig + extractUdpIpMetaDataForRoCE ); FIFOF#(UdpLength) dataStreamLengthBuf <- mkFIFOF; @@ -379,5 +379,4 @@ module mkUdpIpMetaDataAndDataStreamForRdma#( interface PipeOut udpIpMetaDataOut = convertFifoToPipeOut(udpIpMetaDataOutBuf); interface PipeOut dataStreamOut = convertFifoToPipeOut(dataStreamOutBuf); - endmodule diff --git a/src/XilinxCmacRxTxWrapper.bsv b/src/XilinxCmacRxTxWrapper.bsv new file mode 100644 index 0000000..2e67432 --- /dev/null +++ b/src/XilinxCmacRxTxWrapper.bsv @@ -0,0 +1,616 @@ +import Cntrs :: *; +import FIFOF :: *; +import GetPut :: *; +import Vector :: *; +import BRAMFIFO :: *; +import Connectable :: *; + +import Ports :: *; +import Utils :: *; +import EthernetTypes :: *; +import PriorityFlowControl :: *; + +import SemiFifo :: *; +import AxiStreamTypes :: *; + +typedef 9 CMAC_TX_INIT_COUNT_WIDTH; +typedef 8 CMAC_TX_INIT_DONE_FLAG_INDEX; + +typedef 6 CMAC_TX_PAUSE_REQ_COUNT_WIDTH; + +// +typedef 2500 MAX_PKT_BYTE_NUM; +typedef TDiv#(MAX_PKT_BYTE_NUM, AXIS_TKEEP_WIDTH) MAX_PKT_FRAME_NUM; +typedef TLog#(MAX_PKT_FRAME_NUM) FRAME_INDEX_WIDTH; +typedef MAX_PKT_FRAME_NUM CMAC_INTER_BUF_DEPTH; +typedef TLog#(CMAC_INTER_BUF_DEPTH) PKT_INDEX_WIDTH; + +typedef 9 CMAC_PAUSE_ENABLE_WIDTH; +typedef 9 CMAC_PAUSE_REQ_WIDTH; +typedef 9 CMAC_PAUSE_ACK_WIDTH; + + +(* always_ready, always_enabled *) +interface XilinxCmacTxWrapper; + + // AxiStream Interface + (* prefix = "tx_axis" *) + interface RawAxiStreamMaster#(AXIS_TKEEP_WIDTH, AXIS_TUSER_WIDTH) txRawAxiStreamOut; + + // CMAC Control Output + (* result = "tx_ctl_enable" *) + method Bool ctlTxEnable; + (* result = "tx_ctl_test_pattern" *) + method Bool ctlTxTestPattern; + (* result = "tx_ctl_send_idle" *) + method Bool ctlTxSendIdle; + (* result = "tx_ctl_send_lfi" *) + method Bool ctlTxSendLocalFaultIndication; + (* result = "tx_ctl_send_rfi" *) + method Bool ctlTxSendRemoteFaultIndication; + (* result = "tx_ctl_reset" *) + method Bool ctlTxReset; + + // PFC Control Output + (* result = "tx_ctl_pause_enable" *) + method Bit#(CMAC_PAUSE_ENABLE_WIDTH) ctlTxPauseEnable; + (* result = "tx_ctl_pause_req" *) + method Bit#(CMAC_PAUSE_REQ_WIDTH) ctlTxPauseReq; + (* result = "tx_ctl_pause_quanta0" *) + method PfcPauseQuanta ctlTxPauseQuanta0; + (* result = "tx_ctl_pause_quanta1" *) + method PfcPauseQuanta ctlTxPauseQuanta1; + (* result = "tx_ctl_pause_quanta2" *) + method PfcPauseQuanta ctlTxPauseQuanta2; + (* result = "tx_ctl_pause_quanta3" *) + method PfcPauseQuanta ctlTxPauseQuanta3; + (* result = "tx_ctl_pause_quanta4" *) + method PfcPauseQuanta ctlTxPauseQuanta4; + (* result = "tx_ctl_pause_quanta5" *) + method PfcPauseQuanta ctlTxPauseQuanta5; + (* result = "tx_ctl_pause_quanta6" *) + method PfcPauseQuanta ctlTxPauseQuanta6; + (* result = "tx_ctl_pause_quanta7" *) + method PfcPauseQuanta ctlTxPauseQuanta7; + (* result = "tx_ctl_pause_quanta8" *) + method PfcPauseQuanta ctlTxPauseQuanta8; + + // CMAC Status Input + (* prefix = "" *) method Action cmacTxStatus( + (* port = "tx_stat_ovfout" *) Bool txOverFlow, + (* port = "tx_stat_unfout" *) Bool txUnderFlow, + (* port = "tx_stat_rx_aligned" *) Bool rxAligned + ); + +endinterface + +typedef enum { + TX_STATE_IDLE, + TX_STATE_GT_LOCKED, + TX_STATE_WAIT_RX_ALIGNED, + TX_STATE_PKT_TRANSFER_INIT, + TX_STATE_AXIS_ENABLE, + TX_STATE_HALT +} CmacTxWrapperState deriving(Bits, Eq, FShow); + +module mkXilinxCmacTxWrapper#( + Bool isEnableFlowControl, + Bool isWaitRxAligned, + AxiStream512PipeOut txAxiStreamIn, + PipeOut#(FlowControlReqVec) txFlowCtrlReqVec +)(XilinxCmacTxWrapper); + Reg#(Bool) ctlTxEnableReg <- mkReg(False); + Reg#(Bool) ctlTxTestPatternReg <- mkReg(False); + Reg#(Bool) ctlTxSendIdleReg <- mkReg(False); + Reg#(Bool) ctlTxSendLocalFaultIndicationReg <- mkReg(False); + Reg#(Bool) ctlTxSendRemoteFaultIndicationReg <- mkReg(False); + + Reg#(Bit#(VIRTUAL_CHANNEL_NUM)) ctlTxPauseEnableReg <- mkReg(0); + Reg#(Bit#(VIRTUAL_CHANNEL_NUM)) ctlTxPauseReqReg <- mkReg(0); + Vector#(VIRTUAL_CHANNEL_NUM, Reg#(PfcPauseQuanta)) ctlTxPauseQuantaRegVec <- replicateM(mkReg(0)); + + Reg#(Bool) txOverFlowReg <- mkReg(False); + Reg#(Bool) txUnderFlowReg <- mkReg(False); + Reg#(Bool) rxAlignedReg <- mkReg(False); + + FIFOF#(AxiStream512) txAxiStreamOutBuf <- mkFIFOF; + FIFOF#(AxiStream512) txAxiStreamInterBuf <- mkSizedBRAMFIFOF(valueOf(CMAC_INTER_BUF_DEPTH)); + FIFOF#(Bool) packetReadyInfoBuf <- mkSizedFIFOF(valueOf(CMAC_INTER_BUF_DEPTH)); + + Reg#(CmacTxWrapperState) txStateReg <- mkReg(TX_STATE_IDLE); + Reg#(Bit#(CMAC_TX_INIT_COUNT_WIDTH)) initCounter <- mkReg(0); + Reg#(Bool) isTxPauseReqBusy <- mkReg(False); + Reg#(Bit#(CMAC_TX_PAUSE_REQ_COUNT_WIDTH)) txPauseReqCounter <- mkReg(0); + + + rule stateIdle if (txStateReg == TX_STATE_IDLE); + ctlTxEnableReg <= False; + ctlTxTestPatternReg <= False; + ctlTxSendIdleReg <= False; + ctlTxSendLocalFaultIndicationReg <= False; + ctlTxSendRemoteFaultIndicationReg <= False; + + if (txAxiStreamIn.notEmpty) begin + txStateReg <= TX_STATE_GT_LOCKED; + end + endrule + + rule stateGtLocked if (txStateReg == TX_STATE_GT_LOCKED); + ctlTxEnableReg <= False; + ctlTxSendIdleReg <= False; + ctlTxSendLocalFaultIndicationReg <= False; + ctlTxSendRemoteFaultIndicationReg <= True; + txStateReg <= TX_STATE_WAIT_RX_ALIGNED; + $display("CmacTxWrapper: Wait CMAC Rx Algined Ready"); + endrule + + rule stateWaitRxAligned if (txStateReg == TX_STATE_WAIT_RX_ALIGNED); + if (rxAlignedReg) begin + txStateReg <= TX_STATE_PKT_TRANSFER_INIT; + $display("CmacTxWrapper: Init CMAC Tx Datapath"); + end + endrule + + rule statePktTransferInit if (txStateReg == TX_STATE_PKT_TRANSFER_INIT); + ctlTxEnableReg <= True; + if (isEnableFlowControl) begin + ctlTxPauseEnableReg <= setAllBits; + end + else begin + ctlTxPauseEnableReg <= 0; + end + ctlTxSendIdleReg <= False; + ctlTxSendLocalFaultIndicationReg <= False; + ctlTxSendRemoteFaultIndicationReg <= False; + + Bool initDone = unpack(initCounter[valueOf(CMAC_TX_INIT_DONE_FLAG_INDEX)]); + if (!initDone) begin + initCounter <= initCounter + 1; + end + + if (!rxAlignedReg) begin + txStateReg <= TX_STATE_IDLE; + end + else if (initDone && !txOverFlowReg && !txUnderFlowReg) begin + $display("CmacTxWrapper: Start Transmitting Ethernet Packet"); + txStateReg <= TX_STATE_AXIS_ENABLE; + initCounter <= 0; + end + endrule + + rule stateAxisEnable if (txStateReg == TX_STATE_AXIS_ENABLE); + let axiStream = txAxiStreamIn.first; + txAxiStreamIn.deq; + txAxiStreamInterBuf.enq(axiStream); + if (axiStream.tLast) begin + packetReadyInfoBuf.enq(axiStream.tLast); + end + + $display("CmacTxWrapper: CMAC Tx transmit ", fshow(axiStream)); + if (!rxAlignedReg) begin + txStateReg <= TX_STATE_IDLE; + $display("CmacTxWrapper: CMAC Tx IDLE"); + end + else if (txOverFlowReg || txUnderFlowReg) begin + $display("CmacTxWrapper: CMAC TX Path Halted !!"); + txStateReg <= TX_STATE_HALT; + end + endrule + + rule stateHalt if (txStateReg == TX_STATE_HALT); + if (!rxAlignedReg) begin + txStateReg <= TX_STATE_IDLE; + + end + else if ((!txOverFlowReg) && (!txUnderFlowReg)) begin + txStateReg <= TX_STATE_AXIS_ENABLE; + $display("CmacTxWrapper: Restart Transmitting Ethernet Packet"); + end + + endrule + + rule genCtlTxPauseReq if (txStateReg == TX_STATE_AXIS_ENABLE); + if (isTxPauseReqBusy) begin + txPauseReqCounter <= txPauseReqCounter + 1; + if (unpack(msb(txPauseReqCounter))) begin + isTxPauseReqBusy <= False; + ctlTxPauseReqReg <= 0; + end + end + else begin + let flowControlReqVec = txFlowCtrlReqVec.first; + txFlowCtrlReqVec.deq; + Vector#(VIRTUAL_CHANNEL_NUM, Bool) txPauseReqVec = replicate(False); + for (Integer i = 0; i < valueOf(VIRTUAL_CHANNEL_NUM); i = i + 1) begin + if (flowControlReqVec[i] matches tagged Valid .ctrlReq) begin + txPauseReqVec[i] = True; + if (ctrlReq == FLOW_CTRL_PASS) begin + ctlTxPauseQuantaRegVec[i] <= 0; + end + else begin + ctlTxPauseQuantaRegVec[i] <= setAllBits; + end + end + end + ctlTxPauseReqReg <= pack(txPauseReqVec); + isTxPauseReqBusy <= True; + end + endrule + + rule genFullPacketAxiStreamOut; + let packetReady = packetReadyInfoBuf.first; + let axiStream = txAxiStreamInterBuf.first; + txAxiStreamInterBuf.deq; + txAxiStreamOutBuf.enq(axiStream); + if (axiStream.tLast == packetReady) begin + packetReadyInfoBuf.deq; + end + endrule + + let rawAxiStreamBus <- mkPipeOutToRawAxiStreamMaster(convertFifoToPipeOut(txAxiStreamOutBuf)); + interface txRawAxiStreamOut = rawAxiStreamBus; + + method Bool ctlTxReset = False; + method Bool ctlTxEnable = ctlTxEnableReg; + method Bool ctlTxTestPattern = ctlTxTestPatternReg; + method Bool ctlTxSendIdle = ctlTxSendIdleReg; + method Bool ctlTxSendLocalFaultIndication = ctlTxSendLocalFaultIndicationReg; + method Bool ctlTxSendRemoteFaultIndication = ctlTxSendRemoteFaultIndicationReg; + + // PFC Control Output + method Bit#(CMAC_PAUSE_ENABLE_WIDTH) ctlTxPauseEnable = zeroExtend(ctlTxPauseEnableReg); + method Bit#(CMAC_PAUSE_REQ_WIDTH) ctlTxPauseReq = zeroExtend(ctlTxPauseReqReg); + method PfcPauseQuanta ctlTxPauseQuanta0 = ctlTxPauseQuantaRegVec[0]; + method PfcPauseQuanta ctlTxPauseQuanta1 = ctlTxPauseQuantaRegVec[1]; + method PfcPauseQuanta ctlTxPauseQuanta2 = ctlTxPauseQuantaRegVec[2]; + method PfcPauseQuanta ctlTxPauseQuanta3 = ctlTxPauseQuantaRegVec[3]; + method PfcPauseQuanta ctlTxPauseQuanta4 = ctlTxPauseQuantaRegVec[4]; + method PfcPauseQuanta ctlTxPauseQuanta5 = ctlTxPauseQuantaRegVec[5]; + method PfcPauseQuanta ctlTxPauseQuanta6 = ctlTxPauseQuantaRegVec[6]; + method PfcPauseQuanta ctlTxPauseQuanta7 = ctlTxPauseQuantaRegVec[7]; + method PfcPauseQuanta ctlTxPauseQuanta8 = 0; + + method Action cmacTxStatus(Bool txOverFlow, Bool txUnderFlow, Bool rxAligned); + txOverFlowReg <= txOverFlow; + txUnderFlowReg <= txUnderFlow; + rxAlignedReg <= !isWaitRxAligned || rxAligned; + endmethod +endmodule + +(* always_ready, always_enabled *) +interface XilinxCmacRxWrapper; + // Raw AxiStream Interface + (* prefix = "rx_axis" *) + interface RawAxiStreamSlave#(AXIS_TKEEP_WIDTH, AXIS_TUSER_WIDTH) rxRawAxiStreamIn; + + // CMAC Control Output + (* result = "rx_ctl_enable" *) + method Bool ctlRxEnable; + (* result = "rx_ctl_force_resync" *) + method Bool ctlRxForceResync; + (* result = "rx_ctl_test_pattern" *) + method Bool ctlRxTestPattern; + (* result = "rx_ctl_reset" *) + method Bool ctlRxReset; + + // Pause Control Output + (* result = "rx_ctl_pause_enable" *) + method Bit#(CMAC_PAUSE_ENABLE_WIDTH) ctlRxPauseEnable; + (* result = "rx_ctl_pause_ack" *) + method Bit#(CMAC_PAUSE_ACK_WIDTH) ctlRxPauseAck; + + (* result = "rx_ctl_enable_gcp" *) + method Bool ctlRxCheckEnableGcp; + (* result = "rx_ctl_check_mcast_gcp" *) + method Bool ctlRxCheckMcastGcp; + (* result = "rx_ctl_check_ucast_gcp" *) + method Bool ctlRxCheckUcastGcp; + (* result = "rx_ctl_check_sa_gcp" *) + method Bool ctlRxCheckSaGcp; + (* result = "rx_ctl_check_etype_gcp" *) + method Bool ctlRxCheckEtypeGcp; + (* result = "rx_ctl_check_opcode_gcp" *) + method Bool ctlRxCheckOpcodeGcp; + + (* result = "rx_ctl_enable_pcp" *) + method Bool ctlRxCheckEnablePcp; + (* result = "rx_ctl_check_mcast_pcp" *) + method Bool ctlRxCheckMcastPcp; + (* result = "rx_ctl_check_ucast_pcp" *) + method Bool ctlRxCheckUcastPcp; + (* result = "rx_ctl_check_sa_pcp" *) + method Bool ctlRxCheckSaPcp; + (* result = "rx_ctl_check_etype_pcp" *) + method Bool ctlRxCheckEtypePcp; + (* result = "rx_ctl_check_opcode_pcp" *) + method Bool ctlRxCheckOpcodePcp; + + (* result = "rx_ctl_enable_gpp" *) + method Bool ctlRxCheckEnableGpp; + (* result = "rx_ctl_check_mcast_gpp" *) + method Bool ctlRxCheckMcastGpp; + (* result = "rx_ctl_check_ucast_gpp" *) + method Bool ctlRxCheckUcastGpp; + (* result = "rx_ctl_check_sa_gpp" *) + method Bool ctlRxCheckSaGpp; + (* result = "rx_ctl_check_etype_gpp" *) + method Bool ctlRxCheckEtypeGpp; + (* result = "rx_ctl_check_opcode_gpp" *) + method Bool ctlRxCheckOpcodeGpp; + + (* result = "rx_ctl_enable_ppp" *) + method Bool ctlRxCheckEnablePpp; + (* result = "rx_ctl_check_mcast_ppp" *) + method Bool ctlRxCheckMcastPpp; + (* result = "rx_ctl_check_ucast_ppp" *) + method Bool ctlRxCheckUcastPpp; + (* result = "rx_ctl_check_sa_ppp" *) + method Bool ctlRxCheckSaPpp; + (* result = "rx_ctl_check_etype_ppp" *) + method Bool ctlRxCheckEtypePpp; + (* result = "rx_ctl_check_opcode_ppp" *) + method Bool ctlRxCheckOpcodePpp; + + // CMAC Status Input + (* prefix = "" *) method Action cmacRxStatus( + (* port = "rx_stat_aligned" *) Bool rxAligned, + (* port = "rx_stat_pause_req" *) Bit#(CMAC_PAUSE_REQ_WIDTH) rxPauseReq + ); +endinterface + +typedef enum { + RX_STATE_IDLE, + RX_STATE_GT_LOCKED, + RX_STATE_WAIT_RX_ALIGNED, + RX_STATE_AXIS_ENABLE +} CmacRxWrapperState deriving(Bits, Eq, FShow); + +typedef struct { + Bit#(PKT_INDEX_WIDTH) pktIdx; + Bit#(FRAME_INDEX_WIDTH) frameIdx; + AxiStream512 axiStream; +} AxiStream512WithTag deriving(Bits, FShow); + +typedef struct { + Bit#(PKT_INDEX_WIDTH) pktIdx; + Bit#(FRAME_INDEX_WIDTH) frameNum; +} FaultPktInfo deriving(Bits, Eq, FShow); + +module mkXilinxCmacRxWrapper#( + Bool isEnableFlowControl, + AxiStream512PipeIn rxAxiStreamOut, + PipeIn#(FlowControlReqVec) rxFlowCtrlReqVec +)(XilinxCmacRxWrapper); + Reg#(Bool) ctlRxEnableReg <- mkReg(False); + Reg#(Bool) ctlRxForceResyncReg <- mkReg(False); + Reg#(Bool) ctlRxTestPatternReg <- mkReg(False); + Reg#(Bit#(VIRTUAL_CHANNEL_NUM)) ctlRxPauseEnableReg <- mkReg(0); + Reg#(Bit#(VIRTUAL_CHANNEL_NUM)) ctlRxPauseAckReg <- mkReg(0); + + Reg#(Bool) rxAlignedReg <- mkReg(False); + Reg#(Bit#(VIRTUAL_CHANNEL_NUM)) rxPauseReqReg <- mkRegU; + + Wire#(Maybe#(AxiStream512)) rxAxiStreamInW <- mkBypassWire; + + Reg#(Bool) isThrowFaultFrame <- mkReg(False); + Reg#(Bit#(PKT_INDEX_WIDTH)) bufInputPktCount <- mkReg(0); + Reg#(Bit#(FRAME_INDEX_WIDTH)) bufInputFrameCount <- mkReg(0); + FIFOF#(FaultPktInfo) faultPktInfoBuf <- mkSizedFIFOF(valueOf(CMAC_INTER_BUF_DEPTH)); + FIFOF#(AxiStream512WithTag) rxAxiStreamInterBuf <- mkSizedBRAMFIFOF(valueOf(CMAC_INTER_BUF_DEPTH)); + + + Reg#(CmacRxWrapperState) rxStateReg <- mkReg(RX_STATE_IDLE); + + rule stateIdle if (rxStateReg == RX_STATE_IDLE); + ctlRxEnableReg <= False; + ctlRxForceResyncReg <= False; + ctlRxTestPatternReg <= False; + + rxStateReg <= RX_STATE_GT_LOCKED; + endrule + + rule stateGtLocked if (rxStateReg == RX_STATE_GT_LOCKED); + ctlRxEnableReg <= True; + ctlRxForceResyncReg <= False; + ctlRxTestPatternReg <= False; + if (isEnableFlowControl) begin + ctlRxPauseEnableReg <= setAllBits; + end + else begin + ctlRxPauseEnableReg <= 0; + end + rxStateReg <= RX_STATE_WAIT_RX_ALIGNED; + $display("CmacRxWrapper: Wait CMAC Rx Aligned"); + endrule + + rule stateWaitRxAligned if (rxStateReg == RX_STATE_WAIT_RX_ALIGNED); + if (rxAlignedReg) begin + rxStateReg <= RX_STATE_AXIS_ENABLE; + $display("CmacRxWrapper: Start Receiving Ethernet Packet"); + end + endrule + + rule stateAxisEnable if (rxStateReg == RX_STATE_AXIS_ENABLE); + if (!rxAlignedReg) begin + rxStateReg <= RX_STATE_IDLE; + end + endrule + + // Drop whole packet when intermediate buffer is full + rule enqRxAxiStreamInterBuf if (rxStateReg == RX_STATE_AXIS_ENABLE && isValid(rxAxiStreamInW)); + let rxAxiStream = fromMaybe(?, rxAxiStreamInW); + if (rxAxiStream.tLast) begin + bufInputPktCount <= bufInputPktCount + 1; + bufInputFrameCount <= 0; + end + else begin + bufInputFrameCount <= bufInputFrameCount + 1; + end + + if (isThrowFaultFrame) begin + isThrowFaultFrame <= !rxAxiStream.tLast; + end + else begin + if (rxAxiStreamInterBuf.notFull) begin + rxAxiStreamInterBuf.enq( + AxiStream512WithTag { + pktIdx: bufInputPktCount, + frameIdx: bufInputFrameCount, + axiStream: rxAxiStream + } + ); + end + else begin + if (bufInputFrameCount != 0 ) begin + faultPktInfoBuf.enq( + FaultPktInfo { + pktIdx: bufInputPktCount, + frameNum: bufInputFrameCount + } + ); + end + isThrowFaultFrame <= True; + end + end + endrule + + rule deqRxAxiStreamInterBuf; + let rxAxiStreamWithTag = rxAxiStreamInterBuf.first; + rxAxiStreamInterBuf.deq; + + let pktIdx = rxAxiStreamWithTag.pktIdx; + let frameIdx = rxAxiStreamWithTag.frameIdx; + let axiStream = rxAxiStreamWithTag.axiStream; + + if (faultPktInfoBuf.notEmpty) begin + let faultPktInfo = faultPktInfoBuf.first; + if (pktIdx == faultPktInfo.pktIdx) begin + if (frameIdx == (faultPktInfo.frameNum - 1)) begin + faultPktInfoBuf.deq; + end + end + else begin + rxAxiStreamOut.enq(axiStream); + end + end + else begin + rxAxiStreamOut.enq(axiStream); + end + endrule + + rule genFlowControlReq; + FlowControlReqVec flowCtrlReqVec = replicate(tagged Invalid); + Bit#(VIRTUAL_CHANNEL_NUM) nextCtlRxPauseAck = ctlRxPauseAckReg; + for (Integer i = 0; i < valueOf(VIRTUAL_CHANNEL_NUM); i = i + 1) begin + if (ctlRxPauseAckReg[i] != rxPauseReqReg[i]) begin + nextCtlRxPauseAck[i] = rxPauseReqReg[i]; + if (rxPauseReqReg[i] == 0) begin + flowCtrlReqVec[i] = tagged Valid FLOW_CTRL_PASS; + end + else begin + flowCtrlReqVec[i] = tagged Valid FLOW_CTRL_STOP; + end + end + end + ctlRxPauseAckReg <= nextCtlRxPauseAck; + rxFlowCtrlReqVec.enq(flowCtrlReqVec); + endrule + + method Bool ctlRxEnable = ctlRxEnableReg; + method Bool ctlRxForceResync = ctlRxForceResyncReg; + method Bool ctlRxTestPattern = ctlRxTestPatternReg; + method Bool ctlRxReset = False; + + method Bit#(CMAC_PAUSE_ENABLE_WIDTH) ctlRxPauseEnable = zeroExtend(ctlRxPauseEnableReg); + method Bit#(CMAC_PAUSE_ACK_WIDTH) ctlRxPauseAck = zeroExtend(ctlRxPauseAckReg); + + method Bool ctlRxCheckEnableGcp = False; + method Bool ctlRxCheckMcastGcp = False; + method Bool ctlRxCheckUcastGcp = False; + method Bool ctlRxCheckSaGcp = False; + method Bool ctlRxCheckEtypeGcp = False; + method Bool ctlRxCheckOpcodeGcp = False; + + method Bool ctlRxCheckEnablePcp = True; + method Bool ctlRxCheckMcastPcp = True; + method Bool ctlRxCheckUcastPcp = False; + method Bool ctlRxCheckSaPcp = False; + method Bool ctlRxCheckEtypePcp = False; + method Bool ctlRxCheckOpcodePcp = True; + + method Bool ctlRxCheckEnableGpp = False; + method Bool ctlRxCheckMcastGpp = False; + method Bool ctlRxCheckUcastGpp = False; + method Bool ctlRxCheckSaGpp = False; + method Bool ctlRxCheckEtypeGpp = False; + method Bool ctlRxCheckOpcodeGpp = False; + + method Bool ctlRxCheckEnablePpp = True; + method Bool ctlRxCheckMcastPpp = True; + method Bool ctlRxCheckUcastPpp = False; + method Bool ctlRxCheckSaPpp = False; + method Bool ctlRxCheckEtypePpp = False; + method Bool ctlRxCheckOpcodePpp = True; + + method Action cmacRxStatus( + Bool rxAligned, + Bit#(CMAC_PAUSE_REQ_WIDTH) rxPauseReq + ); + rxAlignedReg <= rxAligned; + rxPauseReqReg <= truncate(rxPauseReq); + endmethod + + interface RawAxiStreamSlave rxRawAxiStreamIn; + method Bool tReady = True; + method Action tValid( + Bool valid, + Bit#(AXIS_TDATA_WIDTH) tData, + Bit#(AXIS_TKEEP_WIDTH) tKeep, + Bool tLast, + Bit#(AXIS_TUSER_WIDTH) tUser + ); + if (valid) begin + rxAxiStreamInW <= tagged Valid AxiStream512 { + tData: tData, + tKeep: tKeep, + tLast: tLast, + tUser: tUser + }; + end + else begin + rxAxiStreamInW <= tagged Invalid; + end + endmethod + endinterface + +endmodule + + +interface XilinxCmacRxTxWrapper; + (* prefix = "" *) + interface XilinxCmacTxWrapper cmacTxWrapper; + (* prefix = "" *) + interface XilinxCmacRxWrapper cmacRxWrapper; +endinterface + + +(* no_default_reset *) +module mkXilinxCmacRxTxWrapper#( + Bool isEnableFlowControl, + Bool isTxWaitRxAligned, + AxiStream512PipeOut txAxiStream, + AxiStream512PipeIn rxAxiStream, + PipeOut#(FlowControlReqVec) txFlowCtrlReqVec, + PipeIn#(FlowControlReqVec) rxFlowCtrlReqVec +)( + Reset cmacRxReset, + Reset cmacTxReset, + XilinxCmacRxTxWrapper ifc +); + let txWrapper <- mkXilinxCmacTxWrapper(isEnableFlowControl, isTxWaitRxAligned, txAxiStream, txFlowCtrlReqVec, reset_by cmacTxReset); + let rxWrapper <- mkXilinxCmacRxWrapper(isEnableFlowControl, rxAxiStream, rxFlowCtrlReqVec, reset_by cmacRxReset); + + interface cmacTxWrapper = txWrapper; + interface cmacRxWrapper = rxWrapper; +endmodule + diff --git a/src/includes/EthernetTypes.bsv b/src/includes/EthernetTypes.bsv index f390a7a..7f03486 100644 --- a/src/includes/EthernetTypes.bsv +++ b/src/includes/EthernetTypes.bsv @@ -19,9 +19,11 @@ typedef 2054 ETH_TYPE_ARP;// TYPE = 0x0806 /////////////// IP Layer -typedef 4 IP_VERSION_WIDTH; -typedef 4 IP_IHL_WIDTH; -typedef 8 IP_DS_WIDTH; +typedef 4 IP_VERSION_WIDTH; +typedef 4 IP_IHL_WIDTH; +typedef 8 IP_DS_WIDTH; +typedef 6 IP_DSCP_WIDTH; +typedef 2 IP_ECN_WIDTH; typedef 16 IP_TL_WIDTH; typedef 16 IP_ID_WIDTH; typedef 3 IP_FLAGS_WIDTH; @@ -33,6 +35,8 @@ typedef 32 IP_ADDR_WIDTH; typedef Bit#(IP_VERSION_WIDTH ) IpVersion; typedef Bit#(IP_IHL_WIDTH ) IpIHL; +typedef Bit#(IP_DSCP_WIDTH ) IpDscp; +typedef Bit#(IP_ECN_WIDTH ) IpEcn; typedef Bit#(IP_DS_WIDTH ) IpDS; typedef Bit#(IP_TL_WIDTH ) IpTL; typedef Bit#(IP_ID_WIDTH ) IpID; @@ -45,7 +49,8 @@ typedef Bit#(IP_ADDR_WIDTH ) IpAddr; typedef struct { IpVersion ipVersion; IpIHL ipIHL; - IpDS ipDS; + IpDscp ipDscp; + IpEcn ipEcn; IpTL ipTL; IpID ipID; IpFlags ipFlag; @@ -60,6 +65,8 @@ typedef struct { typedef 4 IP_VERSION_VAL; // VERSION = 0x4 typedef 5 IP_IHL_VAL; // IHL = 0x5 typedef 0 IP_DS_VAL; // DS = 0x0 +typedef 0 IP_DSCP_VAL; +typedef 0 IP_ECN_VAL; typedef 0 IP_FLAGS_VAL; // FLAGS = 0x0 typedef 0 IP_OFFSET_VAL; // FRAGMENT_OFFSET = 0 typedef 64 IP_TTL_VAL; // TTL = 0x40 @@ -235,4 +242,6 @@ typedef TMul#(BTH_UDP_IP_BYTE_WIDTH, 8) BTH_UDP_IP_WIDTH; ///// Priority Flow Control typedef 8 VIRTUAL_CHANNEL_NUM; typedef TLog#(VIRTUAL_CHANNEL_NUM) VIRTUAL_CHANNEL_INDEX_WIDTH; -typedef Bit#(VIRTUAL_CHANNEL_INDEX_WIDTH) VirtualChannelIndex; \ No newline at end of file +typedef Bit#(VIRTUAL_CHANNEL_INDEX_WIDTH) VirtualChannelIndex; +typedef 16 PFC_PAUSE_QUANTA_WIDTH; +typedef Bit#(PFC_PAUSE_QUANTA_WIDTH) PfcPauseQuanta; \ No newline at end of file diff --git a/src/includes/PortConversion.bsv b/src/includes/PortConversion.bsv index 119ed91..86677ee 100644 --- a/src/includes/PortConversion.bsv +++ b/src/includes/PortConversion.bsv @@ -12,6 +12,8 @@ interface RawUdpIpMetaDataBusSlave; method Action validData( (* port = "valid" *) Bool valid, (* port = "ip_addr" *) IpAddr ipAddr, + (* port = "ip_dscp" *) IpDscp ipDscp, + (* port = "ip_ecn" *) IpEcn ipEcn, (* port = "dst_port" *) UdpPort dstPort, (* port = "src_port" *) UdpPort srcPort, (* port = "data_len" *) UdpLength dataLen @@ -24,6 +26,8 @@ endinterface interface RawUdpIpMetaDataBusMaster; (* result = "valid" *) method Bool valid; (* result = "ip_addr" *) method IpAddr ipAddr; + (* result = "ip_dscp" *) method IpDscp ipDscp; + (* result = "ip_ecn" *) method IpEcn ipEcn; (* result = "dst_port" *) method UdpPort dstPort; (* result = "src_port" *) method UdpPort srcPort; (* result = "data_len" *) method UdpLength dataLen; @@ -102,6 +106,8 @@ module mkRawUdpIpMetaDataBusMaster#(UdpIpMetaDataPipeOut pipeIn)(RawUdpIpMetaDat method Bool valid = rawBus.valid; method IpAddr ipAddr = rawBus.data.ipAddr; + method IpDscp ipDscp = rawBus.data.ipDscp; + method IpEcn ipEcn = rawBus.data.ipEcn; method UdpPort dstPort = rawBus.data.dstPort; method UdpPort srcPort = rawBus.data.srcPort; method UdpLength dataLen = rawBus.data.dataLen; @@ -116,14 +122,18 @@ module mkRawUdpIpMetaDataBusSlave#(Put#(UdpIpMetaData) put)(RawUdpIpMetaDataBusS RawBusSlave#(UdpIpMetaData) rawBus <- mkPutToRawBusSlave(put, CF); method Action validData( - Bool valid, - IpAddr ipAddr, - UdpPort dstPort, - UdpPort srcPort, + Bool valid, + IpAddr ipAddr, + IpDscp ipDscp, + IpEcn ipEcn, + UdpPort dstPort, + UdpPort srcPort, UdpLength dataLen ); UdpIpMetaData metaData = UdpIpMetaData { ipAddr: ipAddr, + ipDscp: ipDscp, + ipEcn: ipEcn, dstPort: dstPort, srcPort: srcPort, dataLen: dataLen diff --git a/src/includes/Ports.bsv b/src/includes/Ports.bsv index a899871..536904e 100644 --- a/src/includes/Ports.bsv +++ b/src/includes/Ports.bsv @@ -26,10 +26,11 @@ typedef struct { } DataStream deriving(Bits, Bounded, Eq, FShow); typedef PipeOut#(DataStream) DataStreamPipeOut; - typedef struct { UdpLength dataLen; IpAddr ipAddr; + IpDscp ipDscp; + IpEcn ipEcn; UdpPort dstPort; UdpPort srcPort; } UdpIpMetaData deriving(Bits, Bounded, Eq, FShow); @@ -49,11 +50,6 @@ typedef struct { } UdpConfig deriving(Bits, Bounded, Eq, FShow); typedef PipeOut#(UdpConfig) UdpConfigPipeOut; -typedef struct { - UdpIpMetaData udpIpMetaData; - VirtualChannelIndex channelIdx; -} UdpIpMetaDataAndChannelIdx deriving(Bits, Eq, FShow); - typedef 512 AXIS_TDATA_WIDTH; typedef TDiv#(AXIS_TDATA_WIDTH, BYTE_WIDTH) AXIS_TKEEP_WIDTH; @@ -63,5 +59,7 @@ typedef AxiStream#(AXIS_TKEEP_WIDTH, AXIS_TUSER_WIDTH) AxiStream512; typedef AxiStream#(DATA_BUS_BYTE_WIDTH, AXIS_TUSER_WIDTH) AxiStream256; typedef PipeOut#(AxiStream256) AxiStream256PipeOut; typedef PipeOut#(AxiStream512) AxiStream512PipeOut; +typedef PipeIn#(AxiStream256) AxiStream256PipeIn; +typedef PipeIn#(AxiStream512) AxiStream512PipeIn; //4k Cache diff --git a/src/includes/Utils.bsv b/src/includes/Utils.bsv index 42817fe..0a9d1a2 100644 --- a/src/includes/Utils.bsv +++ b/src/includes/Utils.bsv @@ -712,4 +712,57 @@ module mkSizedFifoToPipeOut#( return convertFifoToPipeOut(fifo); endmodule +interface Counter#(type countType); + method countType _read; + method Action incr(countType amt); + method Action decr(countType amt); + method Action clear; +endinterface + +interface MultiPortCounter#(numeric type portNum, type countType); + interface Vector#(portNum, Counter#(countType)) countPorts; +endinterface + +module mkMultiPortCounter#(countType initVal)(MultiPortCounter#(portNum, countType)) + provisos(Arith#(countType), Bits#(countType, countSize)); + + Reg#(countType) countReg <- mkReg(initVal); + Vector#(portNum, Wire#(countType)) incrementVec <- replicateM(mkDWire(0)); + Vector#(portNum, Wire#(countType)) decrementVec <- replicateM(mkDWire(0)); + let isClear <- mkPulseWireOR; + + rule updateCounterValue; + countType totalIncr = 0, totalDecr = 0; + for (Integer i = 0; i < valueOf(portNum); i = i + 1) begin + totalIncr = totalIncr + incrementVec[i]; + totalDecr = totalDecr + decrementVec[i]; + end + if (isClear) begin + countReg <= 0; + end + else begin + countReg <= countReg + totalIncr - totalDecr; + end + endrule + + Vector#(portNum, Counter#(countType)) ports = newVector; + for (Integer i = 0; i < valueOf(portNum); i = i + 1) begin + ports[i] = ( + interface Counter; + method countType _read = countReg; + method Action incr(countType amt); + incrementVec[i] <= amt; + endmethod + method Action decr(countType amt); + decrementVec[i] <= amt; + endmethod + method Action clear; + isClear.send; + endmethod + endinterface + ); + end + interface countPorts = ports; +endmodule + diff --git a/syn/Makefile b/syn/Makefile index f9959ac..893d8c4 100644 --- a/syn/Makefile +++ b/syn/Makefile @@ -13,7 +13,7 @@ OUTPUTDIR = output_ooc ONLYSYNTH = 1 CLK = main_clock -TARGET = RdmaUdpArpEthRxTx +TARGET = RdmaUdpIpArpEthRxTx TARGET_FILE ?= $(ROOT_DIR)/src/$(TARGET).bsv TOPMODULE ?= mkRaw$(TARGET) export TOP = $(TOPMODULE) diff --git a/test/bluesim/TestPriorityFlowControl.bsv b/test/bluesim/TestPriorityFlowControl.bsv index 5bea687..ca6068f 100644 --- a/test/bluesim/TestPriorityFlowControl.bsv +++ b/test/bluesim/TestPriorityFlowControl.bsv @@ -17,7 +17,7 @@ import PriorityFlowControl :: *; typedef 16 CYCLE_COUNT_WIDTH; typedef 16 CASE_COUNT_WIDTH; typedef 50000 MAX_CYCLE_NUM; -typedef 64 TEST_CASE_NUM; +typedef 32 TEST_CASE_NUM; typedef 5 FRAME_COUNT_WIDTH; typedef 4 MAX_RANDOM_DELAY; @@ -47,14 +47,24 @@ module mkTestPriorityFlowControl(); Vector#(CHANNEL_NUM, Randomize#(Bit#(FRAME_COUNT_WIDTH))) randDataStreamLen <- replicateM(mkGenericRandomizer); // DUT And Ref Model - PriorityFlowControlTx#(BUF_PACKET_NUM, MAX_PACKET_FRAME_NUM) pfcTx <- mkPriorityFlowControlTx; - PriorityFlowControlRx#(BUF_PACKET_NUM, MAX_PACKET_FRAME_NUM, PFC_THRESHOLD) pfcRx <- mkPriorityFlowControlRx; - RandomDelay#(UdpIpMetaDataAndChannelIdx, MAX_RANDOM_DELAY) metaDataDelay <- mkRandomDelay; - RandomDelay#(DataStream, MAX_RANDOM_DELAY) dataStreamDelay <- mkRandomDelay; - mkConnection(metaDataDelay.request, pfcTx.udpIpMetaAndChannelIdxOut); - mkConnection(metaDataDelay.response, pfcRx.udpIpMetaAndChannelIdxIn); - mkConnection(dataStreamDelay.request, pfcTx.dataStreamOut); - mkConnection(dataStreamDelay.response, pfcRx.dataStreamIn); + Vector#(CHANNEL_NUM, FIFOF#(UdpIpMetaData)) udpIpMetaDataInBufVec <- replicateM(mkFIFOF); + Vector#(CHANNEL_NUM, FIFOF#(DataStream)) dataStreamInBufVec <- replicateM(mkFIFOF); + FIFOF#(UdpIpMetaData) udpIpMetaDataInterBuf <- mkFIFOF; + FIFOF#(DataStream) dataStreamInterBuf <- mkFIFOF; + FIFOF#(FlowControlReqVec) flowControlReqVecInterBuf <- mkFIFOF; + PriorityFlowControlTx pfcTx <- mkPriorityFlowControlTx( + convertFifoToPipeOut(flowControlReqVecInterBuf), + map(convertFifoToPipeOut, dataStreamInBufVec), + map(convertFifoToPipeOut, udpIpMetaDataInBufVec) + ); + PriorityFlowControlRx#(BUF_PACKET_NUM, MAX_PACKET_FRAME_NUM, PFC_THRESHOLD) pfcRx <- mkPriorityFlowControlRx( + convertFifoToPipeOut(dataStreamInterBuf), + convertFifoToPipeOut(udpIpMetaDataInterBuf) + ); + + mkConnection(pfcTx.udpIpMetaDataOut, toPut(udpIpMetaDataInterBuf)); + mkConnection(pfcTx.dataStreamOut, toPut(dataStreamInterBuf)); + mkConnection(pfcRx.flowControlReqVecOut, flowControlReqVecInterBuf); Vector#(CHANNEL_NUM, Reg#(Bool)) metaDataSentFlags <- replicateM(mkReg(False)); Vector#(CHANNEL_NUM, Reg#(Bit#(FRAME_COUNT_WIDTH))) dataStreamLenReg <- replicateM(mkRegU); @@ -89,7 +99,9 @@ module mkTestPriorityFlowControl(); rule sendMetaData if (isInit && !metaDataSentFlags[i] && inputCaseCounters[i] < fromInteger(testCaseNum)); let udpIpMetaData <- randUdpIpMetaData[i].next; let dataStreamLen <- randDataStreamLen[i].next; - pfcTx.udpIpMetaDataInVec[i].put(udpIpMetaData); + udpIpMetaData.ipDscp = 0; + udpIpMetaData.ipEcn = 0; + udpIpMetaDataInBufVec[i].enq(udpIpMetaData); refMetaDataBuf[i].enq(udpIpMetaData); dataStreamLenReg[i] <= dataStreamLen; frameCounters[i] <= 0; @@ -109,7 +121,7 @@ module mkTestPriorityFlowControl(); isLast: nextFrameCount == dataStreamLenReg[i] }; - pfcTx.dataStreamInVec[i].put(dataStream); + dataStreamInBufVec[i].enq(dataStream); refDataStreamBuf[i].enq(dataStream); frameCounters[i] <= nextFrameCount; @@ -128,6 +140,8 @@ module mkTestPriorityFlowControl(); let refMetaData = refMetaDataBuf[i].first; refMetaDataBuf[i].deq; $display("Virtual Channel %d: Receive %d UdpIpMetaData", i, outputCaseCounters[i]); + // $display("REF: ", fshow(refMetaData)); + // $display("DUT: ", fshow(dutMetaData)); immAssert( dutMetaData == refMetaData, "Compare DUT And REF UdpIpMetaData output @ mkTestPriorityFlowControl", diff --git a/test/bluesim/TestUdpArpEthRxTx.bsv b/test/bluesim/TestUdpArpEthRxTx.bsv index 9944cf2..07048f6 100644 --- a/test/bluesim/TestUdpArpEthRxTx.bsv +++ b/test/bluesim/TestUdpArpEthRxTx.bsv @@ -4,7 +4,7 @@ import ClientServer :: *; import FIFOF :: *; import Randomizable :: *; -import UdpArpEthRxTx :: *; +import UdpIpArpEthRxTx :: *; import Ports :: *; import EthernetTypes :: *; import TestUtils :: *; @@ -28,9 +28,9 @@ typedef enum { } InputGenState deriving(Bits, Eq); (* synthesize *) -module mkTestUdpArpEthRxTx(Empty); - UdpArpEthRxTx srcUdp <- mkUdpArpEthRxTx; - UdpArpEthRxTx dstUdp <- mkUdpArpEthRxTx; +module mkTestUdpIpArpEthRxTx(Empty); + UdpIpArpEthRxTx srcUdp <- mkUdpIpArpEthRxTx; + UdpIpArpEthRxTx dstUdp <- mkUdpIpArpEthRxTx; Reg#(UdpConfig) dstUdpConfigReg <- mkRegU; Reg#(UdpConfig) srcUdpConfigReg <- mkRegU; RandomDelay#(AxiStream512, MAX_CHANNEL_DELAY) srcToDstDelayBuf <- mkRandomDelay; diff --git a/test/bluesim/TestUdpIpArpEthRxTxWithPfc.bsv b/test/bluesim/TestUdpIpArpEthRxTxWithPfc.bsv new file mode 100644 index 0000000..cc8140f --- /dev/null +++ b/test/bluesim/TestUdpIpArpEthRxTxWithPfc.bsv @@ -0,0 +1,199 @@ +import FIFOF :: *; +import GetPut :: *; +import Vector :: *; +import Connectable :: *; +import Randomizable :: *; + +import Ports :: *; +import Utils :: *; +import PrimUtils :: *; +import EthernetTypes :: *; +import UdpIpArpEthRxTxWithPfc :: *; + +import SemiFifo :: *; + +typedef 16 CYCLE_COUNT_WIDTH; +typedef 16 CASE_COUNT_WIDTH; +typedef 50000 MAX_CYCLE_NUM; +typedef 512 TEST_CASE_NUM; + +typedef 32'h7F000001 DUT_IP_ADDR; +typedef 48'hd89c679c4829 DUT_MAC_ADDR; +typedef 32'h00000000 DUT_NET_MASK; +typedef 32'h00000000 DUT_GATE_WAY; +typedef 22 DUT_PORT_NUM; + +typedef 5 FRAME_COUNT_WIDTH; +typedef VIRTUAL_CHANNEL_NUM CHANNEL_NUM; + +typedef 400 PAUSE_CYCLE_NUM; + +typedef 4 TEST_CHANNEL_IDX; +typedef 10 BUF_PACKET_NUM; +typedef 32 MAX_PACKET_FRAME_NUM; +typedef 3 PFC_THRESHOLD; + +typedef 256 REF_BUF_DEPTH; + +(* synthesize *) +module mkTestUdpIpArpEthRxTxWithPfc(); + Integer testCaseNum = valueOf(TEST_CASE_NUM); + Integer maxCycleNum = valueOf(MAX_CYCLE_NUM); + Integer testChannelIdx = valueOf(TEST_CHANNEL_IDX); + + // Common Signals + Reg#(Bool) isInit <- mkReg(False); + Reg#(Bit#(CYCLE_COUNT_WIDTH)) cycleCount <- mkReg(0); + Reg#(Bit#(CASE_COUNT_WIDTH)) inputCaseCounter <- mkReg(0); + Reg#(Bit#(CASE_COUNT_WIDTH)) outputCaseCounter <- mkReg(0); + + // Random Signals + Randomize#(Bool) randPause <- mkGenericRandomizer; + Randomize#(Data) randData <- mkGenericRandomizer; + Randomize#(Bit#(FRAME_COUNT_WIDTH)) randFrameNum <- mkGenericRandomizer; + + // DUT And Ref Model + Reg#(Bool) isRxPause <- mkReg(True); + Reg#(Bit#(CYCLE_COUNT_WIDTH)) pauseCycleCount <- mkReg(0); + Reg#(Bool) metaDataSentFlag <- mkReg(False); + Reg#(Bit#(FRAME_COUNT_WIDTH)) frameNumReg <- mkRegU; + Reg#(Bit#(FRAME_COUNT_WIDTH)) frameCounter <- mkReg(0); + + FIFOF#(AxiStream512) axiStreamInterBuf <- mkFIFOF; + FIFOF#(UdpIpMetaData) refMetaDataBuf <- mkSizedFIFOF(valueOf(REF_BUF_DEPTH)); + FIFOF#(DataStream) refDataStreamBuf <- mkSizedFIFOF(valueOf(REF_BUF_DEPTH)); + + UdpIpArpEthRxTxWithPfc#(BUF_PACKET_NUM, MAX_PACKET_FRAME_NUM, PFC_THRESHOLD) udpIpArpEthRxTxWithPfc <- mkUdpIpArpEthRxTxWithPfc; + mkConnection(udpIpArpEthRxTxWithPfc.flowControlReqVecIn, toGet(udpIpArpEthRxTxWithPfc.flowControlReqVecOut)); + mkConnection(udpIpArpEthRxTxWithPfc.axiStreamInRx, toGet(axiStreamInterBuf)); + rule connectAxiStream; + let axiStream = udpIpArpEthRxTxWithPfc.axiStreamOutTx.first; + udpIpArpEthRxTxWithPfc.axiStreamOutTx.deq; + if (axiStreamInterBuf.notFull) begin + axiStreamInterBuf.enq(axiStream); + end + else begin + $display("Testbench: Throw AxiStream frame"); + end + endrule + + + // Initialize Testbench + rule initTest if (!isInit); + randPause.cntrl.init; + randData.cntrl.init; + randFrameNum.cntrl.init; + + udpIpArpEthRxTxWithPfc.udpConfig.put( + UdpConfig { + macAddr: fromInteger(valueOf(DUT_MAC_ADDR)), + ipAddr: fromInteger(valueOf(DUT_IP_ADDR)), + netMask: fromInteger(valueOf(DUT_NET_MASK)), + gateWay: fromInteger(valueOf(DUT_GATE_WAY)) + } + ); + + isInit <= True; + endrule + + // Count Cycle Number + rule doCycleCount if (isInit); + cycleCount <= cycleCount + 1; + $display("\nCycle %d ----------------------------------------", cycleCount); + immAssert( + cycleCount < fromInteger(maxCycleNum), + "Testbench timeout assertion @ mkTestUdpIpArpEthRxTxWithPfc", + $format("Cycle number overflow %d", maxCycleNum) + ); + endrule + + rule genRandomRxPause if (isInit); + if (pauseCycleCount == fromInteger(valueOf(PAUSE_CYCLE_NUM))) begin + pauseCycleCount <= 0; + let isPause <- randPause.next; + isRxPause <= isPause; + $display("Testbench: Pause UdpIpArpEthRx ", fshow(isPause)); + end + else begin + pauseCycleCount <= pauseCycleCount + 1; + end + endrule + + rule sendMetaData if (isInit && !metaDataSentFlag && inputCaseCounter < fromInteger(testCaseNum)); + let frameNum <- randFrameNum.next; + if (frameNum == 0) frameNum = 1; + + let udpIpMetaData = UdpIpMetaData { + dataLen: zeroExtend(frameNum) * fromInteger(valueOf(DATA_BUS_BYTE_WIDTH)), + ipAddr: fromInteger(valueOf(DUT_IP_ADDR)), + ipDscp: 0, + ipEcn: 0, + dstPort: fromInteger(valueOf(DUT_PORT_NUM)), + srcPort: fromInteger(valueOf(DUT_PORT_NUM)) + }; + + refMetaDataBuf.enq(udpIpMetaData); + udpIpArpEthRxTxWithPfc.udpIpMetaDataInTxVec[testChannelIdx].put(udpIpMetaData); + + frameNumReg <= frameNum; + frameCounter <= 0; + metaDataSentFlag <= True; + $display("Testbench: Channel %3d Send %d UdpIpMetaData", testChannelIdx, inputCaseCounter); + endrule + + rule sendDataStream if (metaDataSentFlag); + let data <- randData.next; + let nextFrameCount = frameCounter + 1; + let dataStream = DataStream { + data: data, + byteEn: setAllBits, + isFirst: frameCounter == 0, + isLast: nextFrameCount == frameNumReg + }; + + + refDataStreamBuf.enq(dataStream); + udpIpArpEthRxTxWithPfc.dataStreamInTxVec[testChannelIdx].put(dataStream); + frameCounter <= nextFrameCount; + + if (dataStream.isLast) begin + metaDataSentFlag <= False; + inputCaseCounter <= inputCaseCounter + 1; + end + + $display("Testbench: Channel %3d: Send %d dataStream of %d case", testChannelIdx, frameCounter, inputCaseCounter); + endrule + + + rule recvAndCheckMetaData if (!isRxPause); + let dutMetaData <- udpIpArpEthRxTxWithPfc.udpIpMetaDataOutRxVec[testChannelIdx].get; + let refMetaData = refMetaDataBuf.first; + refMetaDataBuf.deq; + $display("Testbench: Channel %3d: Receive %d UdpIpMetaData", testChannelIdx, outputCaseCounter); + immAssert( + dutMetaData == refMetaData, + "Compare DUT And REF UdpIpMetaData output @ mkTestUdpIpArpEthRxTxWithPfc", + $format("Channel %d Case %5d incorrect", testChannelIdx, outputCaseCounter) + ); + endrule + + rule recvAndCheckDataStream if (!isRxPause); + let dutDataStream <- udpIpArpEthRxTxWithPfc.dataStreamOutRxVec[testChannelIdx].get; + let refDataStream = refDataStreamBuf.first; + refDataStreamBuf.deq; + $display("Testbench: Channel %3d: Receive %d DataStream", testChannelIdx, outputCaseCounter); + immAssert( + dutDataStream == refDataStream, + "Compare DUT And REF DataStream output @ mkTestUdpIpArpEthRxTxWithPfc", + $format("Channel %3d Case %5d incorrect", testChannelIdx, outputCaseCounter) + ); + if (dutDataStream.isLast) begin + outputCaseCounter <= outputCaseCounter + 1; + end + endrule + + rule finishTest if (outputCaseCounter == fromInteger(testCaseNum)); + $display("Testbench: Channel %3d pass %5d testcases", testChannelIdx, testCaseNum); + $finish; + endrule +endmodule \ No newline at end of file diff --git a/test/bluesim/TestUtils.bsv b/test/bluesim/TestUtils.bsv index 7d45a54..5bd10c2 100644 --- a/test/bluesim/TestUtils.bsv +++ b/test/bluesim/TestUtils.bsv @@ -81,6 +81,7 @@ module mkDataStreamSender#( if (nextRawByteCountVal >= rawByteNum) begin let extraByteNum = nextRawByteCountVal - rawByteNum; dataStream.byteEn = dataStream.byteEn >> extraByteNum; + dataStream.data = bitMask(dataStream.data, dataStream.byteEn); dataStream.isLast = True; fragCounter <= 0; rawByteCounter <= 0; diff --git a/test/cocotb/Makefile b/test/cocotb/Makefile index e7cb33d..4bd29b5 100644 --- a/test/cocotb/Makefile +++ b/test/cocotb/Makefile @@ -25,7 +25,7 @@ verilog: echo "" > $(VLOG_FILE) bluetcl $(SCRIPTS_DIR)/listVlogFiles.tcl -bdir $(BUILDDIR) -vdir $(BUILDDIR) $(TOP) $(TOP) | grep -i '\.v' | xargs -I {} cat {} >> $(VLOG_FILE) -cocotb: verilog table +cocotb: verilog #table python3 $(TEST_FILE) clean: diff --git a/test/cocotb/TestRdmaUdpIpArpEthRxTx.py b/test/cocotb/TestRdmaUdpIpArpEthRxTx.py new file mode 100644 index 0000000..e973b82 --- /dev/null +++ b/test/cocotb/TestRdmaUdpIpArpEthRxTx.py @@ -0,0 +1 @@ +// TODO: \ No newline at end of file diff --git a/test/cocotb/TestRdmaUdpIpEthRx.py b/test/cocotb/TestRdmaUdpIpEthRx.py index 564fe5f..6982978 100644 --- a/test/cocotb/TestRdmaUdpIpEthRx.py +++ b/test/cocotb/TestRdmaUdpIpEthRx.py @@ -15,25 +15,11 @@ from cocotbext.axi import AxiStreamBus, AxiStreamSource, AxiStreamSink, AxiStreamFrame from cocotbext.axi.stream import define_stream +from TestUtils import * -UdpConfigBus, UdpConfigTransation, UdpConfigSource, UdpConfigSink, UdpConfigMonitor = define_stream( - "UdpConfig", signals=["valid", "ready", "mac_addr", "ip_addr", "net_mask", "gate_way"] -) - -UdpMetaBus, UdpMetaTransation, UdpMetaSource, UdpMetaSink, UdpMetaMonitor = define_stream( - "UdpMeta", signals=["valid", "ready", "ip_addr", "dst_port", "src_port", "data_len"] -) - -MacMetaBus, MacMetaTransaction, MacMetaSource, MacMetaSink, MacMetaMonitor = define_stream( - "MacMeta", signals=["valid", "ready", "mac_addr", "eth_type"] -) - -UDP_PORT_LEN = 2 -IP_ADDR_LEN = 4 -MAC_ADDR_LEN = 6 -MIN_PAYLOAD_LEN = 2048 -MAX_PAYLOAD_LEN = 4096 -CASES_NUM = 32 +MIN_PAYLOAD_LEN = 46 +MAX_PAYLOAD_LEN = 2048 +CASES_NUM = 1024 class RdmaUdpIpEthRxTester: def __init__(self, dut, cases_num, min_payload_len, max_payload_len): @@ -55,8 +41,8 @@ def __init__(self, dut, cases_num, min_payload_len, max_payload_len): self.axi_stream_src = AxiStreamSource(AxiStreamBus.from_prefix(dut, "s_axis"), self.clock, self.resetn, False) self.data_stream_sink = AxiStreamSink(AxiStreamBus.from_prefix(dut, "m_data_stream"), self.clock, self.resetn, False) - self.udp_meta_sink = UdpMetaSink(UdpMetaBus.from_prefix(dut, "m_udp_meta"), self.clock, self.resetn, False) - self.mac_meta_sink = MacMetaSink(MacMetaBus.from_prefix(dut, "m_mac_meta"), self.clock, self.resetn, False) + self.udp_ip_meta_sink = UdpIpMetaDataSink(UdpIpMetaDataBus.from_prefix(dut, "m_udp_meta"), self.clock, self.resetn, False) + self.mac_meta_sink = MacMetaDataSink(MacMetaDataBus.from_prefix(dut, "m_mac_meta"), self.clock, self.resetn, False) async def gen_clock(self): await cocotb.start(Clock(self.clock, 10, 'ns').start()) @@ -72,10 +58,10 @@ async def gen_reset(self): await RisingEdge(self.clock) async def config(self): - self.local_mac = random.randbytes(MAC_ADDR_LEN) - self.local_ip = random.randbytes(IP_ADDR_LEN) - self.net_mask = random.randbytes(IP_ADDR_LEN) - self.gate_way = random.randbytes(IP_ADDR_LEN) + self.local_mac = random.randbytes(MAC_ADDR_BYTE_NUM) + self.local_ip = random.randbytes(IP_ADDR_BYTE_NUM) + self.net_mask = random.randbytes(IP_ADDR_BYTE_NUM) + self.gate_way = random.randbytes(IP_ADDR_BYTE_NUM) udpConfig = UdpConfigTransation() udpConfig.mac_addr = int.from_bytes(self.local_mac, 'big') udpConfig.ip_addr = int.from_bytes(self.local_ip, 'big') @@ -86,10 +72,10 @@ async def config(self): def gen_random_packet(self): bind_layers(UDP, BTH) - src_mac = random.randbytes(MAC_ADDR_LEN) - src_ip = random.randbytes(IP_ADDR_LEN) - sport = random.randbytes(UDP_PORT_LEN) - dport = random.randbytes(UDP_PORT_LEN) + src_mac = random.randbytes(MAC_ADDR_BYTE_NUM) + src_ip = random.randbytes(IP_ADDR_BYTE_NUM) + sport = random.randbytes(UDP_PORT_BYTE_NUM) + dport = random.randbytes(UDP_PORT_BYTE_NUM) payload_size = random.randint(self.min_payload_len, self.max_payload_len - 1) payload = random.randbytes(payload_size) @@ -102,16 +88,6 @@ def gen_random_packet(self): packet = Ether(raw(header/Raw(payload))) return packet - - def is_udp_meta_equal(self, dut, ref): - is_equal = (dut.ip_addr == ref.ip_addr) - is_equal = is_equal & (dut.dst_port == ref.dst_port) - is_equal = is_equal & (dut.src_port == ref.src_port) - is_equal = is_equal & (dut.data_len == ref.data_len) - return is_equal - - def is_mac_meta_equal(self, dut, ref): - return (dut.mac_addr == ref.mac_addr) & (dut.eth_type == ref.eth_type) async def drive_dut_input(self): for case_idx in range(self.cases_num): @@ -119,12 +95,12 @@ async def drive_dut_input(self): axi_frame = AxiStreamFrame(tdata=raw(packet)) await self.axi_stream_src.send(axi_frame) - mac_meta_trans = MacMetaTransaction() + mac_meta_trans = MacMetaDataTransaction() mac_meta_trans.mac_addr = int.from_bytes(mac2str(packet[Ether].src), 'big') mac_meta_trans.eth_type = packet[Ether].type self.ref_mac_meta_buf.put(mac_meta_trans) - udp_meta_trans = UdpMetaTransation() + udp_meta_trans = UdpIpMetaDataTransation() udp_meta_trans.ip_addr = atol(packet[IP].src) udp_meta_trans.dst_port = packet[UDP].dport udp_meta_trans.src_port = packet[UDP].sport @@ -139,26 +115,26 @@ async def drive_dut_input(self): async def check_mac_meta(self): self.mac_meta_sink.clear() for case_idx in range(self.cases_num): - dut_mac_meta = await self.mac_meta_sink.recv() - ref_mac_meta = self.ref_mac_meta_buf.get() - equal = self.is_mac_meta_equal(dut_mac_meta, ref_mac_meta) + dut_meta = await self.mac_meta_sink.recv() + ref_meta = self.ref_mac_meta_buf.get() + equal = is_mac_meta_equal(dut_meta, ref_meta) if not equal: - print("Dut Mac Meta: ", dut_mac_meta) - print("Ref Mac Meta: ", ref_mac_meta) - assert equal, f"Test Case {case_idx}: check mac meta failed" - self.log.info(f"Test Case {case_idx}: Pass mac meta check") + print("Dut MacMetaData: ", dut_meta) + print("Ref MacMetaData: ", ref_meta) + assert equal, f"Test Case {case_idx}: check MacMetaData failed" + self.log.info(f"Test Case {case_idx}: Pass MacMetaData check") - async def check_udp_meta(self): - self.udp_meta_sink.clear() + async def check_udp_ip_meta(self): + self.udp_ip_meta_sink.clear() for case_idx in range(self.cases_num): - dut_udp_meta = await self.udp_meta_sink.recv() - ref_udp_meta = self.ref_udp_meta_buf.get() - equal = self.is_udp_meta_equal(dut_udp_meta, ref_udp_meta) + dut_meta = await self.udp_ip_meta_sink.recv() + ref_meta = self.ref_udp_meta_buf.get() + equal = is_udp_ip_meta_equal(dut_meta, ref_meta) if not equal: - print("Dut Udp Meta: ", dut_udp_meta) - print("Ref Udp Meta: ", ref_udp_meta) - assert equal, f"Test Case {case_idx}: check udp meta failed" - self.log.info(f"Test Case {case_idx}: Pass udp meta check") + print("Dut UdpIpMetaData: ", dut_meta) + print("Ref UdpIpMetaData: ", ref_meta) + assert equal, f"Test Case {case_idx}: check UdpIpMetaData failed" + self.log.info(f"Test Case {case_idx}: Pass UdpIpMetaData check") async def check_data_stream(self): for case_idx in range(self.cases_num): @@ -166,22 +142,22 @@ async def check_data_stream(self): dut_data_stream = bytes(dut_data_stream.tdata) ref_data_stream = self.ref_data_stream_buf.get() if(dut_data_stream != ref_data_stream): - print(f"Dut Data Stream Size {len(dut_data_stream)}") - print("Dut Data Stream: ", dut_data_stream.hex('-')) - print(f"Ref Data Stream Size {len(ref_data_stream)}") - print("Ref Data Stream: ", ref_data_stream.hex('-')) - print(f"Test Case {case_idx}: check data stream failed") + print(f"Dut DataStream Size {len(dut_data_stream)}") + print("Dut DataStream: ", dut_data_stream.hex('-')) + print(f"Ref DataStream Size {len(ref_data_stream)}") + print("Ref DataStream: ", ref_data_stream.hex('-')) + print(f"Test Case {case_idx}: check DataStream failed") assert dut_data_stream == ref_data_stream - self.log.info(f"Test Case {case_idx}: Pass data stream check") + self.log.info(f"Test Case {case_idx}: Pass DataStream check") async def check_dut_output(self): check_mac_meta = await cocotb.start(self.check_mac_meta()) - check_udp_meta = await cocotb.start(self.check_udp_meta()) + check_udp_ip_meta = await cocotb.start(self.check_udp_ip_meta()) check_data_stream = await cocotb.start(self.check_data_stream()) await check_data_stream -@cocotb.test(timeout_time=500000, timeout_unit="ns") +@cocotb.test(timeout_time=1000000000, timeout_unit="ns") async def runRdmaUdpIpEthRxTester(dut): tester = RdmaUdpIpEthRxTester(dut, CASES_NUM, MIN_PAYLOAD_LEN, MAX_PAYLOAD_LEN) @@ -192,7 +168,7 @@ async def runRdmaUdpIpEthRxTester(dut): check_thread = cocotb.start_soon(tester.check_dut_output()) tester.log.info("Start testing!") await check_thread - tester.log.info(f"Pass all {tester.cases_num} successfully") + tester.log.info(f"Pass all {tester.cases_num} testcases successfully") def test_RdmaUdpIpEthRx(): diff --git a/test/cocotb/TestRdmaUdpIpEthTx.py b/test/cocotb/TestRdmaUdpIpEthTx.py index 54c3520..3c71013 100644 --- a/test/cocotb/TestRdmaUdpIpEthTx.py +++ b/test/cocotb/TestRdmaUdpIpEthTx.py @@ -13,24 +13,12 @@ from cocotbext.axi import AxiStreamBus, AxiStreamSource, AxiStreamSink, AxiStreamFrame from cocotbext.axi.stream import define_stream -IP_ADDR_LEN = 4 -MAC_ADDR_LEN = 6 -UDP_PORT_LEN = 2 -MIN_PAYLOAD_LEN = 1024 -MAX_PAYLOAD_LEN = 2048 -CASES_NUM = 32 - -UdpConfigBus, UdpConfigTransation, UdpConfigSource, UdpConfigSink, UdpConfigMonitor = define_stream( - "UdpConfig", signals=["valid", "ready", "mac_addr", "ip_addr", "net_mask", "gate_way"] -) +from TestUtils import * -UdpIpMetaBus, UdpIpMetaTransation, UdpIpMetaSource, UdpIpMetaSink, UdpIpMetaMonitor = define_stream( - "UdpIpMeta", signals=["valid", "ready", "ip_addr", "dst_port", "src_port", "data_len"] -) +MIN_PAYLOAD_LEN = 46 +MAX_PAYLOAD_LEN = 2048 +CASES_NUM = 1024 -MacMetaBus, MacMetaTransaction, MacMetaSource, MacMetaSink, MacMetaMonitor = define_stream( - "MacMeta", signals=["valid", "ready", "mac_addr", "eth_type"] -) class RdmaUdpIpEthTxTester: def __init__(self, dut, cases_num, min_payload_len, max_payload_len): @@ -43,15 +31,15 @@ def __init__(self, dut, cases_num, min_payload_len, max_payload_len): self.min_payload_len = min_payload_len self.max_payload_len = max_payload_len self.ref_buffer = Queue(maxsize = self.cases_num) - self.local_ip = random.randbytes(IP_ADDR_LEN) - self.local_mac = random.randbytes(MAC_ADDR_LEN) + self.local_ip = random.randbytes(IP_ADDR_BYTE_NUM) + self.local_mac = random.randbytes(MAC_ADDR_BYTE_NUM) self.clock = dut.CLK self.resetn = dut.RST_N self.udp_config_src = UdpConfigSource(UdpConfigBus.from_prefix(dut, "s_udp_config"), self.clock, self.resetn, False) - self.udp_meta_src = UdpIpMetaSource(UdpIpMetaBus.from_prefix(dut, "s_udp_meta"), self.clock, self.resetn, False) - self.mac_meta_src = MacMetaSource(MacMetaBus.from_prefix(dut, "s_mac_meta"), self.clock, self.resetn, False) + self.udp_ip_meta_src = UdpIpMetaDataSource(UdpIpMetaDataBus.from_prefix(dut, "s_udp_meta"), self.clock, self.resetn, False) + self.mac_meta_src = MacMetaDataSource(MacMetaDataBus.from_prefix(dut, "s_mac_meta"), self.clock, self.resetn, False) self.data_stream_src = AxiStreamSource(AxiStreamBus.from_prefix(dut, "s_data_stream"), self.clock, self.resetn, False) self.axi_stream_sink = AxiStreamSink(AxiStreamBus.from_prefix(dut, "m_axis"), self.clock, self.resetn, False) @@ -71,8 +59,8 @@ async def config_udp(self): udp_config_trans = UdpConfigTransation() udp_config_trans.ip_addr = int.from_bytes(self.local_ip, 'big') udp_config_trans.mac_addr = int.from_bytes(self.local_mac, 'big') - udp_config_trans.net_mask = int.from_bytes(random.randbytes(IP_ADDR_LEN), 'big') - udp_config_trans.gate_way = int.from_bytes(random.randbytes(IP_ADDR_LEN), 'big') + udp_config_trans.net_mask = int.from_bytes(random.randbytes(IP_ADDR_BYTE_NUM), 'big') + udp_config_trans.gate_way = int.from_bytes(random.randbytes(IP_ADDR_BYTE_NUM), 'big') print(f"Udp Config: src_mac = {str2mac(self.local_mac)} src_ip = {ltoa(udp_config_trans.ip_addr)}") await self.udp_config_src.send(udp_config_trans) @@ -80,17 +68,19 @@ async def config_udp(self): async def send(self, pkt): payload = raw(pkt[UDP].payload)[:-4] - udp_meta = UdpIpMetaTransation() - udp_meta.ip_addr = atol(pkt[IP].dst) - udp_meta.dst_port = pkt[UDP].dport - udp_meta.src_port = pkt[UDP].sport - udp_meta.data_len = len(payload) + udp_ip_meta = UdpIpMetaDataTransation() + udp_ip_meta.ip_addr = atol(pkt[IP].dst) + udp_ip_meta.ip_dscp = 0 + udp_ip_meta.ip_ecn = 0 + udp_ip_meta.dst_port = pkt[UDP].dport + udp_ip_meta.src_port = pkt[UDP].sport + udp_ip_meta.data_len = len(payload) - mac_meta = MacMetaTransaction() + mac_meta = MacMetaDataTransaction() mac_meta.mac_addr = int.from_bytes(mac2str(pkt[Ether].dst), 'big') mac_meta.eth_type = pkt[Ether].type - await self.udp_meta_src.send(udp_meta) + await self.udp_ip_meta_src.send(udp_ip_meta) await self.mac_meta_src.send(mac_meta) frame = AxiStreamFrame() frame.tdata = payload @@ -103,11 +93,11 @@ async def recv(self): def gen_random_pkt(self): bind_layers(UDP, BTH) - dst_mac = random.randbytes(MAC_ADDR_LEN) - dst_ip_int = int.from_bytes(random.randbytes(IP_ADDR_LEN), 'big') + dst_mac = random.randbytes(MAC_ADDR_BYTE_NUM) + dst_ip_int = int.from_bytes(random.randbytes(IP_ADDR_BYTE_NUM), 'big') src_ip_int = int.from_bytes(self.local_ip, 'big') - dst_port_int = int.from_bytes(random.randbytes(UDP_PORT_LEN), 'big') - src_port_int = int.from_bytes(random.randbytes(UDP_PORT_LEN), 'big') + dst_port_int = int.from_bytes(random.randbytes(UDP_PORT_BYTE_NUM), 'big') + src_port_int = int.from_bytes(random.randbytes(UDP_PORT_BYTE_NUM), 'big') header = Ether(dst=str2mac(dst_mac), src=str2mac(self.local_mac)) header = header / IP(dst=ltoa(dst_ip_int), src=ltoa(src_ip_int)) header = header / UDP(dport=dst_port_int, sport=src_port_int, chksum=0) @@ -140,7 +130,7 @@ async def check_dut_output(self): assert raw(dut_packet)==raw(ref_packet), f"Test Case {case_idx} Fail" -@cocotb.test(timeout_time=500000, timeout_unit="ns") +@cocotb.test(timeout_time=1000000000, timeout_unit="ns") async def runRdmaUdpIpEthTxTester(dut): tester = RdmaUdpIpEthTxTester(dut, CASES_NUM, MIN_PAYLOAD_LEN, MAX_PAYLOAD_LEN) @@ -151,7 +141,7 @@ async def runRdmaUdpIpEthTxTester(dut): check_thread = cocotb.start_soon(tester.check_dut_output()) print("Start testing!") await check_thread - print(f"Pass all {tester.cases_num} successfully") + print(f"Pass all {tester.cases_num} testcases successfully") def test_RdmaUdpIpEthTx(): diff --git a/test/cocotb/TestUdpArpEthRxTx.py b/test/cocotb/TestUdpIpArpEthRxTx.py similarity index 95% rename from test/cocotb/TestUdpArpEthRxTx.py rename to test/cocotb/TestUdpIpArpEthRxTx.py index 787ccbe..8745e6f 100644 --- a/test/cocotb/TestUdpArpEthRxTx.py +++ b/test/cocotb/TestUdpIpArpEthRxTx.py @@ -12,7 +12,7 @@ from cocotbext.axi import AxiStreamBus, AxiStreamSource, AxiStreamSink, AxiStreamFrame from cocotbext.axi.stream import define_stream -from Utils import * +from TestUtils import * UdpConfigBus, UdpConfigTransation, UdpConfigSource, UdpConfigSink, UdpConfigMonitor = define_stream( @@ -24,7 +24,7 @@ ) -class UdpArpEthRxTxTester: +class UdpIpArpEthRxTxTester: def __init__(self, dut, local_ip, loacal_mac, target_ip, gate_way, net_mask, sport, dport): self.dut = dut @@ -92,7 +92,8 @@ async def config(self): async def drive_dut_input(self): print("Start sending UdpMeta and payload") for case_idx in range(self.cases_num): - payload_len = random.randint(64, self.max_payload_size) + #payload_len = random.randint(64, self.max_payload_size) + payload_len = 1024 payload = random.randbytes(payload_len) udp_meta_trans = UdpMetaTransation() @@ -160,7 +161,7 @@ async def send_and_recv_eth(self): @cocotb.test(timeout_time=100000, timeout_unit="ns") async def runUdpEthRxTester(dut): - tester = UdpArpEthRxTxTester( + tester = UdpIpArpEthRxTxTester( dut = dut, local_ip = get_default_ip_addr(), loacal_mac = get_default_mac_addr(), @@ -183,13 +184,13 @@ async def runUdpEthRxTester(dut): print(f"Pass all {tester.cases_num} successfully") -def test_UdpArpEthRxTx(): - toplevel = "mkUdpArpEthRxTxWrapper" +def test_UdpIpArpEthRxTx(): + toplevel = "mkUdpIpArpEthRxTxWrapper" module = os.path.splitext(os.path.basename(__file__))[0] test_dir = os.path.abspath(os.path.dirname(__file__)) sim_build = os.path.join(test_dir, "build") v_wrapper_file = os.path.join(test_dir, "verilog", f"{toplevel}.v") - v_source_file = os.path.join(test_dir,"verilog", "mkUdpArpEthRxTx.v") + v_source_file = os.path.join(test_dir,"verilog", "mkUdpIpArpEthRxTx.v") verilog_sources = [v_wrapper_file, v_source_file] cocotb_test.simulator.run( @@ -202,4 +203,4 @@ def test_UdpArpEthRxTx(): ) if __name__ == '__main__': - test_UdpArpEthRxTx() \ No newline at end of file + test_UdpIpArpEthRxTx() \ No newline at end of file diff --git a/test/cocotb/TestUdpIpEthRx.py b/test/cocotb/TestUdpIpEthRx.py index f4c3335..6e6d60f 100644 --- a/test/cocotb/TestUdpIpEthRx.py +++ b/test/cocotb/TestUdpIpEthRx.py @@ -14,25 +14,11 @@ from cocotbext.axi import AxiStreamBus, AxiStreamSource, AxiStreamSink, AxiStreamFrame from cocotbext.axi.stream import define_stream +from TestUtils import *; -UdpConfigBus, UdpConfigTransation, UdpConfigSource, UdpConfigSink, UdpConfigMonitor = define_stream( - "UdpConfig", signals=["valid", "ready", "mac_addr", "ip_addr", "net_mask", "gate_way"] -) - -UdpMetaBus, UdpMetaTransation, UdpMetaSource, UdpMetaSink, UdpMetaMonitor = define_stream( - "UdpMeta", signals=["valid", "ready", "ip_addr", "dst_port", "src_port", "data_len"] -) - -MacMetaBus, MacMetaTransaction, MacMetaSource, MacMetaSink, MacMetaMonitor = define_stream( - "MacMeta", signals=["valid", "ready", "mac_addr", "eth_type"] -) - -UDP_PORT_LEN = 2 -IP_ADDR_LEN = 4 -MAC_ADDR_LEN = 6 -MIN_PAYLOAD_LEN = 2048 -MAX_PAYLOAD_LEN = 4096 -CASES_NUM = 128 +MIN_PAYLOAD_LEN = 46 +MAX_PAYLOAD_LEN = 2048 +CASES_NUM = 1024 class UdpIpEthRxTester: def __init__(self, dut, cases_num, min_payload_len, max_payload_len): @@ -54,8 +40,8 @@ def __init__(self, dut, cases_num, min_payload_len, max_payload_len): self.axi_stream_src = AxiStreamSource(AxiStreamBus.from_prefix(dut, "s_axis"), self.clock, self.resetn, False) self.data_stream_sink = AxiStreamSink(AxiStreamBus.from_prefix(dut, "m_data_stream"), self.clock, self.resetn, False) - self.udp_meta_sink = UdpMetaSink(UdpMetaBus.from_prefix(dut, "m_udp_meta"), self.clock, self.resetn, False) - self.mac_meta_sink = MacMetaSink(MacMetaBus.from_prefix(dut, "m_mac_meta"), self.clock, self.resetn, False) + self.udp_meta_sink = UdpIpMetaDataSink(UdpIpMetaDataBus.from_prefix(dut, "m_udp_meta"), self.clock, self.resetn, False) + self.mac_meta_sink = MacMetaDataSink(MacMetaDataBus.from_prefix(dut, "m_mac_meta"), self.clock, self.resetn, False) async def gen_clock(self): await cocotb.start(Clock(self.clock, 10, 'ns').start()) @@ -71,10 +57,10 @@ async def gen_reset(self): await RisingEdge(self.clock) async def config(self): - self.local_mac = random.randbytes(MAC_ADDR_LEN) - self.local_ip = random.randbytes(IP_ADDR_LEN) - self.net_mask = random.randbytes(IP_ADDR_LEN) - self.gate_way = random.randbytes(IP_ADDR_LEN) + self.local_mac = random.randbytes(MAC_ADDR_BYTE_NUM) + self.local_ip = random.randbytes(IP_ADDR_BYTE_NUM) + self.net_mask = random.randbytes(IP_ADDR_BYTE_NUM) + self.gate_way = random.randbytes(IP_ADDR_BYTE_NUM) udpConfig = UdpConfigTransation() udpConfig.mac_addr = int.from_bytes(self.local_mac, 'big') udpConfig.ip_addr = int.from_bytes(self.local_ip, 'big') @@ -83,10 +69,10 @@ async def config(self): await self.udp_config_src.send(udpConfig) def gen_random_packet(self): - src_mac = random.randbytes(MAC_ADDR_LEN) - src_ip = random.randbytes(IP_ADDR_LEN) - sport = random.randbytes(UDP_PORT_LEN) - dport = random.randbytes(UDP_PORT_LEN) + src_mac = random.randbytes(MAC_ADDR_BYTE_NUM) + src_ip = random.randbytes(IP_ADDR_BYTE_NUM) + sport = random.randbytes(UDP_PORT_BYTE_NUM) + dport = random.randbytes(UDP_PORT_BYTE_NUM) payload_size = random.randint(self.min_payload_len, self.max_payload_len - 1) payload = random.randbytes(payload_size) @@ -99,15 +85,6 @@ def gen_random_packet(self): return packet - def is_udp_meta_equal(self, dut, ref): - is_equal = (dut.ip_addr == ref.ip_addr) - is_equal = is_equal & (dut.dst_port == ref.dst_port) - is_equal = is_equal & (dut.src_port == ref.src_port) - is_equal = is_equal & (dut.data_len == ref.data_len) - return is_equal - - def is_mac_meta_equal(self, dut, ref): - return (dut.mac_addr == ref.mac_addr) & (dut.eth_type == ref.eth_type) async def drive_dut_input(self): for case_idx in range(self.cases_num): @@ -115,12 +92,12 @@ async def drive_dut_input(self): axi_frame = AxiStreamFrame(tdata=raw(packet)) await self.axi_stream_src.send(axi_frame) - mac_meta_trans = MacMetaTransaction() + mac_meta_trans = MacMetaDataTransaction() mac_meta_trans.mac_addr = int.from_bytes(mac2str(packet[Ether].src), 'big') mac_meta_trans.eth_type = packet[Ether].type self.ref_mac_meta_buf.put(mac_meta_trans) - udp_meta_trans = UdpMetaTransation() + udp_meta_trans = UdpIpMetaDataTransation() udp_meta_trans.ip_addr = atol(packet[IP].src) udp_meta_trans.dst_port = packet[UDP].dport udp_meta_trans.src_port = packet[UDP].sport @@ -135,26 +112,26 @@ async def drive_dut_input(self): async def check_mac_meta(self): self.mac_meta_sink.clear() for case_idx in range(self.cases_num): - dut_mac_meta = await self.mac_meta_sink.recv() - ref_mac_meta = self.ref_mac_meta_buf.get() - equal = self.is_mac_meta_equal(dut_mac_meta, ref_mac_meta) + dut_meta = await self.mac_meta_sink.recv() + ref_meta = self.ref_mac_meta_buf.get() + equal = is_mac_meta_equal(dut_meta, ref_meta) if not equal: - print("Dut Mac Meta: ", dut_mac_meta) - print("Ref Mac Meta: ", ref_mac_meta) - assert equal, f"Test Case {case_idx}: check mac meta failed" - self.log.info(f"Test Case {case_idx}: Pass mac meta check") + print("Dut MacMetaData: ", dut_mac_meta) + print("Ref MacMetaData: ", ref_mac_meta) + assert equal, f"Test Case {case_idx}: check MacMetaData failed" + self.log.info(f"Test Case {case_idx}: Pass MacMetaData check") - async def check_udp_meta(self): + async def check_udp_ip_meta(self): self.udp_meta_sink.clear() for case_idx in range(self.cases_num): - dut_udp_meta = await self.udp_meta_sink.recv() - ref_udp_meta = self.ref_udp_meta_buf.get() - equal = self.is_udp_meta_equal(dut_udp_meta, ref_udp_meta) + dut_meta = await self.udp_meta_sink.recv() + ref_meta = self.ref_udp_meta_buf.get() + equal = is_udp_ip_meta_equal(dut_meta, ref_meta) if not equal: - print("Dut Udp Meta: ", dut_udp_meta) - print("Ref Udp Meta: ", ref_udp_meta) - assert equal, f"Test Case {case_idx}: check udp meta failed" - self.log.info(f"Test Case {case_idx}: Pass udp meta check") + print("Dut UdpIpMetaData: ", dut_meta) + print("Ref UdpIpMetaData: ", ref_meta) + assert equal, f"Test Case {case_idx}: check UdpIpMetaData failed" + self.log.info(f"Test Case {case_idx}: Pass UdpIpMetaData check") async def check_data_stream(self): for case_idx in range(self.cases_num): @@ -162,22 +139,22 @@ async def check_data_stream(self): dut_data_stream = bytes(dut_data_stream.tdata) ref_data_stream = self.ref_data_stream_buf.get() if(dut_data_stream != ref_data_stream): - print(f"Dut Data Stream Size {len(dut_data_stream)}") - print("Dut Data Stream: ", dut_data_stream.hex('-')) - print(f"Ref Data Stream Size {len(ref_data_stream)}") - print("Ref Data Stream: ", ref_data_stream.hex('-')) - print(f"Test Case {case_idx}: check data stream failed") + print(f"Dut DataStream Size {len(dut_data_stream)}") + print("Dut DataStream: ", dut_data_stream.hex('-')) + print(f"Ref DataStream Size {len(ref_data_stream)}") + print("Ref DataStream: ", ref_data_stream.hex('-')) + print(f"Test Case {case_idx}: check DataStream failed") assert dut_data_stream == ref_data_stream - self.log.info(f"Test Case {case_idx}: Pass data stream check") + self.log.info(f"Test Case {case_idx}: Pass DataStream check") async def check_dut_output(self): check_mac_meta = await cocotb.start(self.check_mac_meta()) - check_udp_meta = await cocotb.start(self.check_udp_meta()) + check_udp_ip_meta = await cocotb.start(self.check_udp_ip_meta()) check_data_stream = await cocotb.start(self.check_data_stream()) await check_data_stream -@cocotb.test(timeout_time=100000, timeout_unit="ns") +@cocotb.test(timeout_time=1000000000, timeout_unit="ns") async def runUdpIpEthRxTester(dut): tester = UdpIpEthRxTester(dut, CASES_NUM, MIN_PAYLOAD_LEN, MAX_PAYLOAD_LEN) @@ -188,7 +165,7 @@ async def runUdpIpEthRxTester(dut): check_thread = cocotb.start_soon(tester.check_dut_output()) tester.log.info("Start testing!") await check_thread - tester.log.info(f"Pass all {tester.cases_num} successfully") + tester.log.info(f"Pass all {tester.cases_num} testcases successfully") def test_UdpIpEthRx(): diff --git a/test/cocotb/TestUdpIpEthTx.py b/test/cocotb/TestUdpIpEthTx.py index 81b3dce..fa1ac91 100644 --- a/test/cocotb/TestUdpIpEthTx.py +++ b/test/cocotb/TestUdpIpEthTx.py @@ -12,24 +12,12 @@ from cocotbext.axi import AxiStreamBus, AxiStreamSource, AxiStreamSink, AxiStreamFrame from cocotbext.axi.stream import define_stream -UDP_PORT_LEN = 2 -IP_ADDR_LEN = 4 -MAC_ADDR_LEN = 6 +from TestUtils import * + MIN_PAYLOAD_LEN = 46 -MAX_PAYLOAD_LEN = 512 +MAX_PAYLOAD_LEN = 2048 CASES_NUM = 1024 -UdpConfigBus, UdpConfigTransation, UdpConfigSource, UdpConfigSink, UdpConfigMonitor = define_stream( - "UdpConfig", signals=["valid", "ready", "mac_addr", "ip_addr", "net_mask", "gate_way"] -) - -UdpIpMetaBus, UdpIpMetaTransation, UdpIpMetaSource, UdpIpMetaSink, UdpIpMetaMonitor = define_stream( - "UdpIpMeta", signals=["valid", "ready", "ip_addr", "dst_port", "src_port", "data_len"] -) - -MacMetaBus, MacMetaTransaction, MacMetaSource, MacMetaSink, MacMetaMonitor = define_stream( - "MacMeta", signals=["valid", "ready", "mac_addr", "eth_type"] -) class UdpIpEthTxTester: def __init__(self, dut, cases_num, min_payload_len, max_payload_len): @@ -42,15 +30,15 @@ def __init__(self, dut, cases_num, min_payload_len, max_payload_len): self.min_payload_len = min_payload_len self.max_payload_len = max_payload_len self.ref_buffer = Queue(maxsize = self.cases_num) - self.local_ip = random.randbytes(IP_ADDR_LEN) - self.local_mac = random.randbytes(MAC_ADDR_LEN) + self.local_ip = random.randbytes(IP_ADDR_BYTE_NUM) + self.local_mac = random.randbytes(MAC_ADDR_BYTE_NUM) self.clock = dut.CLK self.resetn = dut.RST_N self.udp_config_src = UdpConfigSource(UdpConfigBus.from_prefix(dut, "s_udp_config"), self.clock, self.resetn, False) - self.udp_meta_src = UdpIpMetaSource(UdpIpMetaBus.from_prefix(dut, "s_udp_meta"), self.clock, self.resetn, False) - self.mac_meta_src = MacMetaSource(MacMetaBus.from_prefix(dut, "s_mac_meta"), self.clock, self.resetn, False) + self.udp_ip_meta_src = UdpIpMetaDataSource(UdpIpMetaDataBus.from_prefix(dut, "s_udp_meta"), self.clock, self.resetn, False) + self.mac_meta_src = MacMetaDataSource(MacMetaDataBus.from_prefix(dut, "s_mac_meta"), self.clock, self.resetn, False) self.data_stream_src = AxiStreamSource(AxiStreamBus.from_prefix(dut, "s_data_stream"), self.clock, self.resetn, False) self.axi_stream_sink = AxiStreamSink(AxiStreamBus.from_prefix(dut, "m_axis"), self.clock, self.resetn, False) @@ -70,25 +58,27 @@ async def config_udp(self): udp_config_trans = UdpConfigTransation() udp_config_trans.ip_addr = int.from_bytes(self.local_ip, 'big') udp_config_trans.mac_addr = int.from_bytes(self.local_mac, 'big') - udp_config_trans.net_mask = int.from_bytes(random.randbytes(IP_ADDR_LEN), 'big') - udp_config_trans.gate_way = int.from_bytes(random.randbytes(IP_ADDR_LEN), 'big') + udp_config_trans.net_mask = int.from_bytes(random.randbytes(IP_ADDR_BYTE_NUM), 'big') + udp_config_trans.gate_way = int.from_bytes(random.randbytes(IP_ADDR_BYTE_NUM), 'big') print(f"Udp Config: src_mac = {str2mac(self.local_mac)} src_ip = {ltoa(udp_config_trans.ip_addr)}") await self.udp_config_src.send(udp_config_trans) async def send(self, pkt): payload = raw(pkt[UDP].payload) - udp_meta = UdpIpMetaTransation() - udp_meta.ip_addr = atol(pkt[IP].dst) - udp_meta.dst_port = pkt[UDP].dport - udp_meta.src_port = pkt[UDP].sport - udp_meta.data_len = len(payload) + udp_ip_meta = UdpIpMetaDataTransation() + udp_ip_meta.ip_addr = atol(pkt[IP].dst) + udp_ip_meta.ip_dscp = 0 + udp_ip_meta.ip_ecn = 0 + udp_ip_meta.dst_port = pkt[UDP].dport + udp_ip_meta.src_port = pkt[UDP].sport + udp_ip_meta.data_len = len(payload) - mac_meta = MacMetaTransaction() + mac_meta = MacMetaDataTransaction() mac_meta.mac_addr = int.from_bytes(mac2str(pkt[Ether].dst), 'big') mac_meta.eth_type = pkt[Ether].type - await self.udp_meta_src.send(udp_meta) + await self.udp_ip_meta_src.send(udp_ip_meta) await self.mac_meta_src.send(mac_meta) frame = AxiStreamFrame() frame.tdata = payload @@ -99,11 +89,11 @@ async def recv(self): return bytes(frame.tdata) def gen_random_pkt(self): - dst_mac = random.randbytes(MAC_ADDR_LEN) - dst_ip_int = int.from_bytes(random.randbytes(IP_ADDR_LEN), 'big') + dst_mac = random.randbytes(MAC_ADDR_BYTE_NUM) + dst_ip_int = int.from_bytes(random.randbytes(IP_ADDR_BYTE_NUM), 'big') src_ip_int = int.from_bytes(self.local_ip, 'big') - dst_port_int = int.from_bytes(random.randbytes(UDP_PORT_LEN), 'big') - src_port_int = int.from_bytes(random.randbytes(UDP_PORT_LEN), 'big') + dst_port_int = int.from_bytes(random.randbytes(UDP_PORT_BYTE_NUM), 'big') + src_port_int = int.from_bytes(random.randbytes(UDP_PORT_BYTE_NUM), 'big') header = Ether(dst=str2mac(dst_mac), src=str2mac(self.local_mac)) header = header / IP(dst=ltoa(dst_ip_int), src=ltoa(src_ip_int)) @@ -134,7 +124,7 @@ async def check_dut_output(self): assert raw(dut_packet)==raw(ref_packet), f"Test Case {case_idx} Fail" -@cocotb.test(timeout_time=200000, timeout_unit="ns") +@cocotb.test(timeout_time=1000000000, timeout_unit="ns") async def runUdpIpEthTxTester(dut): tester = UdpIpEthTxTester(dut, CASES_NUM, MIN_PAYLOAD_LEN, MAX_PAYLOAD_LEN) @@ -145,7 +135,7 @@ async def runUdpIpEthTxTester(dut): check_thread = cocotb.start_soon(tester.check_dut_output()) print("Start testing!") await check_thread - print(f"Pass all {tester.cases_num} successfully") + print(f"Pass all {tester.cases_num} testcases successfully") def test_UdpIpEthTx(): diff --git a/test/cocotb/TestUtils.py b/test/cocotb/TestUtils.py new file mode 100644 index 0000000..81b0b42 --- /dev/null +++ b/test/cocotb/TestUtils.py @@ -0,0 +1,51 @@ +import netifaces +from cocotbext.axi.stream import define_stream + +IP_ADDR_BYTE_NUM = 4 +MAC_ADDR_BYTE_NUM = 6 +UDP_PORT_BYTE_NUM = 2 + +UdpConfigBus, UdpConfigTransation, UdpConfigSource, UdpConfigSink, UdpConfigMonitor = define_stream( + "UdpConfig", signals=["valid", "ready", "mac_addr", "ip_addr", "net_mask", "gate_way"] +) + +UdpIpMetaDataBus, UdpIpMetaDataTransation, UdpIpMetaDataSource, UdpIpMetaDataSink, UdpIpMetaDataMonitor = define_stream( + "UdpIpMetaData", signals=["valid", "ready", "ip_addr", "ip_dscp", "ip_ecn", "dst_port", "src_port", "data_len"] +) + +MacMetaDataBus, MacMetaDataTransaction, MacMetaDataSource, MacMetaDataSink, MacMetaDataMonitor = define_stream( + "MacMetaData", signals=["valid", "ready", "mac_addr", "eth_type"] +) + +def is_udp_ip_meta_equal(dut:UdpIpMetaDataTransation, ref:UdpIpMetaDataTransation) -> bool: + is_equal = (dut.ip_addr == ref.ip_addr) + is_equal = is_equal & (dut.ip_dscp == ref.ip_dscp) + is_equal = is_equal & (dut.ip_ecn == ref.ip_ecn) + is_equal = is_equal & (dut.dst_port == ref.dst_port) + is_equal = is_equal & (dut.src_port == ref.src_port) + is_equal = is_equal & (dut.data_len == ref.data_len) + return is_equal + +def is_mac_meta_equal(dut:MacMetaDataTransaction, ref:MacMetaDataTransaction) -> bool: + is_equal = (dut.mac_addr == ref.mac_addr) + is_equal = is_equal & (dut.eth_type == ref.eth_type) + return is_equal + + +def get_default_gateway(): + return netifaces.gateways()['default'][netifaces.AF_INET][0] + +def get_default_ifc_name(): + return netifaces.gateways()['default'][netifaces.AF_INET][1] + +def get_default_ip_addr(): + ifc = get_default_ifc_name() + return netifaces.ifaddresses(ifc)[netifaces.AF_INET][0]['addr'] + +def get_default_mac_addr(): + ifc = get_default_ifc_name() + return netifaces.ifaddresses(ifc)[netifaces.AF_LINK][0]['addr'] + +def get_default_netmask(): + ifc = get_default_ifc_name() + return netifaces.ifaddresses(ifc)[netifaces.AF_INET][0]['netmask'] \ No newline at end of file diff --git a/test/cocotb/Utils.py b/test/cocotb/Utils.py deleted file mode 100644 index 1ec996f..0000000 --- a/test/cocotb/Utils.py +++ /dev/null @@ -1,20 +0,0 @@ -import netifaces - - -def get_default_gateway(): - return netifaces.gateways()['default'][netifaces.AF_INET][0] - -def get_default_ifc_name(): - return netifaces.gateways()['default'][netifaces.AF_INET][1] - -def get_default_ip_addr(): - ifc = get_default_ifc_name() - return netifaces.ifaddresses(ifc)[netifaces.AF_INET][0]['addr'] - -def get_default_mac_addr(): - ifc = get_default_ifc_name() - return netifaces.ifaddresses(ifc)[netifaces.AF_LINK][0]['addr'] - -def get_default_netmask(): - ifc = get_default_ifc_name() - return netifaces.ifaddresses(ifc)[netifaces.AF_INET][0]['netmask'] \ No newline at end of file diff --git a/test/vivado/Makefile b/test/vivado/Makefile new file mode 100644 index 0000000..fd6de1c --- /dev/null +++ b/test/vivado/Makefile @@ -0,0 +1,43 @@ +ROOT_DIR = $(abspath ../../) +SCRIPTS_DIR = $(ROOT_DIR)/scripts +include $(SCRIPTS_DIR)/Makefile.base +LOCALSRCDIR = $(ROOT_DIR)/src:$(ROOT_DIR)/src/includes +LIB_CRC_DIR = $(ROOT_DIR)/lib/blue-crc/src +LIB_WRAPPER_DIR = $(ROOT_DIR)/lib/blue-wrapper/src +LIBSRCDIR = $(LIB_CRC_DIR):$(LIB_WRAPPER_DIR) +CRC_TAB_SCRIPT = $(ROOT_DIR)/lib/blue-crc/scripts/gen_crc_tab.py + +FILE_PATH = $(ROOT_DIR)/test/vivado +FILE_NAME ?= UdpIpArpEthCmacRxTxTestbench.bsv +TESTBENCH_TOP ?= mkUdpIpArpEthCmacRxTxTestbench +DUT_TOP ?= mkUdpIpArpEthCmacRxTxSim +VLOGDIR = generated + +export PROJ_NAME = cmac_test +export CONFIG_SRC = "./verilog/sim_config.vh" +export SIM_SRC = "./verilog/UdpIpArpEthCmacRxTxTestbenchWrapper.v" +DESIGN_SOURCES = $(shell ls ./$(VLOGDIR)/*.v) +DESIGN_SOURCES = "$(DESIGN_SOURCES) ./verilog/UdpIpArpEthCmacRxTxSimWrapper.v" + + +table: + python3 $(CRC_TAB_SCRIPT) $(SCRIPTS_DIR)/crc_ieee_32_256.json ./ + +verilog: + mkdir -p $(BUILDDIR) + bsc -elab $(VERILOGFLAGS) $(DIRFLAGS) $(MISCFLAGS) $(RECOMPILEFLAGS) $(RUNTIMEFLAGS) $(TRANSFLAGS) -g $(TESTBENCH_TOP) $(FILE_PATH)/$(FILE_NAME) + bsc -elab $(VERILOGFLAGS) $(DIRFLAGS) $(MISCFLAGS) $(RECOMPILEFLAGS) $(RUNTIMEFLAGS) $(TRANSFLAGS) -g $(DUT_TOP) $(FILE_PATH)/$(FILE_NAME) + mkdir -p $(VLOGDIR) + bluetcl $(SCRIPTS_DIR)/listVlogFiles.tcl -bdir $(BUILDDIR) -vdir $(BUILDDIR) $(TESTBENCH_TOP) $(TESTBENCH_TOP) | grep -i '\.v' | xargs -I {} cp {} $(VLOGDIR) + bluetcl $(SCRIPTS_DIR)/listVlogFiles.tcl -bdir $(BUILDDIR) -vdir $(BUILDDIR) $(DUT_TOP) $(DUT_TOP) | grep -i '\.v' | xargs -I {} cp {} $(VLOGDIR) + +sim: verilog + vivado -mode batch -source vivado_sim.tcl + +clean: + rm -rf $(BUILDDIR) $(VLOGDIR) $(PROJ_NAME) *.mem .Xil *.jou *.log + + +.PHONY: table verilog clean +.DEFAULT_GOAL := sim + diff --git a/test/vivado/TestUdpIpArpEthCmacRxTxWithPfc.bsv b/test/vivado/TestUdpIpArpEthCmacRxTxWithPfc.bsv new file mode 100644 index 0000000..ba848d4 --- /dev/null +++ b/test/vivado/TestUdpIpArpEthCmacRxTxWithPfc.bsv @@ -0,0 +1,211 @@ +import FIFOF :: *; +import GetPut :: *; +import Vector :: *; +import Connectable :: *; +import Randomizable :: *; + +import Ports :: *; +import Utils :: *; +import PrimUtils :: *; +import EthernetTypes :: *; +import XilinxCmacRxTxWrapper :: *; +import UdpIpArpEthRxTxWithPfc :: *; + +import SemiFifo :: *; + +typedef 24 CYCLE_COUNT_WIDTH; +typedef 16 CASE_COUNT_WIDTH; +typedef 10000000 MAX_CYCLE_NUM; +typedef 512 TEST_CASE_NUM; + +typedef 32'h7F000001 DUT_IP_ADDR; +typedef 48'hd89c679c4829 DUT_MAC_ADDR; +typedef 32'h00000000 DUT_NET_MASK; +typedef 32'h00000000 DUT_GATE_WAY; +typedef 22 DUT_PORT_NUM; + +typedef 5 FRAME_COUNT_WIDTH; +typedef VIRTUAL_CHANNEL_NUM CHANNEL_NUM; + +typedef 400 PAUSE_CYCLE_NUM; + +typedef 4 TEST_CHANNEL_IDX; +typedef 16 BUF_PACKET_NUM; +typedef 32 MAX_PACKET_FRAME_NUM; +typedef 4 PFC_THRESHOLD; +typedef 8 SYNC_BRAM_BUF_DEPTH; + +typedef 256 REF_BUF_DEPTH; + +(* synthesize, default_clock_osc = "clk", default_reset = "reset" *) +module mkTestUdpIpArpEthCmacRxTxWithPfc( + (* osc = "cmac_clk" *) Clock cmacRxTxClk, + (* reset = "cmac_rx_reset" *) Reset cmacRxReset, + (* reset = "cmac_tx_reset" *) Reset cmacTxReset, + XilinxCmacRxTxWrapper cmacIfc +); + Bool isTxWaitRxAligned = True; + Integer testCaseNum = valueOf(TEST_CASE_NUM); + Integer maxCycleNum = valueOf(MAX_CYCLE_NUM); + Integer testChannelIdx = valueOf(TEST_CHANNEL_IDX); + + // Common Signals + Reg#(Bool) isInit <- mkReg(False); + Reg#(Bit#(CYCLE_COUNT_WIDTH)) cycleCount <- mkReg(0); + Reg#(Bit#(CASE_COUNT_WIDTH)) inputCaseCounter <- mkReg(0); + Reg#(Bit#(CASE_COUNT_WIDTH)) outputCaseCounter <- mkReg(0); + + // Random Signals + Randomize#(Bool) randPause <- mkGenericRandomizer; + Randomize#(Data) randData <- mkGenericRandomizer; + Randomize#(Bit#(FRAME_COUNT_WIDTH)) randFrameNum <- mkGenericRandomizer; + + // DUT And Ref Model + Reg#(Bool) isRxPauseReg <- mkReg(True); + Reg#(Bit#(CYCLE_COUNT_WIDTH)) pauseCycleCount <- mkReg(0); + Reg#(Bool) metaDataSentFlag <- mkReg(False); + Reg#(Bit#(FRAME_COUNT_WIDTH)) frameNumReg <- mkRegU; + Reg#(Bit#(FRAME_COUNT_WIDTH)) frameCounter <- mkReg(0); + + FIFOF#(AxiStream512) axiStreamInterBuf <- mkFIFOF; + FIFOF#(UdpIpMetaData) refMetaDataBuf <- mkSizedFIFOF(valueOf(REF_BUF_DEPTH)); + FIFOF#(DataStream) refDataStreamBuf <- mkSizedFIFOF(valueOf(REF_BUF_DEPTH)); + + UdpIpArpEthCmacRxTxWithPfc#( + BUF_PACKET_NUM, + MAX_PACKET_FRAME_NUM, + PFC_THRESHOLD + ) udpIpArpEthCmacRxTxWithPfc <- mkUdpIpArpEthCmacRxTxWithPfc( + isTxWaitRxAligned, + valueOf(SYNC_BRAM_BUF_DEPTH), + cmacRxTxClk, + cmacRxReset, + cmacTxReset + ); + + + // Initialize Testbench + rule initTest if (!isInit); + randPause.cntrl.init; + randData.cntrl.init; + randFrameNum.cntrl.init; + + udpIpArpEthCmacRxTxWithPfc.udpConfig.put( + UdpConfig { + macAddr: fromInteger(valueOf(DUT_MAC_ADDR)), + ipAddr: fromInteger(valueOf(DUT_IP_ADDR)), + netMask: fromInteger(valueOf(DUT_NET_MASK)), + gateWay: fromInteger(valueOf(DUT_GATE_WAY)) + } + ); + + isInit <= True; + endrule + + // Count Cycle Number + rule doCycleCount if (isInit); + cycleCount <= cycleCount + 1; + $display("\nCycle %d ----------------------------------------", cycleCount); + immAssert( + cycleCount < fromInteger(maxCycleNum), + "Testbench timeout assertion @ mkTestUdpIpArpEthCmacRxTxWithPfc", + $format("Cycle number overflow %d", maxCycleNum) + ); + endrule + + rule genRandomRxPause if (isInit); + let isPause <- randPause.next; + if (pauseCycleCount == fromInteger(valueOf(PAUSE_CYCLE_NUM))) begin + pauseCycleCount <= 0; + isRxPauseReg <= isPause; + $display("Testbench: Pause UdpIpArpEthRx ", fshow(isPause)); + end + else begin + pauseCycleCount <= pauseCycleCount + 1; + end + endrule + + rule sendMetaData if (isInit && !metaDataSentFlag && inputCaseCounter < fromInteger(testCaseNum)); + let frameNum <- randFrameNum.next; + if (frameNum == 0) frameNum = 1; + + let udpIpMetaData = UdpIpMetaData { + dataLen: zeroExtend(frameNum) * fromInteger(valueOf(DATA_BUS_BYTE_WIDTH)), + ipAddr: fromInteger(valueOf(DUT_IP_ADDR)), + ipDscp: 0, + ipEcn: 0, + dstPort: fromInteger(valueOf(DUT_PORT_NUM)), + srcPort: fromInteger(valueOf(DUT_PORT_NUM)) + }; + + refMetaDataBuf.enq(udpIpMetaData); + udpIpArpEthCmacRxTxWithPfc.udpIpMetaDataInTxVec[testChannelIdx].put(udpIpMetaData); + + frameNumReg <= frameNum; + frameCounter <= 0; + metaDataSentFlag <= True; + $display("Testbench: Channel %3d Send %d UdpIpMetaData:\n", testChannelIdx, inputCaseCounter, udpIpMetaData); + endrule + + rule sendDataStream if (metaDataSentFlag); + let data <- randData.next; + let nextFrameCount = frameCounter + 1; + let dataStream = DataStream { + data: data, + byteEn: setAllBits, + isFirst: frameCounter == 0, + isLast: nextFrameCount == frameNumReg + }; + + + refDataStreamBuf.enq(dataStream); + udpIpArpEthCmacRxTxWithPfc.dataStreamInTxVec[testChannelIdx].put(dataStream); + frameCounter <= nextFrameCount; + + if (dataStream.isLast) begin + metaDataSentFlag <= False; + inputCaseCounter <= inputCaseCounter + 1; + end + + $display("Testbench: Channel %3d: Send %d dataStream of %d case:\n", testChannelIdx, frameCounter, inputCaseCounter, dataStream); + endrule + + + rule recvAndCheckMetaData if (!isRxPauseReg); + let dutMetaData <- udpIpArpEthCmacRxTxWithPfc.udpIpMetaDataOutRxVec[testChannelIdx].get; + let refMetaData = refMetaDataBuf.first; + refMetaDataBuf.deq; + $display("Testbench: Channel %3d: Receive %d UdpIpMetaData", testChannelIdx, outputCaseCounter); + $display("DUT: ", fshow(dutMetaData)); + $display("REF: ", fshow(refMetaData)); + immAssert( + dutMetaData == refMetaData, + "Compare DUT And REF UdpIpMetaData output @ mkTestUdpIpArpEthCmacRxTxWithPfc", + $format("Channel %d Case %5d incorrect", testChannelIdx, outputCaseCounter) + ); + endrule + + rule recvAndCheckDataStream if (!isRxPauseReg); + let dutDataStream <- udpIpArpEthCmacRxTxWithPfc.dataStreamOutRxVec[testChannelIdx].get; + let refDataStream = refDataStreamBuf.first; + refDataStreamBuf.deq; + $display("Testbench: Channel %3d: Receive %d DataStream:", testChannelIdx, outputCaseCounter); + $display("DUT: ", fshow(dutDataStream)); + $display("REF: ", fshow(refDataStream)); + immAssert( + dutDataStream == refDataStream, + "Compare DUT And REF DataStream output @ mkTestUdpIpArpEthCmacRxTxWithPfc", + $format("Channel %3d Case %5d incorrect", testChannelIdx, outputCaseCounter) + ); + if (dutDataStream.isLast) begin + outputCaseCounter <= outputCaseCounter + 1; + end + endrule + + rule finishTest if (outputCaseCounter == fromInteger(testCaseNum)); + $display("Testbench: Channel %3d pass %5d testcases", testChannelIdx, testCaseNum); + $finish; + endrule + + return udpIpArpEthCmacRxTxWithPfc.cmacRxTxWrapper; +endmodule \ No newline at end of file diff --git a/test/vivado/UdpIpArpEthCmacRxTxTestbench.bsv b/test/vivado/UdpIpArpEthCmacRxTxTestbench.bsv new file mode 100644 index 0000000..390c484 --- /dev/null +++ b/test/vivado/UdpIpArpEthCmacRxTxTestbench.bsv @@ -0,0 +1,399 @@ +import FIFOF :: *; +import Vector :: *; +import GetPut :: *; +import Clocks :: *; +import Randomizable :: *; + +import Ports :: *; +import Utils :: *; +import PrimUtils :: *; +import UdpIpArpEthRxTx :: *; +import XilinxCmacRxTxWrapper :: *; + +import SemiFifo :: *; + +typedef 33 CYCLE_COUNT_WIDTH; +typedef 16 CASE_COUNT_WIDTH; +typedef 16 FRAME_COUNT_WIDTH; +typedef 1000 TEST_CASE_NUM; + +typedef 18 MIN_RAW_BYTE_NUM; +typedef 1024 MAX_RAW_BYTE_NUM; +typedef TMul#(MAX_RAW_BYTE_NUM, BYTE_WIDTH) MAX_RAW_DATA_WIDTH; +typedef TLog#(TAdd#(MAX_RAW_BYTE_NUM, 1)) MAX_RAW_BYTE_NUM_WIDTH; + +// DUT Configuration +typedef 32'h7F000001 DUT_IP_ADDR; +typedef 48'hd89c679c4829 DUT_MAC_ADDR; +typedef 32'h00000000 DUT_NET_MASK; +typedef 32'h00000000 DUT_GATE_WAY; +typedef 22 DUT_PORT_NUM; + +typedef 64 CMAC_RX_INTER_BUF_DEPTH; +typedef 8 SYNC_BRAM_BUF_DEPTH; + +typedef 512 REF_OUTPUT_BUF_DEPTH; + +// Clock and Reset Signal Configuration(unit: 1ps/1ps) +typedef 1 CLK_POSITIVE_INIT_VAL; +typedef 0 CLK_NEGATIVE_INIT_VAL; +typedef 3200 GT_REF_CLK_HALF_PERIOD; +typedef 5000 INIT_CLK_HALF_PERIOD; +typedef 1000 UDP_CLK_HALF_PERIOD; +typedef 100 SYS_RST_DURATION; +typedef 100 UDP_RESET_DURATION; + +module mkDataStreamGenerator#( + PipeOut#(Bit#(maxRawByteNumWidth)) rawByteNumIn, + PipeOut#(Bit#(maxRawDataWidth)) rawDataIn +)(DataStreamPipeOut) + provisos( + Mul#(maxRawByteNum, BYTE_WIDTH, maxRawDataWidth), + Mul#(DATA_BUS_BYTE_WIDTH, maxFragNum, maxRawByteNum), + NumAlias#(TLog#(TAdd#(maxRawByteNum, 1)), maxRawByteNumWidth), + NumAlias#(TLog#(maxFragNum), maxFragNumWidth) + ); + Reg#(Bit#(maxRawByteNumWidth)) rawByteCounter <- mkReg(0); + Reg#(Bit#(maxFragNumWidth)) fragCounter <- mkReg(0); + FIFOF#(DataStream) outputBuf <- mkFIFOF; + + rule doFragment; + let rawData = rawDataIn.first; + Vector#(maxFragNum, Data) rawDataVec = unpack(rawData); + let rawByteNum = rawByteNumIn.first; + + DataStream dataStream = DataStream { + data: rawDataVec[fragCounter], + byteEn: setAllBits, + isFirst: fragCounter == 0, + isLast: False + }; + + let nextRawByteCountVal = rawByteCounter + fromInteger(valueOf(DATA_BUS_BYTE_WIDTH)); + if (nextRawByteCountVal >= rawByteNum) begin + let extraByteNum = nextRawByteCountVal - rawByteNum; + dataStream.byteEn = dataStream.byteEn >> extraByteNum; + dataStream.isLast = True; + fragCounter <= 0; + rawByteCounter <= 0; + rawDataIn.deq; + rawByteNumIn.deq; + end + else begin + fragCounter <= fragCounter + 1; + rawByteCounter <= nextRawByteCountVal; + end + + dataStream.data = bitMask(dataStream.data, dataStream.byteEn); + + outputBuf.enq(dataStream); + //$display("%s: send %8d fragment ", instanceName, fragCounter, fshow(dataStream)); + endrule + + return convertFifoToPipeOut(outputBuf); +endmodule + +interface TestUdpIpArpEthCmacRxTx; + // Configuration + interface Get#(UdpConfig) udpConfig; + + // Tx + interface Get#(UdpIpMetaData) udpIpMetaDataOutTx; + interface Get#(DataStream) dataStreamOutTx; + + // Rx + interface Put#(UdpIpMetaData) udpIpMetaDataInRx; + interface Put#(DataStream) dataStreamInRx; +endinterface + + +module mkTestUdpIpArpEthCmacRxTx(TestUdpIpArpEthCmacRxTx); + Integer testCaseNum = valueOf(TEST_CASE_NUM); + + // Common Signals + Reg#(Bool) isInit <- mkReg(False); + Reg#(Bit#(CYCLE_COUNT_WIDTH)) cycleCount <- mkReg(0); + Reg#(Bit#(CASE_COUNT_WIDTH)) inputCaseCount <- mkReg(0); + Reg#(Bit#(CASE_COUNT_WIDTH)) inputCaseCount2 <- mkReg(0); + Reg#(Bit#(CASE_COUNT_WIDTH)) outputCaseCount <- mkReg(0); + + // Random Signals + Randomize#(Bit#(MAX_RAW_DATA_WIDTH)) randRawData <- mkGenericRandomizer; + Randomize#(Bit#(MAX_RAW_BYTE_NUM_WIDTH)) randRawByteNum <- mkGenericRandomizer; + + // DUT And Ref Model + Reg#(Bool) isDutConfig <- mkReg(False); + Reg#(Bit#(FRAME_COUNT_WIDTH)) inputFrameCount <- mkReg(0); + Reg#(Bit#(FRAME_COUNT_WIDTH)) outputframeCount <- mkReg(0); + FIFOF#(Bit#(MAX_RAW_DATA_WIDTH)) randRawDataBuf <- mkFIFOF; + FIFOF#(Bit#(MAX_RAW_BYTE_NUM_WIDTH)) randRawByteNumBuf <- mkFIFOF; + FIFOF#(DataStream) refDataStreamBuf <- mkSizedFIFOF(valueOf(REF_OUTPUT_BUF_DEPTH)); + FIFOF#(UdpIpMetaData) refMetaDataBuf <- mkSizedFIFOF(valueOf(REF_OUTPUT_BUF_DEPTH)); + + + // Input and Output Buffer + FIFOF#(UdpConfig) udpConfigBuf <- mkFIFOF; + FIFOF#(UdpIpMetaData) udpIpMetaDataOutTxBuf <- mkFIFOF; + FIFOF#(DataStream) dataStreamOutTxBuf <- mkFIFOF; + FIFOF#(UdpIpMetaData) udpIpMetaDataInRxBuf <- mkFIFOF; + FIFOF#(DataStream) dataStreamInRxBuf <- mkFIFOF; + + let pktDataStream <- mkDataStreamGenerator( + convertFifoToPipeOut(randRawByteNumBuf), + convertFifoToPipeOut(randRawDataBuf) + ); + + // Initialize Testbench + rule initTest if (!isInit); + randRawData.cntrl.init; + randRawByteNum.cntrl.init; + isInit <= True; + endrule + + // Count Cycle Number + rule doCycleCount if (isInit); + cycleCount <= cycleCount + 1; + if (cycleCount[7:0] == 0) begin + $display("\nCycle %d ----------------------------------------", cycleCount); + end + + Bool cycleCountOut = unpack(msb(cycleCount)); + immAssert( + !cycleCountOut, + "Testbench timeout assertion @ mkTestCompletionBuf", + $format("Cycle number overflows its limitation") + ); + endrule + + rule configDut if (isInit && !isDutConfig); + udpConfigBuf.enq( + UdpConfig { + macAddr: fromInteger(valueOf(DUT_MAC_ADDR)), + ipAddr: fromInteger(valueOf(DUT_IP_ADDR) ), + netMask: fromInteger(valueOf(DUT_NET_MASK)), + gateWay: fromInteger(valueOf(DUT_GATE_WAY)) + } + ); + isDutConfig <= True; + $display("Testbench: configure UdpIpArpEthCmacRxTx successfully"); + endrule + + rule driveMetaDataTx if (isDutConfig && (inputCaseCount < fromInteger(testCaseNum))); + let rawData <- randRawData.next; + let rawByteNum <- randRawByteNum.next; + + if (rawByteNum < fromInteger(valueOf(MIN_RAW_BYTE_NUM))) begin + rawByteNum = fromInteger(valueOf(MIN_RAW_BYTE_NUM)); + end + else if (rawByteNum > fromInteger(valueOf(MAX_RAW_BYTE_NUM))) begin + rawByteNum = fromInteger(valueOf(MAX_RAW_BYTE_NUM)); + end + + randRawByteNumBuf.enq(rawByteNum); + randRawDataBuf.enq(rawData); + + let metaData = UdpIpMetaData { + dataLen: zeroExtend(rawByteNum), + ipAddr: fromInteger(valueOf(DUT_IP_ADDR)), + ipDscp: 0, + ipEcn: 0, + dstPort: fromInteger(valueOf(DUT_PORT_NUM)), + srcPort: fromInteger(valueOf(DUT_PORT_NUM)) + }; + + udpIpMetaDataOutTxBuf.enq(metaData); + refMetaDataBuf.enq(metaData); + inputCaseCount <= inputCaseCount + 1; + $display("Testbench: drive UdpIpMetaDataTx %d testcase of %d bytes", inputCaseCount, rawByteNum); + endrule + + + rule driveDataStreamTx if (isDutConfig); + let dataStream = pktDataStream.first; + pktDataStream.deq; + dataStreamOutTxBuf.enq(dataStream); + refDataStreamBuf.enq(dataStream); + $display("Testbench: Drive %5d DataStream Frame of %5d testcase:\n", inputFrameCount, inputCaseCount2, fshow(dataStream)); + + if (dataStream.isLast) begin + inputFrameCount <= 0; + inputCaseCount2 <= inputCaseCount2 + 1; + $display("Testbench: Drive All Frames of %5d testcase", inputCaseCount2); + end + else begin + inputFrameCount <= inputFrameCount + 1; + end + endrule + + rule checkMetaDateRx (isDutConfig); + let dutMetaData = udpIpMetaDataInRxBuf.first; + udpIpMetaDataInRxBuf.deq; + + let refMetaData = refMetaDataBuf.first; + refMetaDataBuf.deq; + + $display("Testbench: receive UdpIpMetaData of %5d testcase:", outputCaseCount); + $display("REF: ", fshow(refMetaData)); + $display("DUT: ", fshow(dutMetaData)); + immAssert( + dutMetaData == refMetaData, + "Compare DUT And REF output @ mkTestUdpIpArpEthCmacRxTx", + $format("UdpIpMetaData of %5d testcase is incorrect", outputCaseCount) + ); + endrule + + rule checkDataStreamRx if (isDutConfig); + let dutDataStream = dataStreamInRxBuf.first; + dataStreamInRxBuf.deq; + dutDataStream.data = bitMask(dutDataStream.data, dutDataStream.byteEn); + + let refDataStream = refDataStreamBuf.first; + refDataStreamBuf.deq; + + $display("Testbench: Receive %d DataStream Frame of %5d testcase:", outputframeCount, outputCaseCount); + $display("REF: ", fshow(refDataStream)); + $display("DUT: ", fshow(dutDataStream)); + immAssert( + dutDataStream == refDataStream, + "Compare DUT And REF output @ mkTestUdpIpArpEthCmacRxTx", + $format("%d DataStream frame of %5d testcase is incorrect", outputframeCount, outputCaseCount) + ); + + if (dutDataStream.isLast) begin + outputframeCount <= 0; + outputCaseCount <= outputCaseCount + 1; + $display("Testbench: receive and verify data of %5d testcase", outputCaseCount); + end + else begin + outputframeCount <= outputframeCount + 1; + end + endrule + + // Finish Testbench + rule finishTestbench if (outputCaseCount == fromInteger(testCaseNum)); + $display("Testbench: UdpIpArpEthCmacRxTx passes all %d testcases", testCaseNum); + $finish; + endrule + + + interface udpConfig = toGet(udpConfigBuf); + interface udpIpMetaDataOutTx = toGet(udpIpMetaDataOutTxBuf); + interface dataStreamOutTx = toGet(dataStreamOutTxBuf); + interface udpIpMetaDataInRx = toPut(udpIpMetaDataInRxBuf); + interface dataStreamInRx = toPut(dataStreamInRxBuf); +endmodule + +// Drive testcases and generate clk and reset signals +interface UdpIpArpEthCmacRxTxTestbench; + (* prefix = "" *) + interface TestUdpIpArpEthCmacRxTx testStimulus; + + // Clock and Reset + (* prefix = "gt_ref_clk_p" *) + interface Clock gtPositiveRefClk; + (* prefix = "gt_ref_clk_n" *) + interface Clock gtNegativeRefClk; + (* prefix = "init_clk" *) + interface Clock initClk; + (* prefix = "sys_reset" *) + interface Reset sysReset; + (* prefix = "udp_clk" *) + interface Clock udpClk; + (* prefix = "udp_reset" *) + interface Reset udpReset; +endinterface + +(* synthesize, clock_prefix = "", reset_prefix = "", gate_prefix = "gate", no_default_clock, no_default_reset *) +module mkUdpIpArpEthCmacRxTxTestbench(UdpIpArpEthCmacRxTxTestbench); + // Clock and Reset Generation + let gtPositiveRefClkOsc <- mkAbsoluteClockFull( + valueOf(GT_REF_CLK_HALF_PERIOD), + fromInteger(valueOf(CLK_POSITIVE_INIT_VAL)), + valueOf(GT_REF_CLK_HALF_PERIOD), + valueOf(GT_REF_CLK_HALF_PERIOD) + ); + + let gtNegativeRefClkOsc <- mkAbsoluteClockFull( + valueOf(GT_REF_CLK_HALF_PERIOD), + fromInteger(valueOf(CLK_NEGATIVE_INIT_VAL)), + valueOf(GT_REF_CLK_HALF_PERIOD), + valueOf(GT_REF_CLK_HALF_PERIOD) + ); + + let initClkSrc <- mkAbsoluteClockFull( + valueOf(INIT_CLK_HALF_PERIOD), + fromInteger(valueOf(CLK_POSITIVE_INIT_VAL)), + valueOf(INIT_CLK_HALF_PERIOD), + valueOf(INIT_CLK_HALF_PERIOD) + ); + + let sysResetSrc <- mkInitialReset(valueOf(SYS_RST_DURATION), clocked_by initClkSrc); + + let udpClkSrc <- mkAbsoluteClockFull( + valueOf(UDP_CLK_HALF_PERIOD), + fromInteger(valueOf(CLK_POSITIVE_INIT_VAL)), + valueOf(UDP_CLK_HALF_PERIOD), + valueOf(UDP_CLK_HALF_PERIOD) + ); + let udpResetSrc <- mkInitialReset(valueOf(UDP_RESET_DURATION), clocked_by udpClkSrc); + + + let testUdpIpArpEthCmacRxTx <- mkTestUdpIpArpEthCmacRxTx(clocked_by udpClkSrc, reset_by udpResetSrc); + + interface testStimulus = testUdpIpArpEthCmacRxTx; + interface gtPositiveRefClk = gtPositiveRefClkOsc; + interface gtNegativeRefClk = gtNegativeRefClkOsc; + interface initClk = initClkSrc; + interface udpClk = udpClkSrc; + interface sysReset = sysResetSrc; + interface udpReset = udpResetSrc; +endmodule + + +// Wrap UdpIpArpEthCmacRxTx for Vivado Simulation +interface UdpIpArpEthCmacRxTxSim; + // Interface with CMAC IP + (* prefix = "" *) + interface XilinxCmacRxTxWrapper cmacRxTxWrapper; + + // Configuration Interface + interface Put#(UdpConfig) udpConfig; + + // Tx + interface Put#(UdpIpMetaData) udpIpMetaDataInTx; + interface Put#(DataStream) dataStreamInTx; + + // Rx + interface Get#(UdpIpMetaData) udpIpMetaDataOutRx; + interface Get#(DataStream) dataStreamOutRx; +endinterface + +(* synthesize, no_default_clock, no_default_reset *) +module mkUdpIpArpEthCmacRxTxSim( + (* osc = "udp_clk" *) Clock udpClk, + (* osc = "cmac_rxtx_clk" *) Clock cmacRxTxClk, + (* reset = "udp_reset" *) Reset udpReset, + (* reset = "cmac_rx_reset" *) Reset cmacRxReset, + (* reset = "cmac_tx_reset" *) Reset cmacTxReset, + UdpIpArpEthCmacRxTxSim ifc +); + Bool isTxWaitRxAligned = True; + let udpIpArpEthCmacRxTx <- mkUdpIpArpEthCmacRxTx( + isTxWaitRxAligned, + valueOf(SYNC_BRAM_BUF_DEPTH), + cmacRxTxClk, + cmacRxReset, + cmacTxReset, + clocked_by udpClk, + reset_by udpReset + ); + + interface cmacRxTxWrapper = udpIpArpEthCmacRxTx.cmacRxTxWrapper; + interface udpConfig = udpIpArpEthCmacRxTx.udpConfig; + interface udpIpMetaDataInTx = udpIpArpEthCmacRxTx.udpIpMetaDataInTx; + interface dataStreamInTx = udpIpArpEthCmacRxTx.dataStreamInTx; + + interface udpIpMetaDataOutRx = toGet(udpIpArpEthCmacRxTx.udpIpMetaDataOutRx); + interface dataStreamOutRx = toGet(udpIpArpEthCmacRxTx.dataStreamOutRx); +endmodule + diff --git a/test/vivado/vivado_sim.tcl b/test/vivado/vivado_sim.tcl new file mode 100644 index 0000000..d57ce74 --- /dev/null +++ b/test/vivado/vivado_sim.tcl @@ -0,0 +1,51 @@ + + +# STEP#1: define variables +# +#set out_dir $::env(OUTPUT) +#set top_module $::env(TOP) +# set design_src $::env(DESIGN_SRC) +# set simulation_src $::env(SIM_SRC) + +#set design_src $::env(DESIGN_SRC) +set config_src "./verilog/sim_config.vh" +set simulation_src "./verilog/UdpIpArpEthCmacTestbenchWrapper.v" + +set project_name cmac_test;#$::env(PROJ_NAME) +set cmac_module_name cmac_usplus_0 +set device xcvu9p-flga2104-2L-e; # xcvu9p_CIV-flga2577-2-e; # + + +# STEP#2: create in-memory project and setup sources and ip +# +create_project -part $device $project_name ./$project_name + +add_files -norecurse [glob ./generated/*.v] +add_files -norecurse ./verilog/UdpIpArpEthCmacRxTxSimWrapper.v + +add_files -norecurse $config_src +set_property is_global_include true [get_files $config_src] +update_compile_order -fileset sources_1 + +add_files -fileset sim_1 -norecurse $simulation_src +update_compile_order -fileset sim_1 + + +# STEP#3: create and synthesize ip +# +set ip_xci_file "./${project_name}/${project_name}.srcs/sources_1/ip/${cmac_module_name}/${cmac_module_name}.xci" + +create_ip -name cmac_usplus -vendor xilinx.com -library ip -version 3.1 -module_name $cmac_module_name +set_property CONFIG.USER_INTERFACE {AXIS} [ get_ips $cmac_module_name ] + + +# STEP#4: launch simulation +# +launch_simulation -simset sim_1 -mode behavioral +restart +run all + +close_project + + +