Skip to content
This repository has been archived by the owner on Dec 1, 2021. It is now read-only.

Commit

Permalink
Merge pull request #21 from LeapMind/fdma
Browse files Browse the repository at this point in the history
Add FDma
  • Loading branch information
n-nez committed Mar 25, 2019
2 parents fd6b250 + 74e85d6 commit 7e44b8d
Show file tree
Hide file tree
Showing 7 changed files with 1,471 additions and 0 deletions.
122 changes: 122 additions & 0 deletions src/main/scala/bxb/fdma/FDma.scala
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)))
}
}
169 changes: 169 additions & 0 deletions src/main/scala/bxb/fdma/FDmaAvalonWriter.scala
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)))
}
}
Loading

0 comments on commit 7e44b8d

Please sign in to comment.