This repository has been archived by the owner on Dec 1, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 86
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #21 from LeapMind/fdma
Add FDma
- Loading branch information
Showing
7 changed files
with
1,471 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
package bxb.fdma | ||
|
||
import chisel3._ | ||
import chisel3.util._ | ||
|
||
import bxb.memory.{ReadPort} | ||
import bxb.util.{Util} | ||
|
||
class FDma(b: Int, fAddrWidth: Int, avalonAddrWidth: Int, avalonDataWidth: Int, maxBurst: Int) extends Module { | ||
val fSz = 16 | ||
val tileCountWidth = fAddrWidth | ||
val dataWidth = b * fSz | ||
|
||
require(avalonDataWidth <= 256, "exceeds maximum size of hps sdram slave port") | ||
require(isPow2(maxBurst)) | ||
|
||
val io = IO(new Bundle { | ||
val start = Input(Bool()) | ||
|
||
// Tile generation parameters | ||
val outputAddress = Input(UInt(avalonAddrWidth.W)) | ||
// - should be equal to roundUp(outputHeight / tileHeight) | ||
val outputHCount = Input(UInt(6.W)) | ||
// - should be equal to roundUp(outputWidth / tileWidth) | ||
val outputWCount = Input(UInt(6.W)) | ||
// - should be equal to roundUp(outputChannels / B) | ||
val outputCCount = Input(UInt(6.W)) | ||
|
||
// tileHeight | ||
val regularTileH = Input(UInt(tileCountWidth.W)) | ||
// - outputHeight - (hCount - 1) * tileHeight | ||
val lastTileH = Input(UInt(tileCountWidth.W)) | ||
|
||
// tileWidth | ||
val regularTileW = Input(UInt(tileCountWidth.W)) | ||
// - outputWidth - (wCount - 1) * tileWidth | ||
val lastTileW = Input(UInt(tileCountWidth.W)) | ||
|
||
// (outputWidth - regularTileW + (regularTileW % maxBurst == 0) ? maxBurst : regularTileW % maxBurst) | ||
val regularRowToRowDistance = Input(UInt(tileCountWidth.W)) | ||
// (outputWidth - lastTileW + (lastTileW % maxBurst == 0) ? maxBurst : lastTileW % maxBurst) | ||
val lastRowToRowDistance = Input(UInt(tileCountWidth.W)) | ||
|
||
// outputHeight * outputWidth | ||
val outputSpace = Input(UInt(tileCountWidth.W)) | ||
|
||
// outputWidth * regularTileH - outputWidth + lastTileW | ||
val rowDistance = Input(UInt(avalonAddrWidth.W)) | ||
|
||
// Avalon interface | ||
val avalonMasterAddress = Output(UInt(avalonAddrWidth.W)) | ||
val avalonMasterBurstCount = Output(UInt(10.W)) | ||
val avalonMasterWaitRequest = Input(Bool()) | ||
val avalonMasterWrite = Output(Bool()) | ||
val avalonMasterWriteData = Output(UInt(avalonDataWidth.W)) | ||
|
||
// FMem interface | ||
val fmemRead = Output(Vec(b, ReadPort(fAddrWidth))) | ||
val fmemQ = Input(Vec(b, UInt(fSz.W))) | ||
|
||
// Synchronization interface | ||
val fRawDec = Output(Bool()) | ||
val fRawZero = Input(Bool()) | ||
val fWarInc = Output(Bool()) | ||
}) | ||
|
||
val tileAccepted = Wire(Bool()) | ||
|
||
val tileGenerator = Module(new FDmaTileGenerator(avalonAddrWidth, dataWidth, tileCountWidth)) | ||
tileGenerator.io.start := io.start | ||
|
||
tileGenerator.io.outputAddress := io.outputAddress | ||
tileGenerator.io.outputHCount := io.outputHCount | ||
tileGenerator.io.outputWCount := io.outputWCount | ||
tileGenerator.io.outputCCount := io.outputCCount | ||
|
||
tileGenerator.io.regularTileH := io.regularTileH | ||
tileGenerator.io.lastTileH := io.lastTileH | ||
|
||
tileGenerator.io.regularTileW := io.regularTileW | ||
tileGenerator.io.lastTileW := io.lastTileW | ||
|
||
tileGenerator.io.regularRowToRowDistance := io.regularRowToRowDistance | ||
tileGenerator.io.lastRowToRowDistance := io.lastRowToRowDistance | ||
|
||
tileGenerator.io.outputSpace := io.outputSpace | ||
tileGenerator.io.rowDistance := io.rowDistance | ||
|
||
tileGenerator.io.tileAccepted := tileAccepted | ||
|
||
io.fRawDec := tileGenerator.io.fRawDec | ||
tileGenerator.io.fRawZero := io.fRawZero | ||
io.fWarInc := tileAccepted | ||
|
||
val fmemReader = Module(new FDmaFMemReader(b, avalonDataWidth, fAddrWidth, tileCountWidth)) | ||
fmemReader.io.tileHeight := tileGenerator.io.tileHeight | ||
fmemReader.io.tileWidth := tileGenerator.io.tileWidth | ||
fmemReader.io.tileValid := tileGenerator.io.tileValid | ||
io.fmemRead := fmemReader.io.fmemRead | ||
fmemReader.io.fmemQ := io.fmemQ | ||
io.avalonMasterWriteData := fmemReader.io.data | ||
fmemReader.io.waitRequest := io.avalonMasterWaitRequest | ||
|
||
val avalonWriter = Module(new FDmaAvalonWriter(avalonAddrWidth, avalonDataWidth, dataWidth, tileCountWidth, maxBurst)) | ||
avalonWriter.io.tileStartAddress := tileGenerator.io.tileStartAddress | ||
avalonWriter.io.tileHeight := tileGenerator.io.tileHeight | ||
avalonWriter.io.tileWidth := tileGenerator.io.tileWidth | ||
avalonWriter.io.tileWordRowToRowDistance := tileGenerator.io.tileWordRowToRowDistance | ||
avalonWriter.io.tileValid := tileGenerator.io.tileValid | ||
tileAccepted := avalonWriter.io.tileAccepted | ||
io.avalonMasterAddress := avalonWriter.io.avalonMasterAddress | ||
io.avalonMasterBurstCount := avalonWriter.io.avalonMasterBurstCount | ||
avalonWriter.io.avalonMasterWaitRequest := io.avalonMasterWaitRequest | ||
io.avalonMasterWrite := avalonWriter.io.avalonMasterWrite | ||
avalonWriter.io.readerReady := fmemReader.io.ready | ||
} | ||
|
||
object FDma { | ||
def main(args: Array[String]): Unit = { | ||
println(Util.getVerilog(new FDma(32, 10, 16, 128, 4))) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
package bxb.fdma | ||
|
||
import chisel3._ | ||
import chisel3.util._ | ||
|
||
import bxb.util.{Util} | ||
|
||
class FDmaAvalonWriter(avalonAddrWidth: Int, avalonDataWidth: Int, dataWidth: Int, tileCountWidth: Int, maxBurst: Int) extends Module { | ||
require(isPow2(maxBurst)) | ||
require(isPow2(avalonDataWidth)) | ||
require(isPow2(dataWidth)) | ||
require(avalonDataWidth < dataWidth) | ||
|
||
val avalonDataByteWidth = avalonDataWidth / 8 | ||
val avalonDataByteWidthLog = Chisel.log2Up(avalonDataByteWidth) | ||
|
||
val wordsPerElement = dataWidth / avalonDataWidth | ||
val wordsPerElementLog = Chisel.log2Floor(wordsPerElement) | ||
|
||
require(maxBurst >= wordsPerElement) | ||
val elementsPerBurstMax = maxBurst / wordsPerElement | ||
|
||
val countMsb = Chisel.log2Floor(elementsPerBurstMax) | ||
val burstMsb = Chisel.log2Floor(maxBurst) | ||
|
||
val io = IO(new Bundle { | ||
// Tile Generator interface | ||
val tileStartAddress = Input(UInt(avalonAddrWidth.W)) | ||
val tileHeight = Input(UInt(tileCountWidth.W)) | ||
val tileWidth = Input(UInt(tileCountWidth.W)) | ||
// byte distance between last element of some row and | ||
// first element of a row adjacent to it in elements | ||
val tileWordRowToRowDistance = Input(UInt(tileCountWidth.W)) | ||
// once tileValid asserted above tile parameters must remain stable and until tileAccepted is asserted | ||
val tileValid = Input(Bool()) | ||
// accepted at a clock when last request is sent | ||
val tileAccepted = Output(Bool()) | ||
|
||
// Avalon interface | ||
val avalonMasterAddress = Output(UInt(avalonAddrWidth.W)) | ||
val avalonMasterBurstCount = Output(UInt(10.W)) | ||
val avalonMasterWaitRequest = Input(Bool()) | ||
val avalonMasterWrite = Output(Bool()) | ||
|
||
// FDmaReader interface | ||
val readerReady = Input(Bool()) | ||
}) | ||
|
||
private def toBytes(words: UInt) = { | ||
words << avalonDataByteWidthLog.U | ||
} | ||
|
||
private def toWords(elements: UInt) = { | ||
elements << wordsPerElementLog.U | ||
} | ||
|
||
object State { | ||
val idle :: runningLong :: runningShort :: acknowledge :: Nil = Enum(4) | ||
} | ||
|
||
val state = RegInit(State.idle) | ||
|
||
val idle = (state === State.idle) | ||
val runningLong = (state === State.runningLong) | ||
val runningShort = (state === State.runningShort) | ||
val running = (runningLong | runningShort) | ||
val acknowledge = (state === State.acknowledge) | ||
|
||
val waitRequired = (running & io.avalonMasterWaitRequest) | ||
|
||
// tile loops | ||
val tileXCountShort = if (countMsb != 0) toWords(io.tileWidth(countMsb - 1, 0)) else 0.U(1.W) | ||
val tileXCountShortZero = (tileXCountShort === 0.U) | ||
val tileXCountShortLeft = Reg(UInt(burstMsb.W)) | ||
val tileXCountShortLast = (tileXCountShortLeft === 1.U) | ||
when(~waitRequired) { | ||
when(~runningShort | tileXCountShortLast) { | ||
tileXCountShortLeft := tileXCountShort | ||
}.otherwise { | ||
tileXCountShortLeft := tileXCountShortLeft - 1.U | ||
} | ||
} | ||
|
||
// when maxBurst > 1, two counters are used | ||
// tileXCountLongLeft - is number of transactions remained | ||
// tileXCountLongLoLeft - is number of data transfer remained in current transaction | ||
// when maxBurst == 1, tileXCountLongLeft is only counter we need | ||
// as each transaction has only one element | ||
val tileXCountLongLoLeft = Reg(UInt((burstMsb + 1).W)) | ||
val tileXCountLongLoLast = if (burstMsb != 0) (tileXCountLongLoLeft === 1.U) else true.B | ||
if (burstMsb != 0) { | ||
when(~waitRequired) { | ||
when(~runningLong | tileXCountLongLoLast) { | ||
tileXCountLongLoLeft := maxBurst.U | ||
}.otherwise { | ||
tileXCountLongLoLeft := tileXCountLongLoLeft - 1.U | ||
} | ||
} | ||
} | ||
|
||
val tileXCountLong = io.tileWidth(tileCountWidth - 1, countMsb) | ||
val tileXCountLongZero = (tileXCountLong === 0.U) | ||
val tileXCountLongLeft = Reg(UInt((tileCountWidth - countMsb + wordsPerElementLog).W)) | ||
val tileXCountLongLast = (tileXCountLongLeft === 1.U) & tileXCountLongLoLast | ||
val tileXCountLast = ((runningShort & tileXCountShortLast) | (runningLong & tileXCountLongLast & tileXCountShortZero)) | ||
when(~waitRequired) { | ||
when(~runningLong | tileXCountLongLast) { | ||
tileXCountLongLeft := tileXCountLong | ||
}.elsewhen(tileXCountLongLoLast) { | ||
tileXCountLongLeft := tileXCountLongLeft - 1.U | ||
} | ||
} | ||
|
||
val tileYCountLeft = Reg(UInt(tileCountWidth.W)) | ||
val tileYCountLast = (tileYCountLeft === 1.U) & tileXCountLast | ||
when(~waitRequired) { | ||
when(idle | tileYCountLast) { | ||
tileYCountLeft := io.tileHeight | ||
}.elsewhen(tileXCountLast) { | ||
tileYCountLeft := tileYCountLeft - 1.U | ||
} | ||
} | ||
|
||
val avalonAddress = Reg(UInt(avalonAddrWidth.W)) | ||
when(~waitRequired) { | ||
when(idle) { | ||
avalonAddress := io.tileStartAddress | ||
}.elsewhen(tileXCountLast) { | ||
avalonAddress := avalonAddress + toBytes(io.tileWordRowToRowDistance) | ||
}.otherwise { | ||
avalonAddress := avalonAddress + toBytes(1.U) | ||
} | ||
} | ||
|
||
when(~waitRequired) { | ||
when(idle & io.tileValid & io.readerReady) { | ||
when(~tileXCountLongZero) { | ||
state := State.runningLong | ||
}.elsewhen(~tileXCountShortZero) { | ||
state := State.runningShort | ||
} | ||
}.elsewhen(runningLong & tileXCountLongLast) { | ||
when(tileYCountLast) { | ||
state := State.acknowledge | ||
}.elsewhen(~tileXCountShortZero) { | ||
state := State.runningShort | ||
} | ||
}.elsewhen(runningShort & tileXCountShortLast) { | ||
when(tileYCountLast) { | ||
state := State.acknowledge | ||
}.elsewhen(~tileXCountLongZero) { | ||
state := State.runningLong | ||
} | ||
}.elsewhen(acknowledge) { | ||
state := State.idle | ||
} | ||
} | ||
|
||
io.tileAccepted := acknowledge | ||
io.avalonMasterAddress := avalonAddress | ||
io.avalonMasterWrite := running | ||
io.avalonMasterBurstCount := Mux(runningShort, tileXCountShort, maxBurst.U) | ||
} | ||
|
||
object FDmaAvalonWriter { | ||
def main(args: Array[String]): Unit = { | ||
println(Util.getVerilog(new FDmaAvalonWriter(32, 128, 512, 12, 16))) | ||
} | ||
} |
Oops, something went wrong.