From 20dcc39cfcf713cde975b90b36fc39eb631ce3bd Mon Sep 17 00:00:00 2001 From: BIGWJZ <1059537323@qq.com> Date: Mon, 15 Jul 2024 15:05:47 +0800 Subject: [PATCH] Add DmaRequestCore including mkChunkComputer --- src/DmaController.bsv | 24 ++++++++ src/DmaRequestCore.bsv | 121 +++++++++++++++++++++++++++++++++++++++++ test/TestDmaCore.bsv | 93 +++++++++++++++++++++++++++++++ 3 files changed, 238 insertions(+) create mode 100755 src/DmaController.bsv create mode 100755 src/DmaRequestCore.bsv create mode 100755 test/TestDmaCore.bsv diff --git a/src/DmaController.bsv b/src/DmaController.bsv new file mode 100755 index 0000000..5d8df4b --- /dev/null +++ b/src/DmaController.bsv @@ -0,0 +1,24 @@ +import PcieTypes::*; +import DmaTypes::*; + +interface DmaController#(numeric type dataWidth); + + interface FifoIn#(DataStream) dataC2HPipeIn; + interface FifoIn#(DmaRequestFrame) reqC2HPipeIn; + interface FifoIn#(DmaRequestFrame) reqH2CPipeIn; + interface FifoOut#(DataStream) dataH2CPipeOut; + + interface FifoIn#(DmaCsrFrame) csrC2HPipeIn; + interface FifoOut#(DMACsrAddr) csrC2HPipeOut; // read reg in the card from Host + interface FifoOut#(DmaCsrFrame) csrH2CPipeOut; + + interface RawPcieRequester pcieRequester; + interface RawPcieCompleter pcieCompleter; + interface RawPcieConfiguration pcieConfig; + +endinterface + +module mkDmaController#() (DmaController ifc); + + +endmodule \ No newline at end of file diff --git a/src/DmaRequestCore.bsv b/src/DmaRequestCore.bsv new file mode 100755 index 0000000..8c7df68 --- /dev/null +++ b/src/DmaRequestCore.bsv @@ -0,0 +1,121 @@ +import FIFOF::*; +import GetPut :: *; + +import SemiFifo::*; +import PcieTypes::*; +import DmaTypes::*; + + +typedef 4096 BUS_BOUNDARY; +typedef TAdd#(1, TLog#(BUS_BOUNDARY)) BUS_BOUNDARY_WIDTH; + +typedef Bit#(BUS_BOUNDARY_WIDTH) PcieTlpMaxMaxPayloadSize; +typedef Bit#(TLog#(BUS_BOUNDARY_WIDTH)) PcieTlpSizeWidth; + +typedef 128 DEFAULT_TLP_SIZE; +typedef TAdd#(1, TLog#(DEFAULT_TLP_SIZE)) DEFAULT_TLP_SIZE_WIDTH; + +typedef 3 PCIE_TLP_SIZE_SETTING_WIDTH; +typedef Bit#(PCIE_TLP_SIZE_SETTING_WIDTH) PcieTlpSizeSetting; + +typedef struct { + DmaRequestFrame dmaRequest; + DmaMemAddr firstChunkLen; +} ChunkRequestFrame deriving(Bits, Eq); + +interface ChunkCompute; + interface FifoIn#(DmaRequestFrame) dmaRequestFifoIn; + interface FifoOut#(DmaRequestFrame) chunkRequestFifoOut; + interface Put#(PcieTlpSizeSetting) setTlpMaxSize; +endinterface + +module mkChunkComputer (TRXDirection direction, ChunkCompute ifc); + + FIFOF#(DmaRequestFrame) inputFifo <- mkFIFOF; + FIFOF#(DmaRequestFrame) outputFifo <- mkFIFOF; + FIFOF#(ChunkRequestFrame) splitFifo <- mkFIFOF; + + Reg#(DmaMemAddr) newChunkPtrReg <- mkReg(0); + Reg#(DmaMemAddr) totalLenRemainReg <- mkReg(0); + Reg#(Bool) isSplittingReg <- mkReg(False); + + Reg#(DmaMemAddr) tlpMaxSize <- mkReg(fromInteger(valueOf(DEFAULT_TLP_SIZE))); + Reg#(PcieTlpSizeWidth) tlpMaxSizeWidth <- mkReg(fromInteger(valueOf(DEFAULT_TLP_SIZE_WIDTH))); + + function Bool hasBoundary(DmaRequestFrame request); + let highIdx = (request.startAddr + request.length - 1) >> valueOf(BUS_BOUNDARY_WIDTH); + let lowIdx = request.startAddr >> valueOf(BUS_BOUNDARY_WIDTH); + return (highIdx > lowIdx); + endfunction + + function DmaMemAddr getOffset(DmaRequestFrame request); + // MPS - startAddr % MPS, MPS means MRRS when the module is set to RX mode + DmaMemAddr remainderOfMps = zeroExtend(PcieTlpMaxMaxPayloadSize'(request.startAddr[tlpMaxSizeWidth-1:0])); + DmaMemAddr offsetOfMps = tlpMaxSize - remainderOfMps; + return offsetOfMps; + endfunction + + rule getfirstChunkLen; + let request = inputFifo.first; + inputFifo.deq; + let offset = getOffset(request); + let firstLen = (request.length > tlpMaxSize) ? tlpMaxSize : request.length; + splitFifo.enq(ChunkRequestFrame { + dmaRequest: request, + firstChunkLen: hasBoundary(request) ? offset : firstLen + }); + endrule + + rule execChunkSplit; + let splitRequest = splitFifo.first; + if (isSplittingReg) begin // !isFirst + if (totalLenRemainReg <= tlpMaxSize) begin + isSplittingReg <= False; + outputFifo.enq(DmaRequestFrame { + startAddr: newChunkPtrReg, + length: totalLenRemainReg + }); + splitFifo.deq; + totalLenRemainReg <= 0; + end + else begin + isSplittingReg <= True; + outputFifo.enq(DmaRequestFrame { + startAddr: newChunkPtrReg, + length: tlpMaxSize + }); + newChunkPtrReg <= newChunkPtrReg + tlpMaxSize; + totalLenRemainReg <= totalLenRemainReg - tlpMaxSize; + end + end + else begin // isFirst + let remainderLength = splitRequest.dmaRequest.length - splitRequest.firstChunkLen; + Bool isSplittingNextCycle = (remainderLength > 0); + isSplittingReg <= isSplittingNextCycle; + outputFifo.enq(DmaRequestFrame { + startAddr: splitRequest.dmaRequest.startAddr, + length: splitRequest.firstChunkLen + }); + if (!isSplittingNextCycle) begin + splitFifo.deq; + end + newChunkPtrReg <= splitRequest.dmaRequest.startAddr + splitRequest.firstChunkLen; + totalLenRemainReg <= remainderLength; + end + endrule + + interface dmaRequestFifoIn = convertFifoToFifoIn(inputFifo); + interface chunkRequestFifoOut = convertFifoToFifoOut(outputFifo); + + interface Put setTlpMaxSize; + method Action put (PcieTlpSizeSetting tlpSizeSetting); + let setting = tlpSizeSetting; + setting[valueOf(PCIE_TLP_SIZE_SETTING_WIDTH)-1] = (direction == DMA_TX) ? 0 : setting[valueOf(PCIE_TLP_SIZE_SETTING_WIDTH)-1]; + DmaMemAddr defaultTlpMaxSize = fromInteger(valueOf(DEFAULT_TLP_SIZE)); + tlpMaxSize <= DmaMemAddr'(defaultTlpMaxSize << setting); + PcieTlpSizeWidth defaultTlpMaxSizeWidth = fromInteger(valueOf(DEFAULT_TLP_SIZE_WIDTH)); + tlpMaxSizeWidth <= PcieTlpSizeWidth'(defaultTlpMaxSizeWidth + zeroExtend(setting)); + endmethod + endinterface + +endmodule \ No newline at end of file diff --git a/test/TestDmaCore.bsv b/test/TestDmaCore.bsv new file mode 100755 index 0000000..3d26e2b --- /dev/null +++ b/test/TestDmaCore.bsv @@ -0,0 +1,93 @@ +import GetPut::*; +import Randomizable::*; + +import SemiFifo::*; +import PrimUtils::*; +import DmaTypes::*; +import DmaRequestCore::*; + +typedef 100000 CHUNK_PER_EPOCH_TEST_NUM; +typedef 64'hFFFFFFFFFFFFFFFF MAX_ADDRESS; +typedef 16'hFFFF MAX_TEST_LENGTH; +typedef 2'b00 DEFAULT_TLP_SIZE_SETTING; +typedef 4 CHUNK_TX_TEST_SETTING_NUM; +typedef 6 CHUNK_RX_TEST_SETTING_NUM; + +(* doc = "testcase" *) +module mkChunkComputerTb(Empty); + + ChunkCompute dut <- mkChunkComputer(DMA_TX); + + Reg#(Bool) isInitReg <- mkReg(False); + Reg#(UInt#(32)) testCntReg <- mkReg(0); + Reg#(UInt#(32)) epochCntReg <- mkReg(0); + + Reg#(DmaMemAddr) lenRemainReg <- mkReg(0); + + Randomize#(DmaMemAddr) startAddrRandomVal <- mkConstrainedRandomizer(0, fromInteger(valueOf(MAX_ADDRESS)-1)); + Randomize#(DmaMemAddr) lengthRandomVal <- mkConstrainedRandomizer(1, fromInteger(valueOf(MAX_TEST_LENGTH))); + + function Bool hasBoundary(DmaRequestFrame request); + let highIdx = (request.startAddr + request.length - 1) >> valueOf(BUS_BOUNDARY_WIDTH); + let lowIdx = request.startAddr >> valueOf(BUS_BOUNDARY_WIDTH); + return (highIdx > lowIdx); + endfunction + + rule testInit if (!isInitReg); + startAddrRandomVal.cntrl.init; + lengthRandomVal.cntrl.init; + isInitReg <= True; + dut.setTlpMaxSize.put(fromInteger(valueOf(DEFAULT_TLP_SIZE_SETTING))); + $display("INFO: Start Test of mkChunkComputerTb"); + $display("INFO: Set Max Payload Size to ", valueOf(DEFAULT_TLP_SIZE)); + endrule + + rule testInput if (isInitReg && lenRemainReg == 0); + DmaMemAddr testAddr <- startAddrRandomVal.next; + DmaMemAddr testLength <- lengthRandomVal.next; + let testEnd = testAddr + testLength - 1; + if (testEnd > testAddr && testEnd <= fromInteger(valueOf(MAX_ADDRESS))) begin + let request = DmaRequestFrame{ + startAddr: testAddr, + length: testLength + }; + lenRemainReg <= testLength; + dut.dmaRequestFifoIn.enq(request); + // $display("INFO: input ", fshow(request)); + end + else begin + lenRemainReg <= 0; + end + endrule + + rule testOutput if (isInitReg && lenRemainReg > 0); + let newRequest = dut.chunkRequestFifoOut.first; + dut.chunkRequestFifoOut.deq; + immAssert( + !hasBoundary(newRequest), + "has boundary assert @ mkChunkComputerTb", + fshow(newRequest) + ); + let newRemain = lenRemainReg - newRequest.length; + lenRemainReg <= newRemain; + if (newRemain == 0) begin + if (epochCntReg < fromInteger(valueOf(CHUNK_PER_EPOCH_TEST_NUM)-1)) begin + epochCntReg <= epochCntReg + 1; + end + else begin + epochCntReg <= 0; + testCntReg <= testCntReg + 1; + if (testCntReg == fromInteger(valueOf(CHUNK_TX_TEST_SETTING_NUM)-1)) begin + $display("INFO: ChunkComputer Test End."); + $finish(); + end + else begin + PcieTlpSizeSetting newSetting = fromInteger(valueOf(DEFAULT_TLP_SIZE_SETTING)) + truncate(pack(testCntReg)) + 1; + dut.setTlpMaxSize.put(newSetting); + $display("INFO: Set Max Payload Size to ", pack(fromInteger(valueOf(DEFAULT_TLP_SIZE)) << newSetting)); + end + end + end + endrule + +endmodule \ No newline at end of file