Commit 03be2246 authored by Jens Korinth's avatar Jens Korinth
Browse files

!WIP! still working on fixing Axi

parent 8f2faf2e
......@@ -19,9 +19,9 @@ libraryDependencies ++= (Seq("chisel3","chisel-iotesters").map {
dep: String => "edu.berkeley.cs" %% dep % sys.props.getOrElse(dep + "Version", defaultVersions(dep)) })
libraryDependencies ++= Seq(
"com.novocode" % "junit-interface" % "0.11" % "test",
"org.scalatest" %% "scalatest" % "2.2.6" % "test",
"com.typesafe.play" %% "play-json" % "2.4.8"
"org.scalatest" %% "scalatest" % "3.0.4" % "test",
"org.scalacheck" %% "scalacheck" % "1.13.5" % "test",
"com.typesafe.play" %% "play-json" % "2.6.3"
)
scalacOptions ++= Seq("-language:implicitConversions", "-language:reflectiveCalls", "-deprecation", "-feature")
......@@ -32,5 +32,5 @@ lazy val packaging = project.in(file("packaging"))
lazy val miscutils = project.in(file("miscutils"))
lazy val root = (project in file(".")).dependsOn(packaging, miscutils)
lazy val root = (project in file(".")).dependsOn(packaging, miscutils, miscutils % "test->test")
package chisel.axiutils
import chisel.axiutils.registers._
import chisel.packaging.{CoreDefinition, ModuleBuilder}
import chisel.packaging.CoreDefinition.root
import chisel.packaging._, chisel.packaging.CoreDefinition.root
import chisel.miscutils.DecoupledDataSource
import scala.sys.process._
import java.nio.file.Paths
......@@ -35,10 +34,22 @@ object AxiModuleBuilder extends ModuleBuilder {
DataWidth(64),
IdWidth(1))
implicit val axilite = Axi4Lite.Configuration(AddrWidth(32),
Axi4Lite.Width64)
Axi4Lite.Width32)
val exampleRegisterFile = new Axi4LiteRegisterFileConfiguration(addrGranularity = 8, regs = Map(
0 -> new ConstantRegister(value = BigInt("10101010", 16)),
4 -> new ConstantRegister(value = BigInt("20202020", 16)),
8 -> new ConstantRegister(value = BigInt("30303030", 16)),
16 -> new ConstantRegister(value = BigInt("40404040", 16), bitfield = Map(
"Byte #3" -> BitRange(31, 24),
"Byte #2" -> BitRange(23, 16),
"Byte #1" -> BitRange(15, 8),
"Byte #0" -> BitRange(7, 0)
))
))(Axi4Lite.Configuration(AddrWidth(32), Axi4Lite.Width32))
val modules: List[(() => Module, CoreDefinition)] = List(
( // test module with fixed data
val modules: Seq[ModuleDef] = Seq(
ModuleDef( // test module with fixed data
None,
() => new FifoAxiAdapterTest1(dataWidth = 32, 256),
CoreDefinition(
name = "FifoAxiAdapterTest1",
......@@ -48,7 +59,8 @@ object AxiModuleBuilder extends ModuleBuilder {
root = Paths.get(".").toAbsolutePath.resolve("ip").resolve("FifoAxiAdapterTest1").toString
)
),
( // generic adapter module FIFO -> AXI
ModuleDef( // generic adapter module FIFO -> AXI
None,
() => new FifoAxiAdapter(fifoDepth = 8),
CoreDefinition(
name = "FifoAxiAdapter",
......@@ -58,7 +70,8 @@ object AxiModuleBuilder extends ModuleBuilder {
root = Paths.get(".").toAbsolutePath.resolve("ip").resolve("FifoAxiAdapter").toString
)
),
( // generic adapter module AXI -> FIFO
ModuleDef( // generic adapter module AXI -> FIFO
None,
() => AxiFifoAdapter(fifoDepth = 4)
(Axi4.Configuration(addrWidth = AddrWidth(32),
dataWidth = DataWidth(32),
......@@ -71,7 +84,8 @@ object AxiModuleBuilder extends ModuleBuilder {
root = Paths.get(".").toAbsolutePath.resolve("ip").resolve("AxiFifoAdapter").toString
)
),
( // AXI-based sliding window
ModuleDef( // AXI-based sliding window
None,
() => {
implicit val axi = Axi4.Configuration(AddrWidth(32), DataWidth(64), IdWidth(1))
new AxiSlidingWindow(AxiSlidingWindowConfiguration(
......@@ -89,7 +103,8 @@ object AxiModuleBuilder extends ModuleBuilder {
root = root("AxiSlidingWindow")
)
),
( // AXI Crossbar
ModuleDef( // AXI Crossbar
None,
() => new AxiMux(8),
CoreDefinition(
name = "AxiMux",
......@@ -99,50 +114,20 @@ object AxiModuleBuilder extends ModuleBuilder {
root = root("AxiMux")
)
),
( // AXI Register File
() => {
new Axi4LiteRegisterFile(new Axi4LiteRegisterFileConfiguration(
regs = Map(0 -> new ConstantRegister(value = BigInt("10101010", 16)),
4 -> new ConstantRegister(value = BigInt("20202020", 16)),
8 -> new ConstantRegister(value = BigInt("30303030", 16)),
16 -> new ConstantRegister(value = BigInt("40404040", 16), bitfield = Map(
"Byte #3" -> BitRange(31, 24),
"Byte #2" -> BitRange(23, 16),
"Byte #1" -> BitRange(15, 8),
"Byte #0" -> BitRange(7, 0)
)))
))
},
CoreDefinition/*.withActions*/(
ModuleDef( // AXI Register File
Some(exampleRegisterFile),
() => new Axi4LiteRegisterFile(exampleRegisterFile),
CoreDefinition.withActions(
name = "Axi4LiteRegisterFile",
vendor = "esa.cs.tu-darmstadt.de",
library = "chisel",
version = "0.1",
root = root("Axi4LiteRegisterFile")/*,
root = root("Axi4LiteRegisterFile"),
postBuildActions = Seq(_ match {
case m: Axi4LiteRegisterFile => m.dumpAddressMap(root("Axi4LiteRegisterFile"))
})*/
)
)/*,
( // AXI4 Dummy
() => new chisel.axi.Dummy,
CoreDefinition(
name = "Axi4Dummy",
vendor = "esa.cs.tu-darmstadt.de",
library = "chisel",
version = "0.1",
root = root("Dummy")
)
),
( // AXI4Lite Dummy
() => new chisel.axi.Axi4Lite.Dummy,
CoreDefinition(
name = "Axi4LiteDummy",
vendor = "esa.cs.tu-darmstadt.de",
library = "chisel",
version = "0.1",
root = root("Dummy")
case Some(cfg: Axi4LiteRegisterFileConfiguration) => cfg.dumpAddressMap(root("Axi4LiteRegisterFile"))
case _ => ()
})
)
)*/
)
)
}
......@@ -142,11 +142,11 @@ object Axi4 {
}
class Master private (implicit cfg: Configuration) extends Bundle {
val writeAddr = Decoupled(new Address)
val writeData = Decoupled(new Data.Write)
val writeResp = Flipped(Decoupled(new WriteResponse))
val readAddr = Decoupled(new Address)
val readData = Flipped(Decoupled(new Data.Read))
val writeAddr = Irrevocable(new Address)
val writeData = Irrevocable(new Data.Write)
val writeResp = Flipped(Irrevocable(new WriteResponse))
val readAddr = Irrevocable(new Address)
val readData = Flipped(Irrevocable(new Data.Read))
override def cloneType = { new Master()(cfg).asInstanceOf[this.type] }
}
......
......@@ -50,11 +50,11 @@ object Axi4Lite {
}
class Master private (implicit cfg: Configuration) extends Bundle {
val writeAddr = Decoupled(new Address)
val writeData = Decoupled(new Data.Write)
val writeResp = Flipped(Decoupled(new WriteResponse))
val readAddr = Decoupled(new Address)
val readData = Flipped(Decoupled(new Data.Read))
val writeAddr = Irrevocable(new Address)
val writeData = Irrevocable(new Data.Write)
val writeResp = Flipped(Irrevocable(new WriteResponse))
val readAddr = Irrevocable(new Address)
val readData = Flipped(Irrevocable(new Data.Read))
override def cloneType = { new Master()(cfg).asInstanceOf[this.type] }
}
......
......@@ -25,6 +25,20 @@ case class Axi4LiteRegisterFileConfiguration(addrGranularity: Int = 32, regs: Ma
/** Minimum bit width of address lines. */
lazy val minAddrWidth: AddrWidth =
AddrWidth(Seq(log2Ceil(regs.size * axi.dataWidth.toInt / addrGranularity), log2Ceil(regs.keys.max)).max)
/** Dumps address map as markdown file. **/
def dumpAddressMap(path: String) = {
def mksz(s: String, w: Int) = if (s.length > w) s.take(w) else if (s.length < w) s + (" " * (w - s.length)) else s
val fw = new java.io.FileWriter(java.nio.file.Paths.get(path).resolve("AdressMap.md").toString)
fw.append("| **Name** |**From**|**To** | **Description** |").append(NL)
.append("|:----------------|:------:|:------:|:-----------------------------------------|").append(NL)
for (off <- regs.keys.toList.sorted; reg = regs(off))
fw.append("| %s | 0x%04x | 0x%04x | %s |".format(
mksz(reg.name.getOrElse("N/A"), 15), off, off + axi.dataWidth / 8 - 1, reg.description
)).append(NL)
fw.flush()
fw.close
}
}
/**
......@@ -45,20 +59,6 @@ class Axi4LiteRegisterFileIO(cfg: Axi4LiteRegisterFileConfiguration)(implicit ax
* @param axi Implicit AXI configuration.
**/
class Axi4LiteRegisterFile(cfg: Axi4LiteRegisterFileConfiguration)(implicit axi: Configuration) extends Module {
/** Dumps address map as markdown file. **/
def dumpAddressMap(path: String) = {
def mksz(s: String, w: Int) = if (s.length > w) s.take(w) else if (s.length < w) s + (" " * (w - s.length)) else s
val fw = new java.io.FileWriter(java.nio.file.Paths.get(path).resolve("AdressMap.md").toString)
fw.append("| **Name** |**From**|**To** | **Description** |").append(NL)
.append("|:----------------|:------:|:------:|:-----------------------------------------|").append(NL)
for (off <- cfg.regs.keys.toList.sorted; reg = cfg.regs(off))
fw.append("| %s | 0x%04x | 0x%04x | %s |".format(
mksz(reg.name.getOrElse("N/A"), 15), off, off + axi.dataWidth / 8 - 1, reg.description
)).append(NL)
fw.flush()
fw.close
}
/** HARDWARE **/
val io = IO(new Axi4LiteRegisterFileIO(cfg))
......
......@@ -17,7 +17,7 @@ sealed abstract class ControlRegister(_name: Option[String], bitfield: BitfieldM
def name: Option[String] = _name
/** Description of the register. */
def description: String = if (bitfield.size > 0) bf else _name.getOrElse("N/A")
def description: String = if (bitfield.size > 0) bf else _name.getOrElse("Reserved")
/** Access to named bit range. */
def apply(s: String): Option[UInt] = read() map { v =>
......
......@@ -16,22 +16,25 @@ class Axi2AxiModule(val fifoDepth: Int = 16, val size: Option[Int])
(implicit axi: Axi4.Configuration) extends Module {
require (size.isEmpty || log2Ceil(size.get) <= axi.addrWidth,
"size (%d) elements cannot be addressed by %d address bits".format(size.get, axi.addrWidth))
"size (%d) elements cannot be addressed by %d address bits".format(size.get, axi.addrWidth:Int))
val io = IO(new Bundle {
val deq = Decoupled(UInt(axi.dataWidth))
})
val sz = size.getOrElse(pow(2, axi.addrWidth.toDouble).toInt)
val sz = size.getOrElse(pow(2, axi.addrWidth.toDouble).toInt / axi.dataWidth)
val aw = Seq(axi.addrWidth:Int, log2Ceil(sz * (axi.dataWidth / 8))).min
println ("Axi2AxiModule: address bits = %d, size = %d".format(aw, sz))
val cfg = AxiSlaveModelConfiguration()
val data = 0 to sz map (n => n % pow(2, axi.dataWidth:Int).toInt)
val dsrc = Module(new DecoupledDataSource(
gen = UInt(axi.dataWidth),
size = sz,
//data = n => UInt((random * pow(2, axi.dataWidth)).toInt),
data = n => (n % pow(2, axi.dataWidth:Int).toInt).U,
//data = n => (n % pow(2, axi.dataWidth:Int).toInt).U,
data = data map (_.U),
repeat = false))
val fad = Module(new FifoAxiAdapter(fifoDepth = sz, burstSize = Some(fifoDepth)))
......@@ -45,7 +48,7 @@ class Axi2AxiModule(val fifoDepth: Int = 16, val size: Option[Int])
saxi.io.saxi.writeResp <> fad.io.maxi.writeResp
saxi.io.saxi.readAddr <> afa.io.maxi.readAddr
saxi.io.saxi.readData <> afa.io.maxi.readData
afa.reset := dsrc.io.out.valid || fad.fifo.io.count > 0.U
//afa.reset := dsrc.io.out.valid || fad.fifo.io.count > 0.U
fad.io.base := base
afa.io.base := base
io.deq <> afa.io.deq
......@@ -60,7 +63,7 @@ class Axi2AxiModule(val fifoDepth: Int = 16, val size: Option[Int])
class Axi2AxiTester(m: Axi2AxiModule)
(implicit axi: Axi4.Configuration) extends PeekPokeTester(m) {
def toBinaryString(v: BigInt): String =
"b%%%ds".format(axi.dataWidth).format(v.toString(2)).replace(' ', '0')
"b%%%ds".format(axi.dataWidth:Int).format(v.toString(2)).replace(' ', '0')
private val O = 10000
private var cc = 0
private var ccc = O
......@@ -79,7 +82,7 @@ class Axi2AxiTester(m: Axi2AxiModule)
for (i <- 0 until m.sz) {
while (peek(m.io.deq.valid) == 0) step (1)
val v = peek(m.io.deq.bits)
val e = m.dsrc.data(i)
val e = m.data(i)
expect (v == e, "mem[%08d] = %d (%s), expected: %d (%s)"
.format(i, v, toBinaryString(v), e, toBinaryString(e)))
step(1) // advance sim
......@@ -94,7 +97,7 @@ class Axi2AxiSuite extends ChiselFlatSpec {
def run(size: Int, fifoDepth: Int, addrWidth: Int, dataWidth: Int) {
implicit val axi = Axi4.Configuration(addrWidth = AddrWidth(addrWidth), dataWidth = DataWidth(dataWidth))
val dir = Paths.get("test")
.resolve("s%d_aw%d_dw%d".format(size, addrWidth, axi.dataWidth))
.resolve("s%d_aw%d_dw%d".format(size, addrWidth, axi.dataWidth:Int))
.toString
Driver.execute(Array("--fint-write-vcd", "--target-dir", dir),
() => new Axi2AxiModule(fifoDepth = fifoDepth,
......
package chisel.axiutils
import chisel3._
import chisel3.util._
import chisel.miscutils.generators._
import chisel3._, chisel3.util._
import chisel3.iotesters.{ChiselFlatSpec, Driver, PeekPokeTester}
import java.nio.file.Paths
import chisel.axi._
import org.scalacheck._, org.scalacheck.Prop._
import org.scalatest.prop.Checkers
class AxiFifoAdapterModule1(val fifoDepth: Int, val blockSize: Int)
(implicit axi: Axi4.Configuration) extends Module {
val addrWidth = log2Ceil(axi.dataWidth * fifoDepth * blockSize / 8)
val addrWidth = Seq(log2Ceil(axi.dataWidth * fifoDepth * blockSize / 8), 1).max
val cfg = AxiSlaveModelConfiguration(size = Some(Math.pow(2, addrWidth:Int).toInt))
val saxi = Module (new AxiSlaveModel(cfg))
val io = IO(new Bundle {
val dqr = Output(Bool())
val afa_en = Input(Bool())
val afa_deq_valid = Output(Bool())
val afa_deq_bits = Output(UInt(axi.dataWidth))
val saxi_debug = saxi.io.debug.cloneType
})
val afa = Module (AxiFifoAdapter(fifoDepth = fifoDepth))
val saxi = Module (new AxiSlaveModel(cfg))
val dqr = RegInit(true.B)
afa.io.base := 0.U
......@@ -25,11 +29,11 @@ class AxiFifoAdapterModule1(val fifoDepth: Int, val blockSize: Int)
dqr := io.dqr
io.afa_deq_valid := afa.io.deq.valid
io.afa_deq_bits := afa.io.deq.bits
io.saxi_debug <> saxi.io.debug
}
class AxiFifoAdapterModule1Test(m: AxiFifoAdapterModule1)
(implicit axi: Axi4.Configuration) extends PeekPokeTester(m) {
import scala.util.Properties.{lineSeparator => NL}
private var _cc = 0
// re-define step to output progress info
......@@ -39,15 +43,27 @@ class AxiFifoAdapterModule1Test(m: AxiFifoAdapterModule1)
if (cc % 1000 == 0) println("clock cycle: " + _cc)
}
poke(m.io.afa_en, false.B)
reset(10)
// setup data
println("prepping %d (%d x %d) mem elements ...".format(m.fifoDepth * m.blockSize, m.fifoDepth, m.blockSize))
for (i <- 0 until m.fifoDepth * m.blockSize)
pokeAt(m.saxi.mem, i % scala.math.pow(2, axi.dataWidth:Int).toInt, i)
poke(m.io.saxi_debug.r, false.B)
poke(m.io.saxi_debug.ra, 0)
poke(m.io.saxi_debug.w, true.B)
for (i <- 0 until m.fifoDepth * m.blockSize) {
poke(m.io.saxi_debug.wa, i % math.pow(2, axi.dataWidth:Int).toInt)
poke(m.io.saxi_debug.din, i)
step(1)
//pokeAt(m.saxi.mem, i % scala.math.pow(2, axi.dataWidth:Int).toInt, i)
}
poke(m.io.saxi_debug.w, false.B)
poke(m.io.saxi_debug.r, false.B)
poke(m.io.afa_en, true.B)
var res: List[BigInt] = List()
var cc: Int = m.fifoDepth * m.blockSize * 10 // upper bound on cycles
reset(10)
poke(m.io.dqr, true)
while (cc > 0 && res.length < m.fifoDepth * m.blockSize) {
if (peek(m.io.afa_deq_valid) != 0) {
......@@ -66,15 +82,20 @@ class AxiFifoAdapterModule1Test(m: AxiFifoAdapterModule1)
println("#%d: 0x%x (0b%s)".format(i, v, v.toString(2)))
})
for (i <- 0 until res.length if res(i) != peekAt(m.saxi.mem, i)) {
val msg = "Mem[%03d] = %d (expected %d)".format(i, res(i), peekAt(m.saxi.mem, i))
poke(m.io.saxi_debug.r, true.B)
step(1)
for (i <- 0 until res.length /*if res(i) != peekAt(m.saxi.mem, i)*/) {
poke(m.io.saxi_debug.ra, i)
step(1)
val v = peek(m.io.saxi_debug.dout)
val msg = "Mem[%03d] = %d (expected %d)".format(i, res(i), v)
println(msg)
expect(res(i) == peekAt(m.saxi.mem, i), msg)
expect(res(i) == v/*peekAt(m.saxi.mem, i)*/, msg)
}
}
class AxiFifoAdapterSuite extends ChiselFlatSpec {
def runTest(dataWidth: Int, fifoDepth: Int, blockSize: Int) {
class AxiFifoAdapterSuite extends ChiselFlatSpec with Checkers {
def runTest(dataWidth: Int, fifoDepth: Int, blockSize: Int): Boolean = {
val dir = Paths.get("test").resolve("dw%d_fd%d_bs%d".format(dataWidth, fifoDepth, blockSize)).toString
implicit val axi = Axi4.Configuration(dataWidth = DataWidth(dataWidth), addrWidth = AddrWidth(32))
Driver.execute(Array("--fint-write-vcd", "--target-dir", dir),
......@@ -82,13 +103,21 @@ class AxiFifoAdapterSuite extends ChiselFlatSpec {
{ m => new AxiFifoAdapterModule1Test(m) }
}
"checkDw32Fd1Bs256" should "be ok" in { runTest(dataWidth = 32, fifoDepth = 1, blockSize = 256/1) }
"checkDw32Fd8Bs32" should "be ok" in { runTest(dataWidth = 32, fifoDepth = 8, blockSize = 256/8) }
behavior of "AxiFifoAdapter"
/*it should "read data in correct order for arbitrary configurations" in
check(forAll(bitWidthGen(128), genLimited(1, 8) map (1 << _)) { case (bw, fd) =>
println("Testing with %d bit and %d FIFO depth".format(bw:Int, fd:Int))
runTest(bw, fd, 256)
})*/
it should "be ok" in { runTest(dataWidth = 32, fifoDepth = 1, blockSize = 256/1) }
/*"checkDw32Fd8Bs32" should "be ok" in { runTest(dataWidth = 32, fifoDepth = 8, blockSize = 256/8) }
"checkDw8Fd8Bs32" should "be ok" in { runTest(dataWidth = 8, fifoDepth = 8, blockSize = 256/8) }
"checkDw8Fd2Bs128" should "be ok" in { runTest(dataWidth = 8, fifoDepth = 2, blockSize = 256/2) }
"checkDw64Fd16Bs512" should "be ok" in { runTest(dataWidth = 64, fifoDepth = 16, blockSize = 512) }
"checkDw128Fd128Bs1024" should "be ok" in { runTest(dataWidth = 128, fifoDepth = 128, blockSize = 1024/128) }
// FIXME seems to work, but too slow
// "checkDw8Fd1080Bs480" should "be ok" in { runTest(dataWidth = 8, fifoDepth = 256, blockSize = 480*4) }
// "checkDw8Fd1080Bs480" should "be ok" in { runTest(dataWidth = 8, fifoDepth = 256, blockSize = 480*4) }*/
}
package chisel.axiutils
import chisel3._
import chisel3.util._
import chisel3._, chisel3.util._
import chisel3.iotesters.{PeekPokeTester}
import chisel.axi._
class DebugIO(implicit axi: Axi4.Configuration) extends Bundle {
val ra = Input(UInt(axi.addrWidth))
val r = Input(Bool())
val dout = Output(UInt(axi.dataWidth))
val wa = Input(UInt(axi.addrWidth))
val w = Input(Bool())
val din = Input(UInt(axi.dataWidth))
override def cloneType = { new DebugIO()(axi).asInstanceOf[this.type] }
}
class AxiSlaveModelIO(val cfg: AxiSlaveModelConfiguration)
(implicit axi: Axi4.Configuration) extends Bundle {
val saxi = Axi4.Slave(axi)
val saxi = Axi4.Slave(axi)
val debug = new DebugIO
override def cloneType = { new AxiSlaveModelIO(cfg)(axi).asInstanceOf[this.type] }
}
class AxiSlaveModel(val cfg: AxiSlaveModelConfiguration)
......@@ -15,7 +28,21 @@ class AxiSlaveModel(val cfg: AxiSlaveModelConfiguration)
println ("AxiSlaveModel: %s".format(cfg.toString))
val io = IO(new AxiSlaveModelIO(cfg))
val mem = Mem(sz, UInt(axi.dataWidth))
val mem = SyncReadMem(sz, UInt(axi.dataWidth))
/** DEBUG PROCESS **/
val d_read = io.debug.r
val d_write = RegNext(io.debug.w)
val d_waddr = RegNext(io.debug.wa)
val d_raddr = RegNext(io.debug.ra)
val d_din = RegNext(io.debug.din)
d_din := io.debug.din
when (d_read) {
io.debug.dout := mem.read(d_raddr)
}
when (d_write) {
mem.write(d_waddr, d_din)
}
/** WRITE PROCESS **/
val wa_valid = (io.saxi.writeAddr.valid)
......@@ -49,7 +76,8 @@ class AxiSlaveModel(val cfg: AxiSlaveModelConfiguration)
require (idx >= 0 && idx < cfg.size,
"AxiSlaveModel: read at invalid index %d (max: %d) for address 0x%x"
.format(idx, cfg.size - 1, address))
t.peekAt(mem, address / (axi.dataWidth / 8))
//t.peekAt(mem, address / (axi.dataWidth / 8))
BigInt(0)
}
/**
......@@ -62,7 +90,8 @@ class AxiSlaveModel(val cfg: AxiSlaveModelConfiguration)
require (index >= 0 && index < cfg.size,
"AxiSlaveModel: read at invalid index %d (max: %d)"
.format(index, cfg.size - 1))
t.peekAt(mem, index)
//t.peekAt(mem, index)
BigInt(0)
}
/**
......@@ -74,7 +103,7 @@ class AxiSlaveModel(val cfg: AxiSlaveModelConfiguration)
def set(address: Int, value: BigInt)(implicit t: PeekPokeTester[_]) = {
val idx = address / (axi.dataWidth / 8)
printf("AxiSlaveModel: set data at 0x%x (idx: %d) to 0x%x".format(address, value, idx))
t.pokeAt(mem, value, idx)
//t.pokeAt(mem, value, idx)
}
io.saxi.writeAddr.ready := !wa_hs
......@@ -106,7 +135,8 @@ class AxiSlaveModel(val cfg: AxiSlaveModelConfiguration)
when (wa_hs && wr_wait === 0.U) {
when (wa_hs && wd_valid && !wr_valid) {
val shifted_addr = if (axi.dataWidth > 8) wa >> log2Ceil(axi.dataWidth / 8).U else wa
mem(shifted_addr) := wd_data
//mem(shifted_addr) := wd_data
mem.write(shifted_addr, wd_data)
printf("writing data 0x%x to address 0x%x (0x%x)\n", wd_data, wa, shifted_addr)
when (io.saxi.writeData.bits.last || wl === 0.U) { wr_valid := true.B }
.otherwise {
......@@ -143,7 +173,7 @@ class AxiSlaveModel(val cfg: AxiSlaveModelConfiguration)
val rd_valid = ra_hs && rr_wait === 0.U
io.saxi.readData.valid := rd_valid
io.saxi.readData.bits.data := mem(if (axi.dataWidth > 8) ra >> (log2Ceil(axi.dataWidth / 8)).U else ra)
io.saxi.readData.bits.data := mem.read(if (axi.dataWidth > 8) ra >> (Seq(log2Ceil(axi.dataWidth / 8), 1).max).U else ra)
io.saxi.readData.bits.last := ra_hs && l === 0.U
io.saxi.readData.bits.resp := rr_resp
......
......@@ -36,7 +36,7 @@ object AxiSlaveModelConfiguration {
**/
def apply(size: Option[Int] = None, readDelay: Int = 30, writeDelay: Int = 120)
(implicit axi: Axi4.Configuration) = {
val sz: Int = size.getOrElse(scala.math.pow(2, axi.addrWidth.get).toInt)
val sz: Int = size.getOrElse(scala.math.pow(2, axi.addrWidth:Int).toInt / axi.dataWidth)
val aw: Int = Seq(axi.addrWidth:Int, log2Ceil(sz * axi.dataWidth / 8).toInt).min
new AxiSlaveModelConfiguration(size = sz, readDelay = readDelay, writeDelay = writeDelay)
}
......
package chisel.axiutils
import chisel3._
import chisel3.iotesters.PeekPokeTester
import chisel.axi._
/**
* Helper companion: Dump complete memory of slave into file.
**/
object AxiSlaveModelDumper {
/**
* Dumps the complete data of the AXI slave mode to a file.
* @param m The slave model to dump.
* @param filename Filename of dump file (paths will be created).
* @param lineWidth Number of bytes per line in file (default: 16).
* @param t Tester instance.
**/
def writeHexDump(m: AxiSlaveModel, filename: String, lineWidth: Int = 16)
(implicit t: PeekPokeTester[_]) {
require (lineWidth >= m.axi.dataWidth / 8, "lineWidth (%d) must be >= dataWidth / 8 (%d)"
.format(lineWidth, m.axi.dataWidth / 8))
require ((lineWidth * 8) % m.axi.dataWidth == 0,
"lineWidth (%d) must be evenly divisible by word width (%d)"
.format(lineWidth * 8, m.axi.dataWidth))
def hexAddr(addr: Int): String = "%%0%dx".format(m.axi.addrWidth / 4).format(addr)
def hexByte(v: Int): String = "%02x ".format(v)
def asciiByte(v: Int): String = "%c".format(v) take 1
def toBytes(v: BigInt): Seq[Int] = (for (i <- 0 until m.axi.dataWidth / 8) yield ((v >> (i * 8)) & 0xFF).toInt).reverse
def hexStr(vs: Seq[BigInt]): String = vs map toBytes reduce (_++_) map hexByte reduce (_++_)
def asciiStr(vs: Seq[BigInt]): String = vs map toBytes reduce (_++_) map asciiByte reduce (_++_)
def addrToIdx(addr: Int): Int = addr / (m.axi.dataWidth / 8)
def idxToAddr(idx: Int): Int = idx * (m.axi.dataWidth / 8)
java.nio.file.Paths.get(filename).toAbsolutePath.getParent.toFile.mkdirs()
val fw = new java.io.FileWriter(filename)
val lwords = (lineWidth * 8 / m.axi.dataWidth)
println("m.cfg.size = %d, lwords = %d".format(m.cfg.size, lwords))
for (idx <- 0 until m.cfg.size if idx % lwords == 0;
words = for (i <- 0 until lwords) yield t.peekAt(m.mem, idx + i)) {
fw.append("%s\t%s\t%s\n".format(hexAddr(idxToAddr(idx)), hexStr(words), asciiStr(words)))
}
fw.flush()