Commit decea9b9 authored by Jens Korinth's avatar Jens Korinth
Browse files

Pull tapasco-status-chisel

Merge commit 'f94b6de3' into pe-local-memories
parents d5704092 f94b6de3
# This file is a template, and might need editing before it works on your project.
# Official Java image. Look for the different tagged releases at
# https://hub.docker.com/r/library/java/tags/ . A Java image is not required
# but an image with a JVM speeds up the build a bit.
image: java:8
before_script:
# Enable the usage of sources over https
- apt-get update -yqq
- apt-get install apt-transport-https zip -yqq
# Add keyserver for SBT
- echo "deb http://dl.bintray.com/sbt/debian /" | tee -a /etc/apt/sources.list.d/sbt.list
- apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2EE0EA64E40A89B84B2DF73499E82A75642AC823
# Install SBT
- curl -s "https://get.sdkman.io" | bash
- source "/root/.sdkman/bin/sdkman-init.sh"
- sdk install sbt
# Log the sbt version and TaPaSCo version
- sbt sbtVersion version
test:
script:
# Execute your projects tests
- ./chiselSetup.sh
- sbt clean test
......@@ -7,4 +7,4 @@
/ip/
/packaging/target/
/miscutils/target/
*.pyc
......@@ -21,8 +21,7 @@ libraryDependencies ++= (Seq("chisel3","chisel-iotesters").map {
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % "3.0.4" % "test",
"org.scalacheck" %% "scalacheck" % "1.13.5" % "test",
"com.typesafe.play" %% "play-json" % "2.6.8",
"org.scalactic" %% "scalactic" % "3.0.4"
"com.typesafe.play" %% "play-json" % "2.6.8"
)
scalacOptions ++= Seq("-language:implicitConversions", "-language:reflectiveCalls", "-deprecation", "-feature")
......
......@@ -55,7 +55,7 @@ object RegisterFile {
**/
class IO(cfg: Configuration)(implicit axi: Axi4Lite.Configuration) extends Bundle {
val addrWidth: AddrWidth = AddrWidth(Seq(cfg.minAddrWidth:Int, axi.addrWidth:Int).max)
val saxi = Axi4Lite.Slave(axi.copy(addrWidth = addrWidth))
val s_axi = Axi4Lite.Slave(axi.copy(addrWidth = addrWidth))
override def cloneType = new IO(cfg)(axi).asInstanceOf[this.type]
}
......@@ -63,49 +63,49 @@ object RegisterFile {
def behavior(cfg: RegisterFile.Configuration, io: RegisterFile.IO)
(implicit axi: Axi4Lite.Configuration, logger: Logging, logLevel: Logging.Level) {
class ReadData extends Bundle {
val data = io.saxi.readData.bits.data.cloneType
val resp = io.saxi.readData.bits.resp.cloneType
val data = io.s_axi.readData.bits.data.cloneType
val resp = io.s_axi.readData.bits.resp.cloneType
override def cloneType = (new ReadData).asInstanceOf[this.type]
}
val in_q_ra = Module(new Queue(io.saxi.readAddr.bits.addr.cloneType, entries = cfg.fifoDepth, pipe = true))
val in_q_wa = Module(new Queue(io.saxi.writeAddr.bits.addr.cloneType, entries = cfg.fifoDepth, pipe = true))
val in_q_wd = Module(new Queue(io.saxi.writeData.bits.data.cloneType, entries = cfg.fifoDepth, pipe = true))
val in_q_ra = Module(new Queue(io.s_axi.readAddr.bits.addr.cloneType, entries = cfg.fifoDepth, pipe = true))
val in_q_wa = Module(new Queue(io.s_axi.writeAddr.bits.addr.cloneType, entries = cfg.fifoDepth, pipe = true))
val in_q_wd = Module(new Queue(io.s_axi.writeData.bits.data.cloneType, entries = cfg.fifoDepth, pipe = true))
val read_reg = Reg((new ReadData).cloneType)
val resp_reg = RegNext(Response.slverr, init = Response.slverr)
val out_q_rd = Module(new Queue((new ReadData).cloneType, cfg.fifoDepth))
val out_q_wr = Module(new Queue(io.saxi.writeResp.bits.bresp.cloneType, cfg.fifoDepth))
io.saxi.readData.bits.defaults
io.saxi.readData.valid := false.B
io.saxi.writeResp.bits.defaults
io.saxi.writeResp.valid := false.B
in_q_ra.io.enq.bits := io.saxi.readAddr.bits.addr
in_q_ra.io.enq.valid := io.saxi.readAddr.valid
io.saxi.readAddr.ready := in_q_ra.io.enq.ready
in_q_wa.io.enq.bits := io.saxi.writeAddr.bits.addr
in_q_wa.io.enq.valid := io.saxi.writeAddr.valid
io.saxi.writeAddr.ready := in_q_wa.io.enq.ready
in_q_wd.io.enq.bits := io.saxi.writeData.bits.data
in_q_wd.io.enq.valid := io.saxi.writeData.valid
io.saxi.writeData.ready := in_q_wd.io.enq.ready
val out_q_wr = Module(new Queue(io.s_axi.writeResp.bits.bresp.cloneType, cfg.fifoDepth))
io.s_axi.readData.bits.defaults
io.s_axi.readData.valid := false.B
io.s_axi.writeResp.bits.defaults
io.s_axi.writeResp.valid := false.B
in_q_ra.io.enq.bits := io.s_axi.readAddr.bits.addr
in_q_ra.io.enq.valid := io.s_axi.readAddr.valid
io.s_axi.readAddr.ready := in_q_ra.io.enq.ready
in_q_wa.io.enq.bits := io.s_axi.writeAddr.bits.addr
in_q_wa.io.enq.valid := io.s_axi.writeAddr.valid
io.s_axi.writeAddr.ready := in_q_wa.io.enq.ready
in_q_wd.io.enq.bits := io.s_axi.writeData.bits.data
in_q_wd.io.enq.valid := io.s_axi.writeData.valid
io.s_axi.writeData.ready := in_q_wd.io.enq.ready
val out_q_rd_enq_valid = RegNext(false.B, init = false.B)
out_q_rd.io.enq.bits := read_reg
out_q_rd.io.enq.valid := out_q_rd_enq_valid
out_q_rd.io.deq.ready := io.saxi.readData.ready
io.saxi.readData.bits.data := out_q_rd.io.deq.bits.data
io.saxi.readData.bits.resp := out_q_rd.io.deq.bits.resp
io.saxi.readData.valid := out_q_rd.io.deq.valid
out_q_rd.io.deq.ready := io.s_axi.readData.ready
io.s_axi.readData.bits.data := out_q_rd.io.deq.bits.data
io.s_axi.readData.bits.resp := out_q_rd.io.deq.bits.resp
io.s_axi.readData.valid := out_q_rd.io.deq.valid
val out_q_wr_enq_valid = RegNext(false.B, init = false.B)
out_q_wr.io.enq.bits := resp_reg
out_q_wr.io.enq.valid := out_q_wr_enq_valid
out_q_wr.io.deq.ready := io.saxi.writeResp.ready
io.saxi.writeResp.valid := out_q_wr.io.deq.valid
io.saxi.writeResp.bits.bresp := out_q_wr.io.deq.bits
out_q_wr.io.deq.ready := io.s_axi.writeResp.ready
io.s_axi.writeResp.valid := out_q_wr.io.deq.valid
io.s_axi.writeResp.bits.bresp := out_q_wr.io.deq.bits
in_q_ra.io.deq.ready := out_q_rd.io.enq.ready
......@@ -141,11 +141,11 @@ object RegisterFile {
def resetBehavior(io: RegisterFile.IO)(implicit module: Module) {
when (module.reset.toBool) { // this is required for AXI compliance; apparently Queues start working while reset is high
io.saxi.readAddr.ready := false.B
io.saxi.readData.valid := false.B
io.saxi.writeAddr.ready := false.B
io.saxi.writeData.ready := false.B
io.saxi.writeResp.valid := false.B
io.s_axi.readAddr.ready := false.B
io.s_axi.readData.valid := false.B
io.s_axi.writeAddr.ready := false.B
io.s_axi.writeData.ready := false.B
io.s_axi.writeResp.valid := false.B
}
}
}
......
......@@ -26,7 +26,7 @@ class RegFileTest(val size: Int, val off: Int, regs: Map[Long, ControlRegister],
val saxi = Module(new RegisterFile(cfg))
val m = Module(new ProgrammableMaster(actions))
val io = IO(new Bundle {
val rdata = Irrevocable(saxi.io.saxi.readData.bits.cloneType)
val rdata = Irrevocable(saxi.io.s_axi.readData.bits.cloneType)
val wresp = Irrevocable(new chisel.axi.Axi4Lite.WriteResponse)
val finished = Output(Bool())
})
......@@ -34,10 +34,10 @@ class RegFileTest(val size: Int, val off: Int, regs: Map[Long, ControlRegister],
m.io.restart := 0.U
m.io.out.ready := true.B
m.io.w_resp.ready := true.B
m.io.maxi <> saxi.io.saxi
m.io.maxi <> saxi.io.s_axi
io.finished := m.io.finished
io.wresp <> saxi.io.saxi.writeResp
io.rdata <> saxi.io.saxi.readData
io.wresp <> saxi.io.s_axi.writeResp
io.rdata <> saxi.io.s_axi.readData
}
/** Unit test suite for Axi4LiteRegisterFile module. **/
......
......@@ -42,4 +42,7 @@ chiselSetupTask := {
"./chiselSetup.sh" !
}
compile in Compile <<= (compile in Compile).dependsOn(chiselSetupTask)
(compile in Compile) := {
val x = chiselSetupTask.value
(compile in Compile).value
}
......@@ -28,5 +28,8 @@
}, {
"Domain" : "Memory",
"Frequency" : 200
} ]
}
\ No newline at end of file
} ],
"Capabilities" : {
"Capabilities 0" : 1
}
}
......@@ -14,67 +14,82 @@ object Builder {
implicit val axi: Axi4Lite.Configuration = Axi4Lite.Configuration(dataWidth = Axi4Lite.Width32,
addrWidth = AddrWidth(12))
private final val emptySlot = new ConstantRegister(Some("Empty Slot"), value = BigInt(0))
private def makeRegister(s: Slot): Seq[(Long, ControlRegister)] = s match {
case k: Slot.Kernel => Seq(
256L + s.slot * 16L -> new ConstantRegister(Some("Slot ${s.slot} Kernel ID"), value = BigInt(k.kernel)),
260L + s.slot * 16L -> new ConstantRegister(Some("Slot ${s.slot} Local Mem"), value = BigInt(0))
256L + s.slot * 16L -> new ConstantRegister(Some(s"Slot ${s.slot} Kernel ID"), value = BigInt(k.kernel)),
260L + s.slot * 16L -> new ConstantRegister(Some(s"Slot ${s.slot} Local Mem"), value = BigInt(0))
)
case m: Slot.Memory => Seq(
256L + s.slot * 16L -> new ConstantRegister(Some("Slot ${s.slot} Kernel ID"), value = BigInt(0)),
260L + s.slot * 16L -> new ConstantRegister(Some("Slot ${s.slot} Local Mem"), value = BigInt(m.size))
256L + s.slot * 16L -> new ConstantRegister(Some(s"Slot ${s.slot} Kernel ID"), value = BigInt(0)),
260L + s.slot * 16L -> new ConstantRegister(Some(s"Slot ${s.slot} Local Mem"), value = BigInt(m.size))
)
case k: Slot.Empty => Seq(
256L + s.slot * 16L -> emptySlot,
260L + s.slot * 16L -> emptySlot
)
}
private def fillEmptySlots(ss: Seq[Slot]): Seq[Slot] = {
val slotIds: Set[Int] = (ss map (_.slot: Int)).toSet
ss ++ (for (x <- 0 until NUM_SLOTS if !(slotIds.contains(x))) yield Slot.Empty(x))
}
def makeConfiguration(status: Status): RegisterFile.Configuration = RegisterFile.Configuration(
regs = (Seq[(Long, ControlRegister)](
0x00L -> new ConstantRegister(Some("Magic ID"), value = BigInt("E5AE1337", 16)),
0x04L -> new ConstantRegister(Some("Int Count"), value = BigInt(status.interruptControllers)),
0x08L -> new ConstantRegister(Some("Capabilities_0"), value = BigInt(0)), // FIXME CAPABILITIES_0
0x08L -> new ConstantRegister(Some("Capabilities_0"), value = BigInt(status.capabilities.cap0)),
0x10L -> new ConstantRegister(Some("Vivado Version"), value = BigInt(status.versions.vivado.toHex, 16)),
0x14L -> new ConstantRegister(Some("Vivado Version"), value = BigInt(status.versions.tapasco.toHex, 16)),
0x18L -> new ConstantRegister(Some("Bitstream Timestamp"), value = BigInt(status.timestamp)),
0x1CL -> new ConstantRegister(Some("Host Clock (Hz)"), value = BigInt(status.clocks.host.frequency.toLong)),
0x20L -> new ConstantRegister(Some("Design Clock (Hz)"), value = BigInt(status.clocks.design.frequency.toLong)),
0x24L -> new ConstantRegister(Some("Memory Clock (Hz)"), value = BigInt(status.clocks.memory.frequency.toLong))
) ++ ((status.config map (makeRegister _) fold Seq()) (_ ++ _))).toMap
) ++ ((fillEmptySlots(status.config) map (makeRegister _) fold Seq()) (_ ++ _))).toMap
)
private def makeBuilder(status: Status): chisel.packaging.ModuleBuilder = new chisel.packaging.ModuleBuilder {
private def makeBuilder(base: Path, status: Status): chisel.packaging.ModuleBuilder = new chisel.packaging.ModuleBuilder {
val configuration = makeConfiguration(status)
val modules: Seq[ModuleDef] = Seq(
ModuleDef(
None,
() => new RegisterFile(configuration),
CoreDefinition(
Some(configuration),
() => new RegisterFile(configuration) { override def desiredName = "tapasco_status" },
CoreDefinition.withActions(
name = "tapasco_status",
vendor = "esa.cs.tu-darmstadt.de",
library = "tapasco",
version = "1.2",
root = makePath(status).toString,
interfaces = Seq(Interface(name = "saxi", kind = "axi4slave"))
root = makePath(base, status).toString,
interfaces = Seq(Interface(name = "s_axi", kind = "axi4slave")),
postBuildActions = Seq(_ match {
case Some(cfg: RegisterFile.Configuration) => cfg.dumpAddressMap(makePath(base, status).toString)
case _ => ()
})
)
)
)
}
private def makePath(status: Status): Path =
Paths.get(".").toAbsolutePath.resolve("ip").resolve("%08x".format(status.hashCode)).normalize
private def makePath(base: Path, status: Status): Path = base.resolve("%08x".format(status.hashCode))
def main(args: Array[String]) {
require (args.length == 1, "expected exactly one argument: the name of the json configuration file")
require (args.length == 2, "expected exactly two arguments: the base path for IP cores and the name of the json configuration file")
try {
val json = Json.parse(Source.fromFile(args(0)).getLines mkString " ")
val base = Paths.get(args(0)).toAbsolutePath.normalize
val json = Json.parse(Source.fromFile(args(1)).getLines mkString " ")
val status: Status = Json.fromJson[Status](json).get
val hash = "%08x".format(status.hashCode)
val path = makePath(status)
val path = makePath(base, status)
println("Read configuration:")
println(Json.prettyPrint(json))
println("Status:")
println(status)
if (makePath(status).toFile.exists) {
if (path.toFile.exists) {
println(s"IP for configuration 0x$hash already exists, no need to build")
} else {
makeBuilder(status).main(Array("tapasco_status"))
makeBuilder(base, status).main(Array(base.toString, "tapasco_status"))
}
println(s"Finished, IP Core is located in $path")
} catch {
......
......@@ -60,13 +60,26 @@ package object json {
) (Memory.apply _)
/** Slot.Memory @} */
/** @{ Slot.Empty */
implicit val emptyWrites: Writes[Empty] = (
(JsPath \ "Type").write[String] ~
(JsPath \ "SlotId").write[SlotId]
) (e => ("Empty", e.slot))
val emptyReads: Reads[Slot] = (
(JsPath \ "Type").read[String] (verifying[String](_.toLowerCase equals "empty")) ~>
(JsPath \ "SlotId").read[SlotId]
) .fmap(Empty.apply _)
/** Slot.Empty @} */
/** @{ Slot */
implicit val slotReads: Reads[Slot] = kernelReads | memoryReads
implicit val slotReads: Reads[Slot] = kernelReads | memoryReads | emptyReads
implicit object SlotWrites extends Writes[Slot] {
def writes(c: Slot): JsValue = c match {
case k: Kernel => kernelWrites.writes(k)
case m: Memory => memoryWrites.writes(m)
case e: Empty => emptyWrites.writes(e)
}
}
/** Slot @} */
......@@ -153,13 +166,31 @@ package object json {
}
/** Clocks @} */
/** @{ Capabilities **/
implicit object CapBitsWrites extends Writes[CapBits] {
def reads(json: JsValue): JsResult[CapBits] = json match {
case JsNumber(d) => JsSuccess(d.toLong)
case _ => JsError(Seq(JsPath() -> Seq(JsonValidationError("validation.error.expected.jsnumber"))))
}
def writes(cs: CapBits): JsValue = JsNumber(cs)
}
implicit val capabilitiesReads: Reads[Capabilities] =
(JsPath \ "Capabilities 0").read[CapBits] fmap (Capabilities.apply _)
implicit object CapabilitiesWrites extends Writes[Capabilities] {
def writes(cs: Capabilities): JsValue = JsObject(Seq("Capabilities 0" -> Json.toJson(cs.cap0)))
}
/** Capabilities @} */
/** @{ Status */
implicit val statusFormat: Format[Status] = (
(JsPath \ "Composition").format[Seq[Slot]] ~
(JsPath \ "Timestamp").format[Int] ~
(JsPath \ "Interrupt Controllers").format[Int] ~
(JsPath \ "Versions").format[Versions] ~
(JsPath \ "Clocks").format[Clocks]
(JsPath \ "Clocks").format[Clocks] ~
(JsPath \ "Capabilities").format[Capabilities]
) (Status.apply _, unlift(Status.unapply _))
/** Status @} */
}
......
......@@ -54,19 +54,22 @@ package object tapasco_status {
}
}
sealed trait Slot {
def slot: SlotId
}
sealed trait Slot { def slot: SlotId }
object Slot {
final case class Kernel(slot: SlotId, kernel: KernelId) extends Slot
final case class Memory(slot: SlotId, size: Size) extends Slot
final case class Empty (slot: SlotId) extends Slot
}
type CapBits = Long
final case class Capabilities(cap0: CapBits)
final case class Status(config: Seq[Slot],
timestamp: Int,
interruptControllers: Int,
versions: Versions,
clocks: Clocks) {
clocks: Clocks,
capabilities: Capabilities) {
require (config.nonEmpty, "a status configuration must not be empty")
require ((config map (_.slot)).toSet.size == config.length, "slot ids must be unique")
}
......
......@@ -50,8 +50,13 @@ package object generators {
k <- genSize
} yield Slot.Memory(slotId getOrElse s, k)
implicit def genEmpty(slotId: Option[SlotId] = None): Gen[Slot.Empty] = for {
s <- genSlotId
} yield Slot.Empty(slotId getOrElse s)
implicit def genSlot(slotId: Option[SlotId] = None): Gen[Slot] = Gen.oneOf(genKernel(slotId),
genMemory(slotId))
genMemory(slotId),
genEmpty(slotId))
val genInterruptControllers: Gen[Int] = Gen.choose(1, 4)
......@@ -60,11 +65,18 @@ package object generators {
slots <- Gen.pick(n, Gen.lzy(genSlot(Some(0))), Gen.lzy(genSlot(Some(1))), 2 until NUM_SLOTS map (s => Gen.lzy(genSlot(Some(s)))):_*)
} yield slots
val genCapBits: Gen[CapBits] = Gen.choose(0L, (1L << 32) - 1)
val genCapabilities: Gen[Capabilities] = for {
cap0 <- genCapBits
} yield Capabilities(cap0)
implicit val genStatus: Gen[Status] = for {
config <- genConfig
timestamp <- genTimestamp
interruptControllers <- genInterruptControllers
versions <- genVersions
clocks <- genClocks
} yield Status(config, timestamp, interruptControllers, versions, clocks)
capabilities <- genCapabilities
} yield Status(config, timestamp, interruptControllers, versions, clocks, capabilities)
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment