From 3dfe43bf256bbda015b3c1081d7fa795314557ea Mon Sep 17 00:00:00 2001 From: Alon Amid Date: Thu, 7 Mar 2019 14:31:31 -0800 Subject: [PATCH 1/9] target sources for standalone firesim --- src/main/scala/TargetConfigs.scala | 157 +++++++++++++++++++++++++ src/main/scala/TargetMixins.scala | 93 +++++++++++++++ src/main/scala/Targets.scala | 181 +++++++++++++++++++++++++++++ 3 files changed, 431 insertions(+) create mode 100644 src/main/scala/TargetConfigs.scala create mode 100644 src/main/scala/TargetMixins.scala create mode 100755 src/main/scala/Targets.scala diff --git a/src/main/scala/TargetConfigs.scala b/src/main/scala/TargetConfigs.scala new file mode 100644 index 0000000..c914958 --- /dev/null +++ b/src/main/scala/TargetConfigs.scala @@ -0,0 +1,157 @@ +package firechip + +import freechips.rocketchip.config.{Parameters, Config} +import freechips.rocketchip.tile._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.devices.tilelink.BootROMParams +import boom.system.BoomTilesKey +import testchipip.{WithBlockDevice, BlockDeviceKey, BlockDeviceConfig} +import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTParams} +import icenet._ + +class WithBootROM extends Config((site, here, up) => { + case BootROMParams => BootROMParams( + contentFileName = s"./target-rtl/firechip/testchipip/bootrom/bootrom.rv${site(XLen)}.img") +}) + +class WithPeripheryBusFrequency(freq: BigInt) extends Config((site, here, up) => { + case PeripheryBusKey => up(PeripheryBusKey).copy(frequency=freq) +}) + +class WithUARTKey extends Config((site, here, up) => { + case PeripheryUARTKey => List(UARTParams( + address = BigInt(0x54000000L), + nTxEntries = 256, + nRxEntries = 256)) +}) + +class WithNICKey extends Config((site, here, up) => { + case NICKey => NICConfig( + inBufPackets = 64, + ctrlQueueDepth = 64) +}) + +class WithRocketL2TLBs(entries: Int) extends Config((site, here, up) => { + case RocketTilesKey => up(RocketTilesKey) map (tile => tile.copy( + core = tile.core.copy( + nL2TLBEntries = entries + ) + )) +}) + +class WithPerfCounters extends Config((site, here, up) => { + case RocketTilesKey => up(RocketTilesKey) map (tile => tile.copy( + core = tile.core.copy(nPerfCounters = 29) + )) +}) + +class WithBoomL2TLBs(entries: Int) extends Config((site, here, up) => { + case BoomTilesKey => up(BoomTilesKey) map (tile => tile.copy( + core = tile.core.copy(nL2TLBEntries = entries) + )) +}) + +class WithTraceRocket extends Config((site, here, up) => { + case RocketTilesKey => up(RocketTilesKey, site) map { r => r.copy(trace = true) } +}) + +class WithTraceBoom extends Config((site, here, up) => { + case BoomTilesKey => up(BoomTilesKey, site) map { r => r.copy(trace = true) } +}) + + +/******************************************************************************* +* Full TARGET_CONFIG configurations. These set parameters of the target being +* simulated. +* +* In general, if you're adding or removing features from any of these, you +* should CREATE A NEW ONE, WITH A NEW NAME. This is because the manager +* will store this name as part of the tags for the AGFI, so that later you can +* reconstruct what is in a particular AGFI. These tags are also used to +* determine which driver to build. +*******************************************************************************/ +class FireSimRocketChipConfig extends Config( + new WithBootROM ++ + new WithPeripheryBusFrequency(BigInt(3200000000L)) ++ + new WithExtMemSize(0x400000000L) ++ // 16GB + new WithoutTLMonitors ++ + new WithUARTKey ++ + new WithNICKey ++ + new WithBlockDevice ++ + new WithRocketL2TLBs(1024) ++ + new WithPerfCounters ++ + new freechips.rocketchip.system.DefaultConfig) + +class WithNDuplicatedRocketCores(n: Int) extends Config((site, here, up) => { + case RocketTilesKey => List.tabulate(n)(i => up(RocketTilesKey).head.copy(hartId = i)) +}) + +class FireSimRocketChipTracedConfig extends Config( + new WithTraceRocket ++ new FireSimRocketChipConfig) + +// single core config +class FireSimRocketChipSingleCoreConfig extends Config(new FireSimRocketChipConfig) + +class FireSimRocketChipSingleCoreTracedConfig extends Config( + new WithTraceRocket ++ new FireSimRocketChipSingleCoreConfig) + +// dual core config +class FireSimRocketChipDualCoreConfig extends Config( + new WithNDuplicatedRocketCores(2) ++ + new FireSimRocketChipSingleCoreConfig) + +class FireSimRocketChipDualCoreTracedConfig extends Config( + new WithTraceRocket ++ new FireSimRocketChipDualCoreConfig) + +// quad core config +class FireSimRocketChipQuadCoreConfig extends Config( + new WithNDuplicatedRocketCores(4) ++ + new FireSimRocketChipSingleCoreConfig) + +class FireSimRocketChipQuadCoreTracedConfig extends Config( + new WithTraceRocket ++ new FireSimRocketChipQuadCoreConfig) + +// hexa core config +class FireSimRocketChipHexaCoreConfig extends Config( + new WithNDuplicatedRocketCores(6) ++ + new FireSimRocketChipSingleCoreConfig) + +class FireSimRocketChipHexaCoreTracedConfig extends Config( + new WithTraceRocket ++ new FireSimRocketChipHexaCoreConfig) + +// octa core config +class FireSimRocketChipOctaCoreConfig extends Config( + new WithNDuplicatedRocketCores(8) ++ + new FireSimRocketChipSingleCoreConfig) + +class FireSimRocketChipOctaCoreTracedConfig extends Config( + new WithTraceRocket ++ new FireSimRocketChipOctaCoreConfig) + +class FireSimBoomConfig extends Config( + new WithBootROM ++ + new WithPeripheryBusFrequency(BigInt(3200000000L)) ++ + new WithExtMemSize(0x400000000L) ++ // 16GB + new WithoutTLMonitors ++ + new WithUARTKey ++ + new WithNICKey ++ + new WithBlockDevice ++ + new WithBoomL2TLBs(1024) ++ + //new WithBoomSynthAssertExcludes ++ // Will do nothing unless assertion synth is enabled + // Using a small config because it has 64-bit system bus, and compiles quickly + new boom.system.SmallBoomConfig) + +// A safer implementation than the one in BOOM in that it +// duplicates whatever BOOMTileKey.head is present N times. This prevents +// accidentally (and silently) blowing away configurations that may change the +// tile in the "up" view +class WithNDuplicatedBoomCores(n: Int) extends Config((site, here, up) => { + case BoomTilesKey => List.tabulate(n)(i => up(BoomTilesKey).head.copy(hartId = i)) +}) + +class FireSimBoomDualCoreConfig extends Config( + new WithNDuplicatedBoomCores(2) ++ + new FireSimBoomConfig) + +class FireSimBoomTracedConfig extends Config( + new WithTraceBoom ++ new FireSimBoomConfig) diff --git a/src/main/scala/TargetMixins.scala b/src/main/scala/TargetMixins.scala new file mode 100644 index 0000000..75d85ac --- /dev/null +++ b/src/main/scala/TargetMixins.scala @@ -0,0 +1,93 @@ +package firechip + +import chisel3._ +import freechips.rocketchip.config.{Field, Parameters} +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.amba.axi4._ +import freechips.rocketchip.util._ +import freechips.rocketchip.rocket.TracedInstruction +import boom.system.BoomSubsystem + +//import midas.models.AXI4BundleWithEdge + + +class TraceOutputTop(val numTraces: Int)(implicit val p: Parameters) extends Bundle { + val traces = Vec(numTraces, new TracedInstruction) +} + + +/* +/** Adds a port to the system intended to master an AXI4 DRAM controller. */ +trait CanHaveMisalignedMasterAXI4MemPort { this: BaseSubsystem => + val module: CanHaveMisalignedMasterAXI4MemPortModuleImp + + private val memPortParamsOpt = p(ExtMem) + private val portName = "axi4" + private val device = new MemoryDevice + val nMemoryChannels: Int + + val memAXI4Node = AXI4SlaveNode(Seq.tabulate(nMemoryChannels) { channel => + val params = memPortParamsOpt.get + val base = AddressSet.misaligned(params.base, params.size) + + AXI4SlavePortParameters( + slaves = Seq(AXI4SlaveParameters( + address = base, + resources = device.reg, + regionType = RegionType.UNCACHED, // cacheable + executable = true, + supportsWrite = TransferSizes(1, cacheBlockBytes), + supportsRead = TransferSizes(1, cacheBlockBytes), + interleavedId = Some(0))), // slave does not interleave read responses + beatBytes = params.beatBytes) + }) + + memPortParamsOpt.foreach { params => + memBuses.map { m => + memAXI4Node := m.toDRAMController(Some(portName)) { + (AXI4UserYanker() := AXI4IdIndexer(params.idBits) := TLToAXI4()) + } + } + } +} +*/ +/** Actually generates the corresponding IO in the concrete Module */ +/* +trait CanHaveMisalignedMasterAXI4MemPortModuleImp extends LazyModuleImp { + val outer: CanHaveMisalignedMasterAXI4MemPort + + val mem_axi4 = IO(new HeterogeneousBag(outer.memAXI4Node.in map AXI4BundleWithEdge.apply)) + (mem_axi4 zip outer.memAXI4Node.in).foreach { case (io, (bundle, _)) => io <> bundle } + + def connectSimAXIMem() { + (mem_axi4 zip outer.memAXI4Node.in).foreach { case (io, (_, edge)) => + val mem = LazyModule(new SimAXIMem(edge, size = p(ExtMem).get.size)) + Module(mem.module).io.axi4.head <> io + } + } +} +*/ + +trait CanHaveRocketTraceIO extends LazyModuleImp { + val outer: RocketSubsystem + + val traced_params = outer.rocketTiles(0).p + val tile_traces = outer.rocketTiles flatMap (tile => tile.module.trace.getOrElse(Nil)) + val traceIO = IO(Output(new TraceOutputTop(tile_traces.length)(traced_params))) + traceIO.traces zip tile_traces foreach ({ case (ioconnect, trace) => ioconnect := trace }) + + println(s"N tile traces: ${tile_traces.size}") +} + +trait CanHaveBoomTraceIO extends LazyModuleImp { + val outer: BoomSubsystem + + val traced_params = outer.boomTiles(0).p + val tile_traces = outer.boomTiles flatMap (tile => tile.module.trace.getOrElse(Nil)) + val traceIO = IO(Output(new TraceOutputTop(tile_traces.length)(traced_params))) + traceIO.traces zip tile_traces foreach ({ case (ioconnect, trace) => ioconnect := trace }) + + println(s"N tile traces: ${tile_traces.size}") +} diff --git a/src/main/scala/Targets.scala b/src/main/scala/Targets.scala new file mode 100755 index 0000000..a38d063 --- /dev/null +++ b/src/main/scala/Targets.scala @@ -0,0 +1,181 @@ +package firechip + +import chisel3._ +import freechips.rocketchip._ +import freechips.rocketchip.subsystem._ +import freechips.rocketchip.diplomacy.LazyModule +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.devices.tilelink._ +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.util.HeterogeneousBag +import freechips.rocketchip.amba.axi4.AXI4Bundle +import freechips.rocketchip.config.{Field, Parameters} +import freechips.rocketchip.diplomacy.LazyModule +import boom.system.{BoomSubsystem, BoomSubsystemModule} +import icenet._ +import testchipip._ +import testchipip.SerialAdapter.SERIAL_IF_WIDTH +import sifive.blocks.devices.uart._ +import midas.targetutils.ExcludeInstanceAssertsAnnotation +import java.io.File + +/******************************************************************************* +* Top level DESIGN configurations. These describe the basic instantiations of +* the designs being simulated. +* +* In general, if you're adding or removing features from any of these, you +* should CREATE A NEW ONE, WITH A NEW NAME. This is because the manager +* will store this name as part of the tags for the AGFI, so that later you can +* reconstruct what is in a particular AGFI. These tags are also used to +* determine which driver to build. +*******************************************************************************/ + +class FireSim(implicit p: Parameters) extends RocketSubsystem + //with CanHaveMisalignedMasterAXI4MemPort + with HasPeripheryBootROM +// with HasSystemErrorSlave + // with HasSyncExtInterrupts + with HasNoDebug + with HasPeripherySerial + with HasPeripheryUART + with HasPeripheryIceNIC + with HasPeripheryBlockDevice +{ + val hasTraces = rocketTiles.map(_.rocketParams.trace).reduce(_ || _) + + override lazy val module = new FireSimModuleImp(this) +// if (hasTraces) new FireSimModuleImpTraced(this) +// else new FireSimModuleImp(this) + + // Error device used for testing and to NACK invalid front port transactions + val error = LazyModule(new TLError(p(ErrorDeviceKey), sbus.beatBytes)) + // always buffer the error device because no one cares about its latency + sbus.coupleTo("slave_named_error"){ error.node := TLBuffer() := _ } +} + +class FireSimModuleImp[+L <: FireSim](l: L) extends RocketSubsystemModuleImp(l) + with HasRTCModuleImp + //with CanHaveMisalignedMasterAXI4MemPortModuleImp + with HasPeripheryBootROMModuleImp + // with HasExtInterruptsModuleImp + with HasNoDebugModuleImp + with HasPeripherySerialModuleImp + with HasPeripheryUARTModuleImp + with HasPeripheryIceNICModuleImpValidOnly + with HasPeripheryBlockDeviceModuleImp + +class FireSimModuleImpTraced[+L <: FireSim](l: L) extends FireSimModuleImp(l) + with CanHaveRocketTraceIO + +class FireSimNoNIC(implicit p: Parameters) extends RocketSubsystem + //with CanHaveMisalignedMasterAXI4MemPort + with HasPeripheryBootROM +// with HasSystemErrorSlave + // with HasSyncExtInterrupts + with HasNoDebug + with HasPeripherySerial + with HasPeripheryUART + with HasPeripheryBlockDevice +{ + val hasTraces = rocketTiles.map(_.rocketParams.trace).reduce(_ || _) + + override lazy val module = new FireSimNoNICModuleImp(this) +// if (hasTraces) new FireSimNoNICModuleImpTraced(this) +// else new FireSimNoNICModuleImp(this) + + // Error device used for testing and to NACK invalid front port transactions + val error = LazyModule(new TLError(p(ErrorDeviceKey), sbus.beatBytes)) + // always buffer the error device because no one cares about its latency + sbus.coupleTo("slave_named_error"){ error.node := TLBuffer() := _ } +} + +class FireSimNoNICModuleImp[+L <: FireSimNoNIC](l: L) extends RocketSubsystemModuleImp(l) + with HasRTCModuleImp + //with CanHaveMisalignedMasterAXI4MemPortModuleImp + with HasPeripheryBootROMModuleImp + // with HasExtInterruptsModuleImp + with HasNoDebugModuleImp + with HasPeripherySerialModuleImp + with HasPeripheryUARTModuleImp + with HasPeripheryBlockDeviceModuleImp + +class FireSimNoNICModuleImpTraced[+L <: FireSimNoNIC](l: L) extends FireSimNoNICModuleImp(l) + with CanHaveRocketTraceIO + +class FireBoom(implicit p: Parameters) extends BoomSubsystem + //with CanHaveMisalignedMasterAXI4MemPort + with HasPeripheryBootROM +// with HasSystemErrorSlave + // with HasSyncExtInterrupts + with HasNoDebug + with HasPeripherySerial + with HasPeripheryUART + with HasPeripheryIceNIC + with HasPeripheryBlockDevice +{ + val hasTraces = boomTiles.map(_.boomParams.trace).reduce(_ || _) + + override lazy val module = new FireBoomModuleImp(this) +// if (hasTraces) new FireBoomModuleImpTraced(this) +// else new FireBoomModuleImp(this) + + ExcludeInstanceAssertsAnnotation(("NonBlockingDCache", "dtlb")) + + // Error device used for testing and to NACK invalid front port transactions + val error = LazyModule(new TLError(p(ErrorDeviceKey), sbus.beatBytes)) + // always buffer the error device because no one cares about its latency + sbus.coupleTo("slave_named_error"){ error.node := TLBuffer() := _ } +} + +class FireBoomModuleImp[+L <: FireBoom](l: L) extends BoomSubsystemModule(l) + with HasRTCModuleImp + //with CanHaveMisalignedMasterAXI4MemPortModuleImp + with HasPeripheryBootROMModuleImp + // with HasExtInterruptsModuleImp + with HasNoDebugModuleImp + with HasPeripherySerialModuleImp + with HasPeripheryUARTModuleImp + with HasPeripheryIceNICModuleImpValidOnly + with HasPeripheryBlockDeviceModuleImp + +class FireBoomModuleImpTraced[+L <: FireBoom](l: L) extends FireBoomModuleImp(l) + with CanHaveBoomTraceIO + +class FireBoomNoNIC(implicit p: Parameters) extends BoomSubsystem + //with CanHaveMisalignedMasterAXI4MemPort + with HasPeripheryBootROM +// with HasSystemErrorSlave + // with HasSyncExtInterrupts + with HasNoDebug + with HasPeripherySerial + with HasPeripheryUART + with HasPeripheryBlockDevice +{ + val hasTraces = boomTiles.map(_.boomParams.trace).reduce(_ || _) + + override lazy val module = new FireBoomNoNICModuleImp(this) +// if (hasTraces) new FireBoomNoNICModuleImpTraced(this) +// else new FireBoomNoNICModuleImp(this) + + ExcludeInstanceAssertsAnnotation(("NonBlockingDCache", "dtlb")) + + // Error device used for testing and to NACK invalid front port transactions + val error = LazyModule(new TLError(p(ErrorDeviceKey), sbus.beatBytes)) + // always buffer the error device because no one cares about its latency + sbus.coupleTo("slave_named_error"){ error.node := TLBuffer() := _ } +} + +class FireBoomNoNICModuleImp[+L <: FireBoomNoNIC](l: L) extends BoomSubsystemModule(l) + with HasRTCModuleImp + //with CanHaveMisalignedMasterAXI4MemPortModuleImp + with HasPeripheryBootROMModuleImp + // with HasExtInterruptsModuleImp + with HasNoDebugModuleImp + with HasPeripherySerialModuleImp + with HasPeripheryUARTModuleImp + with HasPeripheryBlockDeviceModuleImp + +class FireBoomNoNICModuleImpTraced[+L <: FireBoomNoNIC](l: L) extends FireBoomNoNICModuleImp(l) + with CanHaveBoomTraceIO + + From 169cee4789c74c33611df77658f9c678e3d2e8a1 Mon Sep 17 00:00:00 2001 From: Alon Amid Date: Thu, 7 Mar 2019 14:31:57 -0800 Subject: [PATCH 2/9] firesim target decoupling --- build.sbt | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 25d8f87..acc1588 100644 --- a/build.sbt +++ b/build.sbt @@ -13,7 +13,8 @@ lazy val commonSettings = Seq( Resolver.sonatypeRepo("releases"), Resolver.mavenLocal)) -lazy val rocketchip = RootProject(file("rocket-chip")) +//lazy val rocketchip = RootProject(file("rocket-chip")) +lazy val rocketchip = ProjectRef(file("rocket-chip"), "rocketchip") lazy val sifive_blocks = (project in file("sifive-blocks")).settings(commonSettings).dependsOn(rocketchip) @@ -24,3 +25,18 @@ lazy val icenet = project.settings(commonSettings).dependsOn(rocketchip, testchi lazy val boom = project.settings(commonSettings).dependsOn(rocketchip) lazy val example = (project in file(".")).settings(commonSettings).dependsOn(boom, icenet, testchipip, sifive_blocks) + + +def dependOnProjectDir(prj: Project, dirs: Seq[File]): Project = { + for (d <- dirs) { + if (d.exists()) { + val realprj = (project in d) + return prj.dependsOn(realprj) + } + } + return prj +} + + + +lazy val firechip = dependOnProjectDir((project in file(".")).settings(commonSettings).dependsOn(boom, icenet, testchipip, sifive_blocks), Seq(file("../midas/targetutils/"))) From 1a6247813521522f47d61bcd8ed2934455ed9175 Mon Sep 17 00:00:00 2001 From: alonamid Date: Fri, 8 Mar 2019 07:14:54 -0800 Subject: [PATCH 3/9] move rc hack from fsim to fchip --- build.sbt | 61 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/build.sbt b/build.sbt index acc1588..b42780f 100644 --- a/build.sbt +++ b/build.sbt @@ -13,20 +13,6 @@ lazy val commonSettings = Seq( Resolver.sonatypeRepo("releases"), Resolver.mavenLocal)) -//lazy val rocketchip = RootProject(file("rocket-chip")) -lazy val rocketchip = ProjectRef(file("rocket-chip"), "rocketchip") - -lazy val sifive_blocks = (project in file("sifive-blocks")).settings(commonSettings).dependsOn(rocketchip) - -lazy val testchipip = project.settings(commonSettings).dependsOn(rocketchip) - -lazy val icenet = project.settings(commonSettings).dependsOn(rocketchip, testchipip) - -lazy val boom = project.settings(commonSettings).dependsOn(rocketchip) - -lazy val example = (project in file(".")).settings(commonSettings).dependsOn(boom, icenet, testchipip, sifive_blocks) - - def dependOnProjectDir(prj: Project, dirs: Seq[File]): Project = { for (d <- dirs) { if (d.exists()) { @@ -38,5 +24,50 @@ def dependOnProjectDir(prj: Project, dirs: Seq[File]): Project = { } +//lazy val rocketchip = RootProject(file("rocket-chip")) +//lazy val rocketchip = ProjectRef(file("rocket-chip"), "rocketchip") + +val rocketChipDir = file("rocket-chip") + +// Subproject definitions begin +// NB: FIRRTL dependency is unmanaged (and dropped in sim/lib) +lazy val chisel = (project in rocketChipDir / "chisel3") + +// Contains annotations & firrtl passes you may wish to use in rocket-chip without +// introducing a circular dependency between RC and MIDAS +lazy val midasTargetUtils = (project in file("midas/targetutils")) + .settings(commonSettings) + .dependsOn(chisel) + +// Rocket-chip dependencies (subsumes making RC a RootProject) +lazy val hardfloat = (project in rocketChipDir / "hardfloat") + .settings( + commonSettings, + crossScalaVersions := Seq("2.11.12", "2.12.4")) + .dependsOn(chisel, midasTargetUtils) +lazy val macros = (project in rocketChipDir / "macros") + .settings(commonSettings) + +// HACK: I'm strugging to override settings in rocket-chip's build.sbt (i want +// the subproject to register a new library dependendency on midas's targetutils library) +// So instead, avoid the existing build.sbt altogether and specify the project's root at src/ +lazy val rocketchip = dependOnProjectDir((project in rocketChipDir / "src") + .settings( + commonSettings, + scalaSource in Compile := baseDirectory.value / "main" / "scala", + resourceDirectory in Compile := baseDirectory.value / "main" / "resources") + .dependsOn(chisel, hardfloat, macros), + Seq(file("../../sim/midas/targetutils/"))) + + +lazy val sifive_blocks = (project in file("sifive-blocks")).settings(commonSettings).dependsOn(rocketchip) + +lazy val testchipip = project.settings(commonSettings).dependsOn(rocketchip) + +lazy val icenet = project.settings(commonSettings).dependsOn(rocketchip, testchipip) + +lazy val boom = project.settings(commonSettings).dependsOn(rocketchip) + +lazy val example = (project in file(".")).settings(commonSettings).dependsOn(boom, icenet, testchipip, sifive_blocks) -lazy val firechip = dependOnProjectDir((project in file(".")).settings(commonSettings).dependsOn(boom, icenet, testchipip, sifive_blocks), Seq(file("../midas/targetutils/"))) +lazy val firechip = (project in file(".")).settings(commonSettings).dependsOn(boom, icenet, testchipip, sifive_blocks) From a9ef9919808e4de4174caa15ae203f197cf77d65 Mon Sep 17 00:00:00 2001 From: alonamid Date: Fri, 8 Mar 2019 15:56:04 -0800 Subject: [PATCH 4/9] continue getting sbt --- build.sbt | 1 + project/build.properties | 1 + project/plugins.sbt | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+) create mode 100644 project/build.properties create mode 100644 project/plugins.sbt diff --git a/build.sbt b/build.sbt index b42780f..7834fd5 100644 --- a/build.sbt +++ b/build.sbt @@ -6,6 +6,7 @@ lazy val commonSettings = Seq( scalacOptions ++= Seq("-deprecation","-unchecked","-Xsource:2.11"), libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.1" % "test", libraryDependencies += "org.json4s" %% "json4s-native" % "3.5.3", + libraryDependencies += "org.json4s" %% "json4s-jackson" % "3.5.3", libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value, addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full), resolvers ++= Seq( diff --git a/project/build.properties b/project/build.properties new file mode 100644 index 0000000..31334bb --- /dev/null +++ b/project/build.properties @@ -0,0 +1 @@ +sbt.version=1.1.1 diff --git a/project/plugins.sbt b/project/plugins.sbt new file mode 100644 index 0000000..61fa965 --- /dev/null +++ b/project/plugins.sbt @@ -0,0 +1,19 @@ +resolvers += "jgit-repo" at "http://download.eclipse.org/jgit/maven" + +resolvers += "simplytyped" at "http://simplytyped.github.io/repo/releases" + +addSbtPlugin("com.typesafe.sbt" % "sbt-ghpages" % "0.6.2") + +addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.3.1") + +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.6") + +addSbtPlugin("com.simplytyped" % "sbt-antlr4" % "0.8.1") + +addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.7.0") + +addSbtPlugin("com.eed3si9n" % "sbt-unidoc" % "0.4.1") + +addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.9.3") + +addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.5.1") From 9283142ba5fd141207f1b88f2b3710e92122d02f Mon Sep 17 00:00:00 2001 From: alonamid Date: Mon, 11 Mar 2019 22:19:40 -0700 Subject: [PATCH 5/9] more build.sbt attempts --- build.sbt | 62 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/build.sbt b/build.sbt index 7834fd5..4f04085 100644 --- a/build.sbt +++ b/build.sbt @@ -14,17 +14,31 @@ lazy val commonSettings = Seq( Resolver.sonatypeRepo("releases"), Resolver.mavenLocal)) -def dependOnProjectDir(prj: Project, dirs: Seq[File]): Project = { - for (d <- dirs) { +def dependOnProjectDir(prj: Project, dirs: Seq[(File, String)]): Project = { + for ((d, dprj) <- dirs) { if (d.exists()) { - val realprj = (project in d) + //val realprj = (project in d) + val realprj = Project(dprj, d) return prj.dependsOn(realprj) } } + println(s"Did not find project midastargetutils in paths $dirs") return prj } +def volatileProjectDir(dirs: Seq[(File, String)]): Project = { + for ((d, dprj) <- dirs) { + if (d.exists()) { + val realprj = Project(dprj, d) + return realprj + } + } + println(s"Did not find project midastargetutils in paths $dirs") + val prj = (project in file("empty")) + return prj +} + //lazy val rocketchip = RootProject(file("rocket-chip")) //lazy val rocketchip = ProjectRef(file("rocket-chip"), "rocketchip") @@ -36,31 +50,59 @@ lazy val chisel = (project in rocketChipDir / "chisel3") // Contains annotations & firrtl passes you may wish to use in rocket-chip without // introducing a circular dependency between RC and MIDAS +/* lazy val midasTargetUtils = (project in file("midas/targetutils")) .settings(commonSettings) .dependsOn(chisel) - +*/ // Rocket-chip dependencies (subsumes making RC a RootProject) -lazy val hardfloat = (project in rocketChipDir / "hardfloat") +lazy val hardfloat = dependOnProjectDir((project in rocketChipDir / "hardfloat") .settings( commonSettings, - crossScalaVersions := Seq("2.11.12", "2.12.4")) - .dependsOn(chisel, midasTargetUtils) + crossScalaVersions := Seq("2.11.12", "2.12.4")), + Seq((file(System.getProperty("user.dir") + "/../../../sim/midas/targetutils/"), "midas-targetutils"), + (file(System.getProperty("user.dir") + "/midas/targetutils/"), "midas-targetutils"), + (file("/../../sim/midas/targetutils/"), "midas-targetutils"))) + .dependsOn(chisel) + + + lazy val macros = (project in rocketChipDir / "macros") .settings(commonSettings) // HACK: I'm strugging to override settings in rocket-chip's build.sbt (i want // the subproject to register a new library dependendency on midas's targetutils library) // So instead, avoid the existing build.sbt altogether and specify the project's root at src/ + + +lazy val rocketchip = (project in rocketChipDir / "src") + .settings( + commonSettings, + scalaSource in Compile := baseDirectory.value / "main" / "scala", + resourceDirectory in Compile := baseDirectory.value / "main" / "resources") + .dependsOn(chisel, hardfloat, macros) +/* lazy val rocketchip = dependOnProjectDir((project in rocketChipDir / "src") .settings( commonSettings, scalaSource in Compile := baseDirectory.value / "main" / "scala", resourceDirectory in Compile := baseDirectory.value / "main" / "resources") .dependsOn(chisel, hardfloat, macros), - Seq(file("../../sim/midas/targetutils/"))) - - + Seq((file(System.getProperty("user.dir") + "/../../../sim/midas/targetutils/"), "midas-targetutils"), + (file(System.getProperty("user.dir") + "/midas/targetutils/"), "midas-targetutils"), + (file("/../../sim/midas/targetutils/"), "midas-targetutils"))) +*/ +/* +lazy val rocketchip = (project in rocketChipDir / "src") + .settings( + commonSettings, + scalaSource in Compile := baseDirectory.value / "main" / "scala", + resourceDirectory in Compile := baseDirectory.value / "main" / "resources") + .dependsOn(volatileProjectDir(Seq((file(System.getProperty("user.dir") + "/../../../sim/midas/targetutils/"), "midas-targetutils"), + (file(System.getProperty("user.dir") + "/midas/targetutils/"), "midas-targetutils"), + (file("/../../sim/midas/targetutils/"), "midas-targetutils")))) + .dependsOn(chisel, hardfloat, macros) +*/ lazy val sifive_blocks = (project in file("sifive-blocks")).settings(commonSettings).dependsOn(rocketchip) lazy val testchipip = project.settings(commonSettings).dependsOn(rocketchip) From df14ee39849cefbcd4b64ad43321d459cefd2270 Mon Sep 17 00:00:00 2001 From: David Biancolin Date: Wed, 13 Mar 2019 04:08:49 +0000 Subject: [PATCH 6/9] Get a version of rebar compiling with FireSim as top --- build.sbt | 80 +++++++------------------------ src/main/scala/TargetMixins.scala | 19 +++++--- src/main/scala/Targets.scala | 64 ++++++++++++++++++++----- 3 files changed, 81 insertions(+), 82 deletions(-) diff --git a/build.sbt b/build.sbt index 4f04085..16b6749 100644 --- a/build.sbt +++ b/build.sbt @@ -14,95 +14,49 @@ lazy val commonSettings = Seq( Resolver.sonatypeRepo("releases"), Resolver.mavenLocal)) -def dependOnProjectDir(prj: Project, dirs: Seq[(File, String)]): Project = { - for ((d, dprj) <- dirs) { - if (d.exists()) { - //val realprj = (project in d) - val realprj = Project(dprj, d) - return prj.dependsOn(realprj) - } - } - println(s"Did not find project midastargetutils in paths $dirs") - return prj -} - - -def volatileProjectDir(dirs: Seq[(File, String)]): Project = { - for ((d, dprj) <- dirs) { - if (d.exists()) { - val realprj = Project(dprj, d) - return realprj - } - } - println(s"Did not find project midastargetutils in paths $dirs") - val prj = (project in file("empty")) - return prj -} - //lazy val rocketchip = RootProject(file("rocket-chip")) //lazy val rocketchip = ProjectRef(file("rocket-chip"), "rocketchip") val rocketChipDir = file("rocket-chip") +lazy val midasTargetUtilsDir = settingKey[Option[File]]("Location of MIDAS target annotations") +ThisBuild / midasTargetUtilsDir := Some(baseDirectory.value / "../../sim/midas/targetutils") + + // Subproject definitions begin // NB: FIRRTL dependency is unmanaged (and dropped in sim/lib) lazy val chisel = (project in rocketChipDir / "chisel3") // Contains annotations & firrtl passes you may wish to use in rocket-chip without // introducing a circular dependency between RC and MIDAS -/* -lazy val midasTargetUtils = (project in file("midas/targetutils")) - .settings(commonSettings) - .dependsOn(chisel) -*/ +lazy val midasTargetUtils = (project in file("dummy")) + .settings(commonSettings, + scalaSource in Compile := (midasTargetUtilsDir).value.get / "src" / "main" / "scala", + ).dependsOn(chisel) + // Rocket-chip dependencies (subsumes making RC a RootProject) -lazy val hardfloat = dependOnProjectDir((project in rocketChipDir / "hardfloat") +lazy val hardfloat = (project in rocketChipDir / "hardfloat") .settings( commonSettings, - crossScalaVersions := Seq("2.11.12", "2.12.4")), - Seq((file(System.getProperty("user.dir") + "/../../../sim/midas/targetutils/"), "midas-targetutils"), - (file(System.getProperty("user.dir") + "/midas/targetutils/"), "midas-targetutils"), - (file("/../../sim/midas/targetutils/"), "midas-targetutils"))) - .dependsOn(chisel) - + crossScalaVersions := Seq("2.11.12", "2.12.4")) + .dependsOn(chisel, midasTargetUtils) lazy val macros = (project in rocketChipDir / "macros") - .settings(commonSettings) + .settings(commonSettings, + ) // HACK: I'm strugging to override settings in rocket-chip's build.sbt (i want // the subproject to register a new library dependendency on midas's targetutils library) // So instead, avoid the existing build.sbt altogether and specify the project's root at src/ - lazy val rocketchip = (project in rocketChipDir / "src") .settings( commonSettings, scalaSource in Compile := baseDirectory.value / "main" / "scala", resourceDirectory in Compile := baseDirectory.value / "main" / "resources") .dependsOn(chisel, hardfloat, macros) -/* -lazy val rocketchip = dependOnProjectDir((project in rocketChipDir / "src") - .settings( - commonSettings, - scalaSource in Compile := baseDirectory.value / "main" / "scala", - resourceDirectory in Compile := baseDirectory.value / "main" / "resources") - .dependsOn(chisel, hardfloat, macros), - Seq((file(System.getProperty("user.dir") + "/../../../sim/midas/targetutils/"), "midas-targetutils"), - (file(System.getProperty("user.dir") + "/midas/targetutils/"), "midas-targetutils"), - (file("/../../sim/midas/targetutils/"), "midas-targetutils"))) -*/ -/* -lazy val rocketchip = (project in rocketChipDir / "src") - .settings( - commonSettings, - scalaSource in Compile := baseDirectory.value / "main" / "scala", - resourceDirectory in Compile := baseDirectory.value / "main" / "resources") - .dependsOn(volatileProjectDir(Seq((file(System.getProperty("user.dir") + "/../../../sim/midas/targetutils/"), "midas-targetutils"), - (file(System.getProperty("user.dir") + "/midas/targetutils/"), "midas-targetutils"), - (file("/../../sim/midas/targetutils/"), "midas-targetutils")))) - .dependsOn(chisel, hardfloat, macros) -*/ + lazy val sifive_blocks = (project in file("sifive-blocks")).settings(commonSettings).dependsOn(rocketchip) lazy val testchipip = project.settings(commonSettings).dependsOn(rocketchip) @@ -111,6 +65,4 @@ lazy val icenet = project.settings(commonSettings).dependsOn(rocketchip, testchi lazy val boom = project.settings(commonSettings).dependsOn(rocketchip) -lazy val example = (project in file(".")).settings(commonSettings).dependsOn(boom, icenet, testchipip, sifive_blocks) - -lazy val firechip = (project in file(".")).settings(commonSettings).dependsOn(boom, icenet, testchipip, sifive_blocks) +lazy val firechip = (project in file(".")).settings(commonSettings).dependsOn(boom, icenet, testchipip, sifive_blocks, midasTargetUtils) diff --git a/src/main/scala/TargetMixins.scala b/src/main/scala/TargetMixins.scala index 75d85ac..c204abb 100644 --- a/src/main/scala/TargetMixins.scala +++ b/src/main/scala/TargetMixins.scala @@ -9,7 +9,8 @@ import freechips.rocketchip.amba.axi4._ import freechips.rocketchip.util._ import freechips.rocketchip.rocket.TracedInstruction import boom.system.BoomSubsystem - +import midas.targetutils.ExcludeInstanceAsserts +// TODO: FIX THIS //import midas.models.AXI4BundleWithEdge @@ -17,8 +18,6 @@ class TraceOutputTop(val numTraces: Int)(implicit val p: Parameters) extends Bun val traces = Vec(numTraces, new TracedInstruction) } - -/* /** Adds a port to the system intended to master an AXI4 DRAM controller. */ trait CanHaveMisalignedMasterAXI4MemPort { this: BaseSubsystem => val module: CanHaveMisalignedMasterAXI4MemPortModuleImp @@ -52,13 +51,14 @@ trait CanHaveMisalignedMasterAXI4MemPort { this: BaseSubsystem => } } } -*/ + /** Actually generates the corresponding IO in the concrete Module */ -/* trait CanHaveMisalignedMasterAXI4MemPortModuleImp extends LazyModuleImp { val outer: CanHaveMisalignedMasterAXI4MemPort - val mem_axi4 = IO(new HeterogeneousBag(outer.memAXI4Node.in map AXI4BundleWithEdge.apply)) + // TODO: Resolve this dependency chain: RC (AXI4B) -> MIDAS (AXI4BWEdge) -> FC + //val mem_axi4 = IO(new HeterogeneousBag(outer.memAXI4Node.in map AXI4BundleWithEdge.apply)) + val mem_axi4 = IO(HeterogeneousBag.fromNode(outer.memAXI4Node.in)) (mem_axi4 zip outer.memAXI4Node.in).foreach { case (io, (bundle, _)) => io <> bundle } def connectSimAXIMem() { @@ -68,7 +68,6 @@ trait CanHaveMisalignedMasterAXI4MemPortModuleImp extends LazyModuleImp { } } } -*/ trait CanHaveRocketTraceIO extends LazyModuleImp { val outer: RocketSubsystem @@ -91,3 +90,9 @@ trait CanHaveBoomTraceIO extends LazyModuleImp { println(s"N tile traces: ${tile_traces.size}") } + +// Prevent MIDAS from synthesizing assertions in the dummy TLB included in BOOM +trait ExcludeInvalidBoomAssertions extends LazyModuleImp { + ExcludeInstanceAsserts(("NonBlockingDCache", "dtlb")) +} + diff --git a/src/main/scala/Targets.scala b/src/main/scala/Targets.scala index a38d063..d6e337f 100755 --- a/src/main/scala/Targets.scala +++ b/src/main/scala/Targets.scala @@ -19,6 +19,8 @@ import sifive.blocks.devices.uart._ import midas.targetutils.ExcludeInstanceAssertsAnnotation import java.io.File +case object NumNodes extends Field[Int] + /******************************************************************************* * Top level DESIGN configurations. These describe the basic instantiations of * the designs being simulated. @@ -31,7 +33,7 @@ import java.io.File *******************************************************************************/ class FireSim(implicit p: Parameters) extends RocketSubsystem - //with CanHaveMisalignedMasterAXI4MemPort + with CanHaveMisalignedMasterAXI4MemPort with HasPeripheryBootROM // with HasSystemErrorSlave // with HasSyncExtInterrupts @@ -55,7 +57,7 @@ class FireSim(implicit p: Parameters) extends RocketSubsystem class FireSimModuleImp[+L <: FireSim](l: L) extends RocketSubsystemModuleImp(l) with HasRTCModuleImp - //with CanHaveMisalignedMasterAXI4MemPortModuleImp + with CanHaveMisalignedMasterAXI4MemPortModuleImp with HasPeripheryBootROMModuleImp // with HasExtInterruptsModuleImp with HasNoDebugModuleImp @@ -68,7 +70,7 @@ class FireSimModuleImpTraced[+L <: FireSim](l: L) extends FireSimModuleImp(l) with CanHaveRocketTraceIO class FireSimNoNIC(implicit p: Parameters) extends RocketSubsystem - //with CanHaveMisalignedMasterAXI4MemPort + with CanHaveMisalignedMasterAXI4MemPort with HasPeripheryBootROM // with HasSystemErrorSlave // with HasSyncExtInterrupts @@ -91,7 +93,7 @@ class FireSimNoNIC(implicit p: Parameters) extends RocketSubsystem class FireSimNoNICModuleImp[+L <: FireSimNoNIC](l: L) extends RocketSubsystemModuleImp(l) with HasRTCModuleImp - //with CanHaveMisalignedMasterAXI4MemPortModuleImp + with CanHaveMisalignedMasterAXI4MemPortModuleImp with HasPeripheryBootROMModuleImp // with HasExtInterruptsModuleImp with HasNoDebugModuleImp @@ -103,7 +105,7 @@ class FireSimNoNICModuleImpTraced[+L <: FireSimNoNIC](l: L) extends FireSimNoNIC with CanHaveRocketTraceIO class FireBoom(implicit p: Parameters) extends BoomSubsystem - //with CanHaveMisalignedMasterAXI4MemPort + with CanHaveMisalignedMasterAXI4MemPort with HasPeripheryBootROM // with HasSystemErrorSlave // with HasSyncExtInterrupts @@ -119,7 +121,7 @@ class FireBoom(implicit p: Parameters) extends BoomSubsystem // if (hasTraces) new FireBoomModuleImpTraced(this) // else new FireBoomModuleImp(this) - ExcludeInstanceAssertsAnnotation(("NonBlockingDCache", "dtlb")) + //ExcludeInstanceAssertsAnnotation(("NonBlockingDCache", "dtlb")) // Error device used for testing and to NACK invalid front port transactions val error = LazyModule(new TLError(p(ErrorDeviceKey), sbus.beatBytes)) @@ -129,7 +131,7 @@ class FireBoom(implicit p: Parameters) extends BoomSubsystem class FireBoomModuleImp[+L <: FireBoom](l: L) extends BoomSubsystemModule(l) with HasRTCModuleImp - //with CanHaveMisalignedMasterAXI4MemPortModuleImp + with CanHaveMisalignedMasterAXI4MemPortModuleImp with HasPeripheryBootROMModuleImp // with HasExtInterruptsModuleImp with HasNoDebugModuleImp @@ -137,12 +139,13 @@ class FireBoomModuleImp[+L <: FireBoom](l: L) extends BoomSubsystemModule(l) with HasPeripheryUARTModuleImp with HasPeripheryIceNICModuleImpValidOnly with HasPeripheryBlockDeviceModuleImp + with ExcludeInvalidBoomAssertions class FireBoomModuleImpTraced[+L <: FireBoom](l: L) extends FireBoomModuleImp(l) with CanHaveBoomTraceIO class FireBoomNoNIC(implicit p: Parameters) extends BoomSubsystem - //with CanHaveMisalignedMasterAXI4MemPort + with CanHaveMisalignedMasterAXI4MemPort with HasPeripheryBootROM // with HasSystemErrorSlave // with HasSyncExtInterrupts @@ -157,8 +160,6 @@ class FireBoomNoNIC(implicit p: Parameters) extends BoomSubsystem // if (hasTraces) new FireBoomNoNICModuleImpTraced(this) // else new FireBoomNoNICModuleImp(this) - ExcludeInstanceAssertsAnnotation(("NonBlockingDCache", "dtlb")) - // Error device used for testing and to NACK invalid front port transactions val error = LazyModule(new TLError(p(ErrorDeviceKey), sbus.beatBytes)) // always buffer the error device because no one cares about its latency @@ -167,15 +168,56 @@ class FireBoomNoNIC(implicit p: Parameters) extends BoomSubsystem class FireBoomNoNICModuleImp[+L <: FireBoomNoNIC](l: L) extends BoomSubsystemModule(l) with HasRTCModuleImp - //with CanHaveMisalignedMasterAXI4MemPortModuleImp + with CanHaveMisalignedMasterAXI4MemPortModuleImp with HasPeripheryBootROMModuleImp // with HasExtInterruptsModuleImp with HasNoDebugModuleImp with HasPeripherySerialModuleImp with HasPeripheryUARTModuleImp with HasPeripheryBlockDeviceModuleImp + with ExcludeInvalidBoomAssertions class FireBoomNoNICModuleImpTraced[+L <: FireBoomNoNIC](l: L) extends FireBoomNoNICModuleImp(l) with CanHaveBoomTraceIO +class SupernodeIO( + nNodes: Int, + serialWidth: Int, + bagPrototype: HeterogeneousBag[AXI4Bundle])(implicit p: Parameters) + extends Bundle { + val serial = Vec(nNodes, new SerialIO(serialWidth)) + val mem_axi = Vec(nNodes, bagPrototype.cloneType) + val bdev = Vec(nNodes, new BlockDeviceIO) + val net = Vec(nNodes, new NICIOvonly) + val uart = Vec(nNodes, new UARTPortIO) + + override def cloneType = new SupernodeIO(nNodes, serialWidth, bagPrototype).asInstanceOf[this.type] +} + + +class FireSimSupernode(implicit p: Parameters) extends Module { + val nNodes = p(NumNodes) + val nodes = Seq.fill(nNodes) { + Module(LazyModule(new FireSim).module) + } + + val io = IO(new SupernodeIO(nNodes, SERIAL_IF_WIDTH, nodes(0).mem_axi4)) + + io.mem_axi.zip(nodes.map(_.mem_axi4)).foreach { + case (out, mem_axi4) => out <> mem_axi4 + } + io.serial <> nodes.map(_.serial) + io.bdev <> nodes.map(_.bdev) + io.net <> nodes.map(_.net) + io.uart <> nodes.map(_.uart(0)) + nodes.foreach{ case n => { + n.debug.clockeddmi.get.dmi.req.valid := false.B + n.debug.clockeddmi.get.dmi.resp.ready := false.B + n.debug.clockeddmi.get.dmiClock := clock + n.debug.clockeddmi.get.dmiReset := reset.toBool + n.debug.clockeddmi.get.dmi.req.bits.data := DontCare + n.debug.clockeddmi.get.dmi.req.bits.addr := DontCare + n.debug.clockeddmi.get.dmi.req.bits.op := DontCare + } } +} From 5d48fdeed47fa304e33f163d78c11b9797a830a4 Mon Sep 17 00:00:00 2001 From: David Biancolin Date: Sat, 16 Mar 2019 01:54:30 +0000 Subject: [PATCH 7/9] wip --- .gitmodules | 6 ++++++ Makefrag | 15 +++++++++------ build.sbt | 26 ++++++++++++++------------ firesim | 1 + tools/firrtl | 1 + 5 files changed, 31 insertions(+), 18 deletions(-) create mode 160000 firesim create mode 160000 tools/firrtl diff --git a/.gitmodules b/.gitmodules index 340826f..3dd7b40 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,9 @@ [submodule "boom"] path = boom url = https://github.com/ucb-bar/riscv-boom.git +[submodule "firesim"] + path = firesim + url = https://github.com/firesim/firesim.git +[submodule "tools/firrtl"] + path = tools/firrtl + url = https://github.com/freechipsproject/firrtl.git diff --git a/Makefrag b/Makefrag index 786eb81..03e1f6e 100644 --- a/Makefrag +++ b/Makefrag @@ -6,15 +6,18 @@ lookup_scala_srcs = $(shell find $(1)/ -iname "*.scala" 2> /dev/null) PACKAGES=rocket-chip testchipip icenet sifive-blocks SCALA_SOURCES=$(foreach pkg,$(PACKAGES),$(call lookup_scala_srcs,$(base_dir)/$(pkg)/src/main/scala)) $(call lookup_scala_srcs,$(base_dir)/src/main/scala) -ROCKET_CLASSES ?= "$(ROCKETCHIP_DIR)/target/scala-2.12/classes:$(ROCKETCHIP_DIR)/chisel3/target/scala-2.12/*" +# NB: The rocketchip hack below +ROCKET_CLASSES ?= $(ROCKETCHIP_DIR)/src/target/scala-2.12/classes:$(ROCKETCHIP_DIR)/chisel3/target/scala-2.12/* -FIRRTL_JAR ?= $(ROCKETCHIP_DIR)/lib/firrtl.jar +FIRRTL_DIR ?= $(base_dir)/tools/firrtl +FIRRTL_JAR ?= $(base_dir)/lib/firrtl.jar +# TODO: FIXME FIRRTL ?= java -Xmx2G -Xss8M -XX:MaxPermSize=256M -cp $(ROCKET_CLASSES):$(FIRRTL_JAR) firrtl.Driver -$(FIRRTL_JAR): $(call lookup_scala_srcs, $(ROCKETCHIP_DIR)/firrtl/src/main/scala) - $(MAKE) -C $(ROCKETCHIP_DIR)/firrtl SBT="$(SBT)" root_dir=$(ROCKETCHIP_DIR)/firrtl build-scala - mkdir -p $(ROCKETCHIP_DIR)/lib - cp $(ROCKETCHIP_DIR)/firrtl/utils/bin/firrtl.jar $(FIRRTL_JAR) +$(FIRRTL_JAR): $(call lookup_scala_srcs, $(FIRRTL_DIR)/src/main/scala) + $(MAKE) -C $(FIRRTL_DIR) SBT="$(SBT)" root_dir=$(FIRRTL_DIR) build-scala + mkdir -p $(@D) + cp $(FIRRTL_DIR)/utils/bin/firrtl.jar $(FIRRTL_JAR) build_dir=$(sim_dir)/generated-src testchip_dir = $(base_dir)/testchipip diff --git a/build.sbt b/build.sbt index 16b6749..791cd98 100644 --- a/build.sbt +++ b/build.sbt @@ -14,14 +14,14 @@ lazy val commonSettings = Seq( Resolver.sonatypeRepo("releases"), Resolver.mavenLocal)) -//lazy val rocketchip = RootProject(file("rocket-chip")) -//lazy val rocketchip = ProjectRef(file("rocket-chip"), "rocketchip") - val rocketChipDir = file("rocket-chip") -lazy val midasTargetUtilsDir = settingKey[Option[File]]("Location of MIDAS target annotations") -ThisBuild / midasTargetUtilsDir := Some(baseDirectory.value / "../../sim/midas/targetutils") - +lazy val firesimAsLibrary = sys.env.get("FIRESIM_IS_TOP") == None +lazy val firesimDir = if (firesimAsLibrary) { + file("firesim/sim/") +} else { + file("../../sim/") +} // Subproject definitions begin // NB: FIRRTL dependency is unmanaged (and dropped in sim/lib) @@ -29,10 +29,8 @@ lazy val chisel = (project in rocketChipDir / "chisel3") // Contains annotations & firrtl passes you may wish to use in rocket-chip without // introducing a circular dependency between RC and MIDAS -lazy val midasTargetUtils = (project in file("dummy")) - .settings(commonSettings, - scalaSource in Compile := (midasTargetUtilsDir).value.get / "src" / "main" / "scala", - ).dependsOn(chisel) +lazy val midasTargetUtils = (project in firesimDir / "midas/targetutils") + .settings(commonSettings).dependsOn(chisel) // Rocket-chip dependencies (subsumes making RC a RootProject) lazy val hardfloat = (project in rocketChipDir / "hardfloat") @@ -55,7 +53,7 @@ lazy val rocketchip = (project in rocketChipDir / "src") commonSettings, scalaSource in Compile := baseDirectory.value / "main" / "scala", resourceDirectory in Compile := baseDirectory.value / "main" / "resources") - .dependsOn(chisel, hardfloat, macros) + .dependsOn(chisel, hardfloat, macros) lazy val sifive_blocks = (project in file("sifive-blocks")).settings(commonSettings).dependsOn(rocketchip) @@ -65,4 +63,8 @@ lazy val icenet = project.settings(commonSettings).dependsOn(rocketchip, testchi lazy val boom = project.settings(commonSettings).dependsOn(rocketchip) -lazy val firechip = (project in file(".")).settings(commonSettings).dependsOn(boom, icenet, testchipip, sifive_blocks, midasTargetUtils) +lazy val firechip = (project in file(".")) + .settings(commonSettings) + .dependsOn(boom, icenet, testchipip, sifive_blocks, midasTargetUtils) + +lazy val firesim = RootProject(file("firesim/sim")) diff --git a/firesim b/firesim new file mode 160000 index 0000000..bb10c96 --- /dev/null +++ b/firesim @@ -0,0 +1 @@ +Subproject commit bb10c963ee4fd327ebaee4aff0dd82f5e5ab0c02 diff --git a/tools/firrtl b/tools/firrtl new file mode 160000 index 0000000..380c233 --- /dev/null +++ b/tools/firrtl @@ -0,0 +1 @@ +Subproject commit 380c233b43c2de53b0ee15a39e9364d438066b9f From 30f9589c30abdd596b7b2a48dcfc0e6b00bc3e81 Mon Sep 17 00:00:00 2001 From: David Biancolin Date: Wed, 20 Mar 2019 07:03:54 +0000 Subject: [PATCH 8/9] Can run FireSim tests out of rebar --- Makefrag | 7 +- build.sbt | 8 +- firesim | 2 +- src/main/scala/firesim/Generator.scala | 122 +++++++++ src/main/scala/firesim/SimConfigs.scala | 131 +++++++++ .../scala/{ => firesim}/TargetConfigs.scala | 17 +- .../scala/firesim/TargetLandTestSuites.scala | 45 ++++ .../scala/{ => firesim}/TargetMixins.scala | 2 +- src/main/scala/{ => firesim}/Targets.scala | 2 +- .../firesim/endpoints/BlockDevWidget.scala | 255 ++++++++++++++++++ .../firesim/endpoints/SerialWidget.scala | 72 +++++ .../firesim/endpoints/SimpleNICWidget.scala | 249 +++++++++++++++++ .../firesim/endpoints/TracerVWidget.scala | 75 ++++++ .../scala/firesim/endpoints/UARTWidget.scala | 129 +++++++++ src/test/scala/firesim/ScalaTestSuite.scala | 118 ++++++++ 15 files changed, 1223 insertions(+), 11 deletions(-) create mode 100755 src/main/scala/firesim/Generator.scala create mode 100644 src/main/scala/firesim/SimConfigs.scala rename src/main/scala/{ => firesim}/TargetConfigs.scala (92%) create mode 100644 src/main/scala/firesim/TargetLandTestSuites.scala rename src/main/scala/{ => firesim}/TargetMixins.scala (99%) rename src/main/scala/{ => firesim}/Targets.scala (99%) create mode 100644 src/main/scala/firesim/endpoints/BlockDevWidget.scala create mode 100644 src/main/scala/firesim/endpoints/SerialWidget.scala create mode 100644 src/main/scala/firesim/endpoints/SimpleNICWidget.scala create mode 100644 src/main/scala/firesim/endpoints/TracerVWidget.scala create mode 100644 src/main/scala/firesim/endpoints/UARTWidget.scala create mode 100644 src/test/scala/firesim/ScalaTestSuite.scala diff --git a/Makefrag b/Makefrag index 03e1f6e..e7548fd 100644 --- a/Makefrag +++ b/Makefrag @@ -1,10 +1,13 @@ ROCKETCHIP_DIR=$(base_dir)/rocket-chip -SBT ?= java -Xmx2G -Xss8M -XX:MaxPermSize=256M -jar $(ROCKETCHIP_DIR)/sbt-launch.jar ++2.12.4 +SBT ?= java -Xmx16G -Xss8M -XX:MaxPermSize=256M -jar $(ROCKETCHIP_DIR)/sbt-launch.jar ++2.12.4 lookup_scala_srcs = $(shell find $(1)/ -iname "*.scala" 2> /dev/null) -PACKAGES=rocket-chip testchipip icenet sifive-blocks +PACKAGES=testchipip icenet sifive-blocks \ + $(addprefix firesim/sim/, . midas midas/targetutils) \ + $(addprefix $(ROCKETCHIP_DIR)/, . hardfloat) + SCALA_SOURCES=$(foreach pkg,$(PACKAGES),$(call lookup_scala_srcs,$(base_dir)/$(pkg)/src/main/scala)) $(call lookup_scala_srcs,$(base_dir)/src/main/scala) # NB: The rocketchip hack below ROCKET_CLASSES ?= $(ROCKETCHIP_DIR)/src/target/scala-2.12/classes:$(ROCKETCHIP_DIR)/chisel3/target/scala-2.12/* diff --git a/build.sbt b/build.sbt index 791cd98..2c96f11 100644 --- a/build.sbt +++ b/build.sbt @@ -63,8 +63,10 @@ lazy val icenet = project.settings(commonSettings).dependsOn(rocketchip, testchi lazy val boom = project.settings(commonSettings).dependsOn(rocketchip) +// The library components of FireSim +lazy val firesim = ProjectRef(firesimDir, "common") + lazy val firechip = (project in file(".")) .settings(commonSettings) - .dependsOn(boom, icenet, testchipip, sifive_blocks, midasTargetUtils) - -lazy val firesim = RootProject(file("firesim/sim")) + .dependsOn(boom, icenet, testchipip, sifive_blocks, midasTargetUtils, + firesim % "test->test;compile->compile") diff --git a/firesim b/firesim index bb10c96..83e9096 160000 --- a/firesim +++ b/firesim @@ -1 +1 @@ -Subproject commit bb10c963ee4fd327ebaee4aff0dd82f5e5ab0c02 +Subproject commit 83e9096bb81ba99e11dedf32d2aef6474edcf80e diff --git a/src/main/scala/firesim/Generator.scala b/src/main/scala/firesim/Generator.scala new file mode 100755 index 0000000..2c30cd6 --- /dev/null +++ b/src/main/scala/firesim/Generator.scala @@ -0,0 +1,122 @@ +package firesim.firesim + +import java.io.{File} + +import chisel3.experimental.RawModule +import chisel3.internal.firrtl.{Circuit, Port} + +import freechips.rocketchip.diplomacy.{ValName, AutoBundle} +import freechips.rocketchip.devices.debug.DebugIO +import freechips.rocketchip.util.{HasGeneratorUtilities, ParsedInputNames, ElaborationArtefacts} +import freechips.rocketchip.system.DefaultTestSuites._ +import freechips.rocketchip.system.{TestGeneration, RegressionTestSuite} +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.subsystem.RocketTilesKey +import freechips.rocketchip.tile.XLen + +import boom.system.{BoomTilesKey, BoomTestSuites} + +import firesim.util.{GeneratorArgs, HasTargetAgnosticUtilites, HasFireSimGeneratorUtilities} + +trait HasTestSuites { + val rv64RegrTestNames = collection.mutable.LinkedHashSet( + "rv64ud-v-fcvt", + "rv64ud-p-fdiv", + "rv64ud-v-fadd", + "rv64uf-v-fadd", + "rv64um-v-mul", + // "rv64mi-p-breakpoint", // Not implemented in BOOM + // "rv64uc-v-rvc", // Not implemented in BOOM + "rv64ud-v-structural", + "rv64si-p-wfi", + "rv64um-v-divw", + "rv64ua-v-lrsc", + "rv64ui-v-fence_i", + "rv64ud-v-fcvt_w", + "rv64uf-v-fmin", + "rv64ui-v-sb", + "rv64ua-v-amomax_d", + "rv64ud-v-move", + "rv64ud-v-fclass", + "rv64ua-v-amoand_d", + "rv64ua-v-amoxor_d", + "rv64si-p-sbreak", + "rv64ud-v-fmadd", + "rv64uf-v-ldst", + "rv64um-v-mulh", + "rv64si-p-dirty") + + val rv32RegrTestNames = collection.mutable.LinkedHashSet( + "rv32mi-p-ma_addr", + "rv32mi-p-csr", + "rv32ui-p-sh", + "rv32ui-p-lh", + "rv32uc-p-rvc", + "rv32mi-p-sbreak", + "rv32ui-p-sll") + + def addTestSuites(targetName: String, params: Parameters) { + val coreParams = + if (params(RocketTilesKey).nonEmpty) { + params(RocketTilesKey).head.core + } else { + params(BoomTilesKey).head.core + } + val xlen = params(XLen) + val vm = coreParams.useVM + val env = if (vm) List("p","v") else List("p") + coreParams.fpu foreach { case cfg => + if (xlen == 32) { + TestGeneration.addSuites(env.map(rv32uf)) + if (cfg.fLen >= 64) + TestGeneration.addSuites(env.map(rv32ud)) + } else { + TestGeneration.addSuite(rv32udBenchmarks) + TestGeneration.addSuites(env.map(rv64uf)) + if (cfg.fLen >= 64) + TestGeneration.addSuites(env.map(rv64ud)) + } + } + if (coreParams.useAtomics) TestGeneration.addSuites(env.map(if (xlen == 64) rv64ua else rv32ua)) + if (coreParams.useCompressed) TestGeneration.addSuites(env.map(if (xlen == 64) rv64uc else rv32uc)) + val (rvi, rvu) = + if (params(BoomTilesKey).nonEmpty) ((if (vm) BoomTestSuites.rv64i else BoomTestSuites.rv64pi), rv64u) + else if (xlen == 64) ((if (vm) rv64i else rv64pi), rv64u) + else ((if (vm) rv32i else rv32pi), rv32u) + + TestGeneration.addSuites(rvi.map(_("p"))) + TestGeneration.addSuites((if (vm) List("v") else List()).flatMap(env => rvu.map(_(env)))) + TestGeneration.addSuite(benchmarks) + TestGeneration.addSuite(new RegressionTestSuite(if (xlen == 64) rv64RegrTestNames else rv32RegrTestNames)) + TestGeneration.addSuite(FastBlockdevTests) + TestGeneration.addSuite(SlowBlockdevTests) + if (!targetName.contains("NoNIC")) + TestGeneration.addSuite(NICLoopbackTests) + } +} + +// Mixed into an App or into a TestSuite +trait IsFireSimGeneratorLike extends HasFireSimGeneratorUtilities with HasTestSuites { + /** Output software test Makefrags, which provide targets for integration testing. */ + def generateTestSuiteMakefrags { + addTestSuites(names.topModuleClass, targetParams) + writeOutputFile(s"$longName.d", TestGeneration.generateMakefrag) // Subsystem-specific test suites + } + + // Output miscellaneous files produced as a side-effect of elaboration + def generateArtefacts { + ElaborationArtefacts.files.foreach { case (extension, contents) => + writeOutputFile(s"${longName}.${extension}", contents ()) + } + } +} + +object FireSimGenerator extends App with IsFireSimGeneratorLike { + lazy val generatorArgs = GeneratorArgs(args) + lazy val genDir = new File(names.targetDir) + + elaborateAndCompileWithMidas + generateTestSuiteMakefrags + generateHostVerilogHeader + generateArtefacts +} diff --git a/src/main/scala/firesim/SimConfigs.scala b/src/main/scala/firesim/SimConfigs.scala new file mode 100644 index 0000000..6d0a398 --- /dev/null +++ b/src/main/scala/firesim/SimConfigs.scala @@ -0,0 +1,131 @@ +package firesim.firesim + +import freechips.rocketchip.config.{Parameters, Config, Field} + +import midas.{EndpointKey} +import midas.widgets.{EndpointMap} +import midas.models._ + +import testchipip.{WithBlockDevice} + +import firesim.endpoints._ +import firesim.configs._ + +class WithSerialWidget extends Config((site, here, up) => { + case EndpointKey => up(EndpointKey) ++ EndpointMap(Seq(new SimSerialIO)) +}) + +class WithUARTWidget extends Config((site, here, up) => { + case EndpointKey => up(EndpointKey) ++ EndpointMap(Seq(new SimUART)) +}) + +class WithSimpleNICWidget extends Config((site, here, up) => { + case EndpointKey => up(EndpointKey) ++ EndpointMap(Seq(new SimSimpleNIC)) + case LoopbackNIC => false +}) + +class WithBlockDevWidget extends Config((site, here, up) => { + case EndpointKey => up(EndpointKey) ++ EndpointMap(Seq(new SimBlockDev)) +}) + +class WithTracerVWidget extends Config((site, here, up) => { + case midas.EndpointKey => up(midas.EndpointKey) ++ + EndpointMap(Seq(new SimTracerV)) +}) + +/******************************************************************************* +* Full PLATFORM_CONFIG Configurations. These set simulator parameters. +* +* In general, if you're adding or removing features from any of these, you +* should CREATE A NEW ONE, WITH A NEW NAME. This is because the manager +* will store this name as part of the tags for the AGFI, so that later you can +* reconstruct what is in a particular AGFI. These tags are also used to +* determine which driver to build. +*******************************************************************************/ +class FireSimConfig extends Config( + new WithDesiredHostFrequency(90) ++ + new WithSerialWidget ++ + new WithUARTWidget ++ + new WithSimpleNICWidget ++ + new WithBlockDevWidget ++ + new WithDefaultMemModel ++ + new WithTracerVWidget ++ + new BasePlatformConfig) + +class FireSimConfig160MHz extends Config( + new WithDesiredHostFrequency(160) ++ + new FireSimConfig) + +class FireSimConfig90MHz extends Config( + new WithDesiredHostFrequency(90) ++ + new FireSimConfig) + +class FireSimConfig75MHz extends Config( + new WithDesiredHostFrequency(75) ++ + new FireSimConfig) + +class FireSimClockDivConfig extends Config( + new WithDesiredHostFrequency(90) ++ + new WithSerialWidget ++ + new WithUARTWidget ++ + new WithSimpleNICWidget ++ + new WithBlockDevWidget ++ + new WithDefaultMemModel(clockDivision = 2) ++ + new BasePlatformConfig) + +class FireSimDDR3Config extends Config( + new WithDesiredHostFrequency(90) ++ + new WithSerialWidget ++ + new WithUARTWidget ++ + new WithSimpleNICWidget ++ + new WithBlockDevWidget ++ + new FCFS16GBQuadRank ++ + new BasePlatformConfig) + +class FireSimDDR3LLC4MBConfig extends Config( + new WithDesiredHostFrequency(90) ++ + new WithSerialWidget ++ + new WithUARTWidget ++ + new WithSimpleNICWidget ++ + new WithBlockDevWidget ++ + new FCFS16GBQuadRankLLC4MB ++ + new BasePlatformConfig) + +class FireSimDDR3FRFCFSConfig extends Config( + new WithDesiredHostFrequency(90) ++ + new WithSerialWidget ++ + new WithUARTWidget ++ + new WithSimpleNICWidget ++ + new WithBlockDevWidget ++ + new FRFCFS16GBQuadRank ++ + new BasePlatformConfig) + +class FireSimDDR3FRFCFSLLC4MBConfig extends Config( + new WithDesiredHostFrequency(90) ++ + new WithSerialWidget ++ + new WithUARTWidget ++ + new WithSimpleNICWidget ++ + new WithBlockDevWidget ++ + new FRFCFS16GBQuadRankLLC4MB ++ + new BasePlatformConfig) + +class FireSimDDR3FRFCFSLLC4MBConfig160MHz extends Config( + new WithDesiredHostFrequency(160) ++ + new FireSimDDR3FRFCFSLLC4MBConfig) + +class FireSimDDR3FRFCFSLLC4MBConfig90MHz extends Config( + new WithDesiredHostFrequency(90) ++ + new FireSimDDR3FRFCFSLLC4MBConfig) + +class FireSimDDR3FRFCFSLLC4MBConfig75MHz extends Config( + new WithDesiredHostFrequency(75) ++ + new FireSimDDR3FRFCFSLLC4MBConfig) + +class FireSimDDR3FRFCFSLLC4MB3ClockDivConfig extends Config( + new WithDesiredHostFrequency(90) ++ + new WithSerialWidget ++ + new WithUARTWidget ++ + new WithSimpleNICWidget ++ + new WithBlockDevWidget ++ + new FRFCFS16GBQuadRankLLC4MB3Div ++ + new BasePlatformConfig) diff --git a/src/main/scala/TargetConfigs.scala b/src/main/scala/firesim/TargetConfigs.scala similarity index 92% rename from src/main/scala/TargetConfigs.scala rename to src/main/scala/firesim/TargetConfigs.scala index c914958..2c38050 100644 --- a/src/main/scala/TargetConfigs.scala +++ b/src/main/scala/firesim/TargetConfigs.scala @@ -1,4 +1,6 @@ -package firechip +package firesim.firesim + +import java.io.File import freechips.rocketchip.config.{Parameters, Config} import freechips.rocketchip.tile._ @@ -11,8 +13,17 @@ import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTParams} import icenet._ class WithBootROM extends Config((site, here, up) => { - case BootROMParams => BootROMParams( - contentFileName = s"./target-rtl/firechip/testchipip/bootrom/bootrom.rv${site(XLen)}.img") + case BootROMParams => { + val rebarBootROM = new File(s"./testchipip/bootrom/bootrom.rv${site(XLen)}.img") + val firesimBootROM = new File(s"./target-rtl/testchipip/bootrom/bootrom.rv${site(XLen)}.img") + + val bootROMPath = if (rebarBootROM.exists()) { + rebarBootROM.getAbsolutePath() + } else { + firesimBootROM.getAbsolutePath() + } + BootROMParams(contentFileName = bootROMPath) + } }) class WithPeripheryBusFrequency(freq: BigInt) extends Config((site, here, up) => { diff --git a/src/main/scala/firesim/TargetLandTestSuites.scala b/src/main/scala/firesim/TargetLandTestSuites.scala new file mode 100644 index 0000000..b20fa8d --- /dev/null +++ b/src/main/scala/firesim/TargetLandTestSuites.scala @@ -0,0 +1,45 @@ +//See LICENSE for license details. +package firesim.firesim + +import scala.collection.mutable.LinkedHashSet + +import freechips.rocketchip.system.{TestGeneration, RocketTestSuite} + +/* This imports tests from FireChip to test devices that aren't natively + * tested by the riscv assembly tests. + * Firesim's target-specific makefrag gives the recipes for building the + * binaries. + */ + +class BlockdevTestSuite(prefix: String, val names: LinkedHashSet[String]) extends RocketTestSuite { + val envName = "" + // fc_test_dir is is defined in firesim's Makefrag + val dir = "$(fc_test_dir)" + val makeTargetName = prefix + "-blkdev-tests" + def kind = "blockdev" + // Blockdev tests need an image, which complicates this + def additionalArgs = "+blkdev-in-mem0=128 +nic-loopback0" + override def toString = s"$makeTargetName = \\\n" + + // Make variable with the binaries of the suite + names.map(n => s"\t$n.riscv").mkString(" \\\n") + "\n\n" + + // Variables with binary specific arguments + names.map(n => s"$n.riscv_ARGS=$additionalArgs").mkString(" \n") + + postScript +} + +object FastBlockdevTests extends BlockdevTestSuite("fast", LinkedHashSet("blkdev")) +object SlowBlockdevTests extends BlockdevTestSuite("slow", LinkedHashSet("big-blkdev")) + +class NICTestSuite(prefix: String, val names: LinkedHashSet[String]) extends RocketTestSuite { + val envName = "" + val dir = "$(fc_test_dir)" + val makeTargetName = prefix + "-nic-tests" + def kind = "nic" + def additionalArgs = "+netbw0=100 +linklatency0=6405 +netburst0=8 +slotid=0 +nic-loopback0" + override def toString = s"$makeTargetName = \\\n" + + names.map(n => s"\t$n.riscv").mkString(" \\\n") + "\n\n" + + names.map(n => s"$n.riscv_ARGS=$additionalArgs").mkString(" \n") + + postScript +} + +object NICLoopbackTests extends NICTestSuite("loopback", LinkedHashSet("nic-loopback")) diff --git a/src/main/scala/TargetMixins.scala b/src/main/scala/firesim/TargetMixins.scala similarity index 99% rename from src/main/scala/TargetMixins.scala rename to src/main/scala/firesim/TargetMixins.scala index c204abb..5a86250 100644 --- a/src/main/scala/TargetMixins.scala +++ b/src/main/scala/firesim/TargetMixins.scala @@ -1,4 +1,4 @@ -package firechip +package firesim.firesim import chisel3._ import freechips.rocketchip.config.{Field, Parameters} diff --git a/src/main/scala/Targets.scala b/src/main/scala/firesim/Targets.scala similarity index 99% rename from src/main/scala/Targets.scala rename to src/main/scala/firesim/Targets.scala index d6e337f..2937697 100755 --- a/src/main/scala/Targets.scala +++ b/src/main/scala/firesim/Targets.scala @@ -1,4 +1,4 @@ -package firechip +package firesim.firesim import chisel3._ import freechips.rocketchip._ diff --git a/src/main/scala/firesim/endpoints/BlockDevWidget.scala b/src/main/scala/firesim/endpoints/BlockDevWidget.scala new file mode 100644 index 0000000..3c9f1fa --- /dev/null +++ b/src/main/scala/firesim/endpoints/BlockDevWidget.scala @@ -0,0 +1,255 @@ +package firesim +package endpoints + +import chisel3._ +import chisel3.util._ +import chisel3.experimental.{DataMirror, Direction} +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.util.DecoupledHelper + +import midas.core.{HostPort, IsRationalClockRatio, UnityClockRatio} +import midas.widgets._ +import midas.models.DynamicLatencyPipe +import testchipip.{BlockDeviceIO, BlockDeviceRequest, BlockDeviceData, BlockDeviceInfo, HasBlockDeviceParameters, BlockDeviceKey} + +class SimBlockDev( + override val clockRatio: IsRationalClockRatio = UnityClockRatio) + extends Endpoint { + def matchType(data: Data) = data match { + case channel: BlockDeviceIO => + DataMirror.directionOf(channel.req.valid) == Direction.Output + case _ => false + } + def widget(p: Parameters) = new BlockDevWidget()(p) + override def widgetName = "BlockDevWidget" +} + +class BlockDevWidgetIO(implicit val p: Parameters) extends EndpointWidgetIO()(p) { + val hPort = Flipped(HostPort(new BlockDeviceIO)) +} + +class BlockDevWidget(implicit p: Parameters) extends EndpointWidget()(p) { + // TODO use HasBlockDeviceParameters + val blockDevExternal = p(BlockDeviceKey) + val dataBytes = 512 + val sectorBits = 32 + val nTrackers = blockDevExternal.nTrackers + val tagBits = log2Up(nTrackers) + val nTrackerBits = log2Up(nTrackers+1) + val dataBitsPerBeat = 64 + val dataBeats = (dataBytes * 8) / dataBitsPerBeat // A transaction is thus dataBeats * len beats long + val sectorSize = log2Ceil(sectorBits/8) + val beatIdxBits = log2Ceil(dataBeats) + val pAddrBits = 32 // TODO: Make configurable somehow + // Timing parameters + val latencyBits = 24 + val defaultReadLatency = (1 << 8).U(latencyBits.W) + val defaultWriteLatency = (1 << 8).U(latencyBits.W) + + val io = IO(new BlockDevWidgetIO) + + val reqBuf = Module(new Queue(new BlockDeviceRequest, 10)) + val dataBuf = Module(new Queue(new BlockDeviceData, 32)) + + val rRespBuf = Module(new Queue(new BlockDeviceData, 32)) + val wAckBuf = Module(new Queue(UInt(tagBits.W), 4)) + + val target = io.hPort.hBits + val channelCtrlSignals = Seq(io.hPort.toHost.hValid, + io.hPort.fromHost.hReady, + io.tReset.valid) + val rRespStallN = Wire(Bool()) // Unset if the SW model hasn't returned the response data in time + val wAckStallN = Wire(Bool()) // As above, but with a write acknowledgement + val fixMeOnNextRocketBump = true.B + val tFireHelper = DecoupledHelper((channelCtrlSignals ++ Seq( + reqBuf.io.enq.ready, + dataBuf.io.enq.ready, + fixMeOnNextRocketBump, + rRespStallN, + wAckStallN)):_*) + + val tFire = tFireHelper.fire(fixMeOnNextRocketBump) // Dummy argument to get conjunction of all signals + // Decoupled helper can't exclude two bools unfortunately... + val targetReset = channelCtrlSignals.reduce(_ && _) && io.tReset.bits + + reqBuf.reset := reset.toBool || targetReset + dataBuf.reset := reset.toBool || targetReset + rRespBuf.reset := reset.toBool || targetReset + wAckBuf.reset := reset.toBool || targetReset + + io.hPort.toHost.hReady := tFireHelper.fire(io.hPort.toHost.hValid) + io.hPort.fromHost.hValid := tFireHelper.fire(io.hPort.fromHost.hReady) + io.tReset.ready := tFireHelper.fire(io.tReset.valid) + + reqBuf.io.enq.bits := target.req.bits + reqBuf.io.enq.valid := target.req.valid && tFireHelper.fire(reqBuf.io.enq.ready) + target.req.ready := true.B + + dataBuf.io.enq.bits := target.data.bits + dataBuf.io.enq.valid := target.data.valid && tFireHelper.fire(dataBuf.io.enq.ready) + target.data.ready := true.B + + // Begin Timing model + val tCycle = RegInit(0.U(latencyBits.W)) + when (tFire) { + tCycle := tCycle + 1.U + } + + // Timing model programmable settings + val readLatency = genWORegInit(Wire(UInt(latencyBits.W)), "read_latency", defaultReadLatency) + val writeLatency = genWORegInit(Wire(UInt(latencyBits.W)), "write_latency", defaultWriteLatency) + + chisel3.experimental.withReset(reset.toBool || targetReset) { + when (tFire) { + assert(!target.req.fire || ((dataBeats.U * target.req.bits.len) < ((BigInt(1) << sectorBits) - 1).U), + "Transaction length exceeds timing model maximum supported length") + } + + // Timing Model -- Write Latency Pipe + // Write latency = write-ack cycle - cycle to receive last write beat + // Count the beats received for each tracker; they can be interleaved + + val wBeatCounters = Reg(Vec(nTrackers, UInt(sectorBits.W))) + val wValid = RegInit(VecInit(Seq.fill(nTrackers)(false.B))) + + val writeLatencyPipe = Module(new DynamicLatencyPipe(UInt(1.W), nTrackers, latencyBits)) + writeLatencyPipe.io.enq.valid := false.B + writeLatencyPipe.io.enq.bits := DontCare + writeLatencyPipe.io.latency := writeLatency + writeLatencyPipe.io.tCycle := tCycle + + val tagMatch = target.data.bits.tag === target.req.bits.tag + + wValid.zip(wBeatCounters).zipWithIndex.foreach { case ((valid, count), idx) => + val wReqFire = target.req.fire && target.req.bits.write && target.req.bits.tag === idx.U + val wDataFire = target.data.fire && target.data.bits.tag === idx.U + val wDone = (wDataFire && count === 1.U) + + when (tFire) { + // New write request received + when(wDone) { + assert(valid, "Write data received for unallocated tracker: %d\n", idx.U) + writeLatencyPipe.io.enq.valid := true.B + valid := false.B + }.elsewhen (wReqFire) { + valid := true.B + count := Mux(wDataFire, dataBeats.U * target.req.bits.len - 1.U, dataBeats.U * target.req.bits.len) + // We don't honestly expect len > 2^29 do we.. + // New data beat received for our tracker + }.elsewhen (wDataFire) { + count := count - 1.U + assert(valid, "Write data received for unallocated tracker: %d\n", idx.U) + } + } + } + + // Timing Model -- Read Latency Pipe + // Read latency is simply the number of cycles between read-req and first resp beat + val readLatencyPipe = Module(new DynamicLatencyPipe(UInt(sectorBits.W), nTrackers, latencyBits)) + + readLatencyPipe.io.enq.valid := tFire && target.req.fire && !target.req.bits.write + readLatencyPipe.io.enq.bits := target.req.bits.len + readLatencyPipe.io.tCycle := tCycle + readLatencyPipe.io.latency := readLatency + + // Scheduler. Prioritize returning write acknowledgements over returning read resps + // as they are only a single cycle long + val readRespBeatsLeft = RegInit(0.U(sectorBits.W)) + val returnWrite = RegInit(false.B) + val readRespBusy = readRespBeatsLeft =/= 0.U + val done = (returnWrite || readRespBeatsLeft === 1.U) && target.resp.fire + val idle = !returnWrite && !readRespBusy + writeLatencyPipe.io.deq.ready := false.B + readLatencyPipe.io.deq.ready := false.B + + when (tFire) { + when (done || idle) { + // If a write-response is waiting, return it first + when(writeLatencyPipe.io.deq.valid) { + returnWrite := true.B + writeLatencyPipe.io.deq.ready := true.B + }.elsewhen(readLatencyPipe.io.deq.valid) { + readRespBeatsLeft := readLatencyPipe.io.deq.bits * dataBeats.U + readLatencyPipe.io.deq.ready := true.B + }.otherwise { + readRespBeatsLeft := 0.U + returnWrite := false.B + } + }.elsewhen(readRespBusy && target.resp.fire) { + readRespBeatsLeft := readRespBeatsLeft - 1.U + } + } + + // Tie functional queues to output, gated with timing model control + target.resp.valid := !idle + target.resp.bits.data := 0.U + target.resp.bits.tag := 0.U + // This shouldn't be necessary for a well behaved target, but only drive bits + // through when there is valid data in the queue, closing a potential + // determinism hole + when (rRespBuf.io.deq.valid && readRespBusy) { + target.resp.bits.data := rRespBuf.io.deq.bits.data + target.resp.bits.tag := rRespBuf.io.deq.bits.tag + }.elsewhen (wAckBuf.io.deq.valid && returnWrite) { + target.resp.bits.tag := wAckBuf.io.deq.bits + } + + wAckStallN := !returnWrite || wAckBuf.io.deq.valid + rRespStallN := !readRespBusy || rRespBuf.io.deq.valid + + wAckBuf.io.deq.ready := tFireHelper.fire(wAckStallN) && returnWrite && target.resp.ready + rRespBuf.io.deq.ready := tFireHelper.fire(rRespStallN) && readRespBusy && target.resp.ready + } // withReset{} + + // Memory mapped registers + val nsectorReg = Reg(UInt(sectorBits.W)) + val max_req_lenReg = Reg(UInt(sectorBits.W)) + attach(nsectorReg, "bdev_nsectors", WriteOnly) + attach(max_req_lenReg, "bdev_max_req_len", WriteOnly) + target.info.nsectors := nsectorReg + target.info.max_req_len := max_req_lenReg + + // Functional request queue (to CPU) + genROReg(reqBuf.io.deq.valid, "bdev_req_valid") + genROReg(reqBuf.io.deq.bits.write, "bdev_req_write") + genROReg(reqBuf.io.deq.bits.offset, "bdev_req_offset") + genROReg(reqBuf.io.deq.bits.len, "bdev_req_len") + genROReg(reqBuf.io.deq.bits.tag, "bdev_req_tag") + Pulsify(genWORegInit(reqBuf.io.deq.ready, "bdev_req_ready", false.B), pulseLength = 1) + + // Functional data queue (to CPU) + genROReg(dataBuf.io.deq.valid, "bdev_data_valid") + genROReg(dataBuf.io.deq.bits.data(63, 32), "bdev_data_data_upper") + genROReg(dataBuf.io.deq.bits.data(31, 0), "bdev_data_data_lower") + genROReg(dataBuf.io.deq.bits.tag, "bdev_data_tag") + Pulsify(genWORegInit(dataBuf.io.deq.ready, "bdev_data_ready", false.B), pulseLength = 1) + + // Read reponse buffer MMIO IF (from CPU) + val rRespDataRegUpper = genWOReg(Wire(UInt((dataBitsPerBeat/2).W)),"bdev_rresp_data_upper") + val rRespDataRegLower = genWOReg(Wire(UInt((dataBitsPerBeat/2).W)),"bdev_rresp_data_lower") + val rRespTag = genWOReg(Wire(UInt(tagBits.W) ),"bdev_rresp_tag") + Pulsify( genWORegInit(rRespBuf.io.enq.valid ,"bdev_rresp_valid", false.B), pulseLength = 1) + genROReg(rRespBuf.io.enq.ready, "bdev_rresp_ready") + + rRespBuf.io.enq.bits.data := Cat(rRespDataRegUpper, rRespDataRegLower) + rRespBuf.io.enq.bits.tag := rRespTag + + // Write acknowledgement buffer MMIO IF (from CPU) -- we only need the tag from SW + val wAckTag = genWOReg(Wire(UInt(tagBits.W)) ,"bdev_wack_tag") + Pulsify( genWORegInit(wAckBuf.io.enq.valid ,"bdev_wack_valid", false.B), pulseLength = 1) + genROReg(wAckBuf.io.enq.ready, "bdev_wack_ready") + wAckBuf.io.enq.bits := wAckTag + + // Indicates to the CPU-hosted component that we need to be serviced + genROReg(reqBuf.io.deq.valid || dataBuf.io.deq.valid, "bdev_reqs_pending") + genROReg(~wAckStallN, "bdev_wack_stalled") + genROReg(~rRespStallN, "bdev_rresp_stalled") + + genCRFile() + + override def genHeader(base: BigInt, sb: StringBuilder) { + super.genHeader(base, sb) + sb.append(CppGenerationUtils.genMacro(s"${getWName.toUpperCase}_latency_bits", UInt32(latencyBits))) + sb.append(CppGenerationUtils.genMacro(s"${getWName.toUpperCase}_num_trackers", UInt32(nTrackers))) + } +} diff --git a/src/main/scala/firesim/endpoints/SerialWidget.scala b/src/main/scala/firesim/endpoints/SerialWidget.scala new file mode 100644 index 0000000..f76e1f6 --- /dev/null +++ b/src/main/scala/firesim/endpoints/SerialWidget.scala @@ -0,0 +1,72 @@ +package firesim +package endpoints + +import midas.core.{HostPort} +import midas.widgets._ + +import chisel3._ +import chisel3.util._ +import chisel3.experimental.{DataMirror, Direction} +import freechips.rocketchip.config.Parameters + +import testchipip.SerialIO + +class SimSerialIO extends Endpoint { + def matchType(data: Data) = data match { + case channel: SerialIO => + DataMirror.directionOf(channel.out.valid) == Direction.Output + case _ => false + } + def widget(p: Parameters) = new SerialWidget()(p) + override def widgetName = "SerialWidget" +} + +class SerialWidgetIO(implicit val p: Parameters) extends EndpointWidgetIO()(p) { + val w = testchipip.SerialAdapter.SERIAL_IF_WIDTH + val hPort = Flipped(HostPort(new SerialIO(w))) +} + +class SerialWidget(implicit p: Parameters) extends EndpointWidget()(p) { + val io = IO(new SerialWidgetIO) + + val inBuf = Module(new Queue(UInt(io.w.W), 16)) + val outBuf = Module(new Queue(UInt(io.w.W), 16)) + val tokensToEnqueue = RegInit(0.U(32.W)) + + val target = io.hPort.hBits + val tFire = io.hPort.toHost.hValid && io.hPort.fromHost.hReady && io.tReset.valid && tokensToEnqueue =/= 0.U + val targetReset = tFire & io.tReset.bits + inBuf.reset := reset.toBool || targetReset + outBuf.reset := reset.toBool || targetReset + + io.hPort.toHost.hReady := tFire + io.hPort.fromHost.hValid := tFire + io.tReset.ready := tFire + + target.in <> inBuf.io.deq + inBuf.io.deq.ready := target.in.ready && tFire + + outBuf.io.enq <> target.out + outBuf.io.enq.valid := target.out.valid && tFire + + genWOReg(inBuf.io.enq.bits, "in_bits") + Pulsify(genWORegInit(inBuf.io.enq.valid, "in_valid", false.B), pulseLength = 1) + genROReg(inBuf.io.enq.ready, "in_ready") + genROReg(outBuf.io.deq.bits, "out_bits") + genROReg(outBuf.io.deq.valid, "out_valid") + Pulsify(genWORegInit(outBuf.io.deq.ready, "out_ready", false.B), pulseLength = 1) + + val stepSize = Wire(UInt(32.W)) + val start = Wire(Bool()) + when (start) { + tokensToEnqueue := stepSize + }.elsewhen (tFire) { + tokensToEnqueue := tokensToEnqueue - 1.U + } + + genWOReg(stepSize, "step_size") + genROReg(tokensToEnqueue === 0.U, "done") + Pulsify(genWORegInit(start, "start", false.B), pulseLength = 1) + + genCRFile() +} diff --git a/src/main/scala/firesim/endpoints/SimpleNICWidget.scala b/src/main/scala/firesim/endpoints/SimpleNICWidget.scala new file mode 100644 index 0000000..870d71a --- /dev/null +++ b/src/main/scala/firesim/endpoints/SimpleNICWidget.scala @@ -0,0 +1,249 @@ +package firesim +package endpoints + +import chisel3._ +import chisel3.util._ +import chisel3.experimental.{DataMirror, Direction} +import freechips.rocketchip.config.{Parameters, Field} +import freechips.rocketchip.diplomacy.AddressSet +import freechips.rocketchip.util._ + +import midas.core.{HostPort} +import midas.widgets._ +import testchipip.{StreamIO, StreamChannel} +import icenet.{NICIOvonly, RateLimiterSettings} +import icenet.IceNIC._ +import junctions.{NastiIO, NastiKey} + +object TokenQueueConsts { + val TOKENS_PER_BIG_TOKEN = 7 + val BIG_TOKEN_WIDTH = (TOKENS_PER_BIG_TOKEN + 1) * 64 + val TOKEN_QUEUE_DEPTH = 6144 +} +import TokenQueueConsts._ + +case object LoopbackNIC extends Field[Boolean] + +/* on a NIC token transaction: + * 1) simulation driver feeds an empty token to start: + * data_in is garbage or real value (if exists) + * data_in_valid is 0 or 1 respectively + * data_out_ready is true (say host can always accept) + * + * 2) target responds: + * data_out garbage or real value (if exists) + * data_out_valid 0 or 1 respectively + * data_in_ready would be 1, so driver knows how to construct the next token if there was data to send + * + * repeat + */ + +class ReadyValidLast extends Bundle { + val data_last = Bool() + val ready = Bool() + val valid = Bool() +} + +class BIGToken extends Bundle { + val data = Vec(7, UInt(64.W)) + val rvls = Vec(7, new ReadyValidLast()) + val pad = UInt(43.W) +} + +class HostToNICToken extends Bundle { + val data_in = new StreamChannel(64) + val data_in_valid = Bool() + val data_out_ready = Bool() +} + +class NICToHostToken extends Bundle { + val data_out = new StreamChannel(64) + val data_out_valid = Bool() + val data_in_ready = Bool() +} + +class SimSimpleNIC extends Endpoint { + def matchType(data: Data) = data match { + case channel: NICIOvonly => + DataMirror.directionOf(channel.out.valid) == Direction.Output + case _ => false + } + def widget(p: Parameters) = new SimpleNICWidget()(p) + override def widgetName = "SimpleNICWidget" +} + +class SimpleNICWidgetIO(implicit val p: Parameters) extends EndpointWidgetIO()(p) { + val hPort = Flipped(HostPort(new NICIOvonly)) +} + +class BigTokenToNICTokenAdapter extends Module { + val io = IO(new Bundle { + val htnt = DecoupledIO(new HostToNICToken) + val pcie_in = Flipped(DecoupledIO(UInt(512.W))) + }) + + val pcieBundled = (new BIGToken).fromBits(io.pcie_in.bits) + + val xactHelper = DecoupledHelper(io.htnt.ready, io.pcie_in.valid) + + val loopIter = RegInit(0.U(32.W)) + when (io.htnt.fire()) { + loopIter := Mux(loopIter === 6.U, 0.U, loopIter + 1.U) + } + + io.htnt.bits.data_in.data := pcieBundled.data(loopIter) + io.htnt.bits.data_in.keep := 0xFF.U + io.htnt.bits.data_in.last := pcieBundled.rvls(loopIter).data_last + io.htnt.bits.data_in_valid := pcieBundled.rvls(loopIter).valid + io.htnt.bits.data_out_ready := pcieBundled.rvls(loopIter).ready + io.htnt.valid := xactHelper.fire(io.htnt.ready) + io.pcie_in.ready := xactHelper.fire(io.pcie_in.valid, loopIter === 6.U) +} + +class NICTokenToBigTokenAdapter extends Module { + val io = IO(new Bundle { + val ntht = Flipped(DecoupledIO(new NICToHostToken)) + val pcie_out = DecoupledIO(UInt(512.W)) + }) + + // step one, buffer 7 elems into registers. note that the 7th element is here + // just for convenience. in reality, it is not used since we're bypassing to + // remove a cycle of latency + val NTHT_BUF = Reg(Vec(7, new NICToHostToken)) + val specialCounter = RegInit(0.U(32.W)) + + when (io.ntht.valid) { + NTHT_BUF(specialCounter) := io.ntht.bits + } + + io.ntht.ready := (specialCounter === 6.U && io.pcie_out.ready) || (specialCounter =/= 6.U) + io.pcie_out.valid := specialCounter === 6.U && io.ntht.valid + when ((specialCounter =/= 6.U) && io.ntht.valid) { + specialCounter := specialCounter + 1.U + } .elsewhen ((specialCounter === 6.U) && io.ntht.valid && io.pcie_out.ready) { + specialCounter := 0.U + } .otherwise { + specialCounter := specialCounter + } + // step two, connect 6 elems + latest one to output (7 items) + // TODO: attach pcie_out to data + + // debug check to help check we're not losing tokens somewhere + val token_trace_counter = RegInit(0.U(43.W)) + when (io.pcie_out.fire()) { + token_trace_counter := token_trace_counter + 1.U + } .otherwise { + token_trace_counter := token_trace_counter + } + + val out = Wire(new BIGToken) + for (i <- 0 until 6) { + out.data(i) := NTHT_BUF(i).data_out.data + out.rvls(i).data_last := NTHT_BUF(i).data_out.last + out.rvls(i).ready := NTHT_BUF(i).data_in_ready + out.rvls(i).valid := NTHT_BUF(i).data_out_valid + } + out.data(6) := io.ntht.bits.data_out.data + out.rvls(6).data_last := io.ntht.bits.data_out.last + out.rvls(6).ready := io.ntht.bits.data_in_ready + out.rvls(6).valid := io.ntht.bits.data_out_valid + out.pad := token_trace_counter + + io.pcie_out.bits := out.asUInt +} + +class HostToNICTokenGenerator(nTokens: Int)(implicit p: Parameters) extends Module { + val io = IO(new Bundle { + val out = Decoupled(new HostToNICToken) + val in = Flipped(Decoupled(new NICToHostToken)) + }) + + val s_init :: s_seed :: s_forward :: Nil = Enum(3) + val state = RegInit(s_init) + + val (_, seedDone) = Counter(state === s_seed && io.out.fire(), nTokens) + + io.out.valid := state === s_seed || (state === s_forward && io.in.valid) + io.out.bits.data_in_valid := state === s_forward && io.in.bits.data_out_valid + io.out.bits.data_in := io.in.bits.data_out + io.out.bits.data_out_ready := state === s_seed || io.in.bits.data_in_ready + io.in.ready := state === s_forward && io.out.ready + + when (state === s_init) { state := s_seed } + when (seedDone) { state := s_forward } +} + +class SimpleNICWidget(implicit p: Parameters) extends EndpointWidget()(p) + with BidirectionalDMA { + val io = IO(new SimpleNICWidgetIO) + + // DMA mixin parameters + lazy val fromHostCPUQueueDepth = TOKEN_QUEUE_DEPTH + lazy val toHostCPUQueueDepth = TOKEN_QUEUE_DEPTH + // Biancolin: Need to look into this + lazy val dmaSize = BigInt((BIG_TOKEN_WIDTH / 8) * TOKEN_QUEUE_DEPTH) + + val htnt_queue = Module(new Queue(new HostToNICToken, 10)) + val ntht_queue = Module(new Queue(new NICToHostToken, 10)) + + val bigtokenToNIC = Module(new BigTokenToNICTokenAdapter) + val NICtokenToBig = Module(new NICTokenToBigTokenAdapter) + + val target = io.hPort.hBits + val tFire = io.hPort.toHost.hValid && io.hPort.fromHost.hReady && io.tReset.valid + val targetReset = tFire & io.tReset.bits + io.tReset.ready := tFire + +// htnt_queue.reset := reset //|| targetReset +// ntht_queue.reset := reset //|| targetReset + + if (p(LoopbackNIC)) { + val tokenGen = Module(new HostToNICTokenGenerator(10)) + htnt_queue.io.enq <> tokenGen.io.out + tokenGen.io.in <> ntht_queue.io.deq + NICtokenToBig.io.ntht.valid := false.B + NICtokenToBig.io.ntht.bits := DontCare + bigtokenToNIC.io.htnt.ready := false.B + } else { + NICtokenToBig.io.ntht <> ntht_queue.io.deq + htnt_queue.io.enq <> bigtokenToNIC.io.htnt + } + + io.hPort.toHost.hReady := ntht_queue.io.enq.ready + ntht_queue.io.enq.valid := io.hPort.toHost.hValid + ntht_queue.io.enq.bits.data_out := target.out.bits + ntht_queue.io.enq.bits.data_out_valid := target.out.valid + ntht_queue.io.enq.bits.data_in_ready := true.B //target.in.ready + + io.hPort.fromHost.hValid := htnt_queue.io.deq.valid + htnt_queue.io.deq.ready := io.hPort.fromHost.hReady + target.in.bits := htnt_queue.io.deq.bits.data_in + target.in.valid := htnt_queue.io.deq.bits.data_in_valid + //target.out.ready := htnt_queue.io.deq.bits.data_out_ready + + bigtokenToNIC.io.pcie_in <> incomingPCISdat.io.deq + outgoingPCISdat.io.enq <> NICtokenToBig.io.pcie_out + + + if (p(LoopbackNIC)) { + target.rlimit.size := 8.U + target.rlimit.period := 0.U + target.rlimit.inc := 1.U + target.macAddr := 0.U + } else { + val macAddrRegUpper = Reg(UInt(32.W)) + val macAddrRegLower = Reg(UInt(32.W)) + val rlimitSettings = Reg(UInt(32.W)) + + target.rlimit := (new RateLimiterSettings).fromBits(rlimitSettings) + target.macAddr := Cat(macAddrRegUpper, macAddrRegLower) + + attach(macAddrRegUpper, "macaddr_upper", WriteOnly) + attach(macAddrRegLower, "macaddr_lower", WriteOnly) + attach(rlimitSettings, "rlimit_settings", WriteOnly) + } + + genROReg(!tFire, "done") + + genCRFile() +} diff --git a/src/main/scala/firesim/endpoints/TracerVWidget.scala b/src/main/scala/firesim/endpoints/TracerVWidget.scala new file mode 100644 index 0000000..1ded90a --- /dev/null +++ b/src/main/scala/firesim/endpoints/TracerVWidget.scala @@ -0,0 +1,75 @@ +package firesim.endpoints + +import chisel3._ +import chisel3.util._ +import freechips.rocketchip.config.{Parameters, Field} +import freechips.rocketchip.diplomacy.AddressSet +import freechips.rocketchip.util._ +import freechips.rocketchip.rocket.TracedInstruction +import freechips.rocketchip.subsystem.RocketTilesKey +import freechips.rocketchip.tile.TileKey +import firesim.firesim.TraceOutputTop + +import midas.core.{HostPort} +import midas.widgets._ +import testchipip.{StreamIO, StreamChannel} +import TokenQueueConsts._ + +class SimTracerV extends Endpoint { + + // this is questionable ... + // but I can't see a better way to do this for now. getting sharedMemoryTLEdge is the problem. + var tracer_param = Parameters.empty + var num_traces = 0 + def matchType(data: Data) = data match { + case channel: TraceOutputTop => { + // this is questionable ... + tracer_param = channel.traces(0).p + num_traces = channel.traces.length + true + } + case _ => false + } + def widget(p: Parameters) = new TracerVWidget(tracer_param, num_traces)(p) + override def widgetName = "TracerVWidget" +} + +class TracerVWidgetIO(val tracerParams: Parameters, val num_traces: Int)(implicit p: Parameters) extends EndpointWidgetIO()(p) { + val hPort = Flipped(HostPort(new TraceOutputTop(num_traces)(tracerParams))) +} + +class TracerVWidget(tracerParams: Parameters, num_traces: Int)(implicit p: Parameters) extends EndpointWidget()(p) + with UnidirectionalDMAToHostCPU { + val io = IO(new TracerVWidgetIO(tracerParams, num_traces)) + + // DMA mixin parameters + lazy val toHostCPUQueueDepth = TOKEN_QUEUE_DEPTH + lazy val dmaSize = BigInt((BIG_TOKEN_WIDTH / 8) * TOKEN_QUEUE_DEPTH) + + val uint_traces = io.hPort.hBits.traces map (trace => trace.asUInt) + outgoingPCISdat.io.enq.bits := Cat(uint_traces) //io.hPort.hBits.traces(0).asUInt + + val tFireHelper = DecoupledHelper(outgoingPCISdat.io.enq.ready, + io.hPort.toHost.hValid, io.hPort.fromHost.hReady, io.tReset.valid) + + io.tReset.ready := tFireHelper.fire(io.tReset.valid) + io.hPort.fromHost.hValid := tFireHelper.fire(io.hPort.fromHost.hReady) + io.hPort.toHost.hReady := tFireHelper.fire(io.hPort.toHost.hValid) + + outgoingPCISdat.io.enq.valid := tFireHelper.fire(outgoingPCISdat.io.enq.ready) + + when (outgoingPCISdat.io.enq.fire()) { + for (i <- 0 until io.hPort.hBits.traces.length) { + printf("trace %d, valid: %x\n", i.U, io.hPort.hBits.traces(i).valid) + printf("trace %d, iaddr: %x\n", i.U, io.hPort.hBits.traces(i).iaddr) + printf("trace %d, insn: %x\n", i.U, io.hPort.hBits.traces(i).insn) + printf("trace %d, priv: %x\n", i.U, io.hPort.hBits.traces(i).priv) + printf("trace %d, exception: %x\n", i.U, io.hPort.hBits.traces(i).exception) + printf("trace %d, interrupt: %x\n", i.U, io.hPort.hBits.traces(i).interrupt) + printf("trace %d, cause: %x\n", i.U, io.hPort.hBits.traces(i).cause) + printf("trace %d, tval: %x\n", i.U, io.hPort.hBits.traces(i).tval) + } + } + attach(outgoingPCISdat.io.deq.valid && !outgoingPCISdat.io.enq.ready, "tracequeuefull", ReadOnly) + genCRFile() +} diff --git a/src/main/scala/firesim/endpoints/UARTWidget.scala b/src/main/scala/firesim/endpoints/UARTWidget.scala new file mode 100644 index 0000000..89be005 --- /dev/null +++ b/src/main/scala/firesim/endpoints/UARTWidget.scala @@ -0,0 +1,129 @@ +package firesim +package endpoints + +import midas.core.{HostPort} +import midas.widgets._ + +import chisel3._ +import chisel3.util._ +import chisel3.experimental.{DataMirror, Direction} +import freechips.rocketchip.config.Parameters +import freechips.rocketchip.subsystem.PeripheryBusKey +import sifive.blocks.devices.uart.{UARTPortIO, PeripheryUARTKey} + +class SimUART extends Endpoint { + def matchType(data: Data) = data match { + case channel: UARTPortIO => + DataMirror.directionOf(channel.txd) == Direction.Output + case _ => false + } + def widget(p: Parameters) = { + val frequency = p(PeripheryBusKey).frequency + val baudrate = 3686400L + val div = (p(PeripheryBusKey).frequency / baudrate).toInt + new UARTWidget(div)(p) + } + override def widgetName = "UARTWidget" +} + +class UARTWidgetIO(implicit p: Parameters) extends EndpointWidgetIO()(p) { + val hPort = Flipped(HostPort(new UARTPortIO)) +} + +class UARTWidget(div: Int)(implicit p: Parameters) extends EndpointWidget()(p) { + val io = IO(new UARTWidgetIO) + + val txfifo = Module(new Queue(UInt(8.W), 128)) + val rxfifo = Module(new Queue(UInt(8.W), 128)) + + val target = io.hPort.hBits + val fire = io.hPort.toHost.hValid && io.hPort.fromHost.hReady && io.tReset.valid & txfifo.io.enq.ready + val targetReset = fire & io.tReset.bits + rxfifo.reset := reset.toBool || targetReset + txfifo.reset := reset.toBool || targetReset + + io.hPort.toHost.hReady := fire + io.hPort.fromHost.hValid := fire + io.tReset.ready := fire + + val sTxIdle :: sTxWait :: sTxData :: sTxBreak :: Nil = Enum(UInt(), 4) + val txState = RegInit(sTxIdle) + val txData = Reg(UInt(8.W)) + // iterate through bits in byte to deserialize + val (txDataIdx, txDataWrap) = Counter(txState === sTxData && fire, 8) + // iterate using div to convert clock rate to baud + val (txBaudCount, txBaudWrap) = Counter(txState === sTxWait && fire, div) + val (txSlackCount, txSlackWrap) = Counter(txState === sTxIdle && target.txd === 0.U && fire, 4) + + switch(txState) { + is(sTxIdle) { + when(txSlackWrap) { + txData := 0.U + txState := sTxWait + } + } + is(sTxWait) { + when(txBaudWrap) { + txState := sTxData + } + } + is(sTxData) { + when(fire) { + txData := txData | (target.txd << txDataIdx) + } + when(txDataWrap) { + txState := Mux(target.txd === 1.U, sTxIdle, sTxBreak) + }.elsewhen(fire) { + txState := sTxWait + } + } + is(sTxBreak) { + when(target.txd === 1.U && fire) { + txState := sTxIdle + } + } + } + + txfifo.io.enq.bits := txData + txfifo.io.enq.valid := txDataWrap + + val sRxIdle :: sRxStart :: sRxData :: Nil = Enum(UInt(), 3) + val rxState = RegInit(sRxIdle) + // iterate using div to convert clock rate to baud + val (rxBaudCount, rxBaudWrap) = Counter(fire, div) + // iterate through bits in byte to deserialize + val (rxDataIdx, rxDataWrap) = Counter(rxState === sRxData && fire && rxBaudWrap, 8) + + target.rxd := 1.U + switch(rxState) { + is(sRxIdle) { + target.rxd := 1.U + when (rxBaudWrap && rxfifo.io.deq.valid) { + rxState := sRxStart + } + } + is(sRxStart) { + target.rxd := 0.U + when(rxBaudWrap) { + rxState := sRxData + } + } + is(sRxData) { + target.rxd := (rxfifo.io.deq.bits >> rxDataIdx)(0) + when(rxDataWrap && rxBaudWrap) { + rxState := sRxIdle + } + } + } + rxfifo.io.deq.ready := (rxState === sRxData) && rxDataWrap && rxBaudWrap && fire + + genROReg(txfifo.io.deq.bits, "out_bits") + genROReg(txfifo.io.deq.valid, "out_valid") + Pulsify(genWORegInit(txfifo.io.deq.ready, "out_ready", false.B), pulseLength = 1) + + genWOReg(rxfifo.io.enq.bits, "in_bits") + Pulsify(genWORegInit(rxfifo.io.enq.valid, "in_valid", false.B), pulseLength = 1) + genROReg(rxfifo.io.enq.ready, "in_ready") + + genCRFile() +} diff --git a/src/test/scala/firesim/ScalaTestSuite.scala b/src/test/scala/firesim/ScalaTestSuite.scala new file mode 100644 index 0000000..8297376 --- /dev/null +++ b/src/test/scala/firesim/ScalaTestSuite.scala @@ -0,0 +1,118 @@ +//See LICENSE for license details. +package firesim.firesim + +import java.io.File + +import scala.concurrent.{Future, Await, ExecutionContext} +import scala.sys.process.{stringSeqToProcess, ProcessLogger} + +import freechips.rocketchip.diplomacy._ +import freechips.rocketchip.system.{RocketTestSuite, BenchmarkTestSuite} +import freechips.rocketchip.system.TestGeneration._ +import freechips.rocketchip.system.DefaultTestSuites._ + +import firesim.util.{GeneratorArgs, HasFireSimGeneratorUtilities} +import firesim._ + +abstract class FireSimTestSuite( + topModuleClass: String, + targetConfigs: String, + platformConfigs: String, + N: Int = 8 + ) extends TestSuiteCommon with IsFireSimGeneratorLike { + import scala.concurrent.duration._ + import ExecutionContext.Implicits.global + + lazy val generatorArgs = GeneratorArgs( + midasFlowKind = "midas", + targetDir = "generated-src", + topModuleProject = "firesim.firesim", + topModuleClass = topModuleClass, + targetConfigProject = "firesim.firesim", + targetConfigs = targetConfigs, + platformConfigProject = "firesim.firesim", + platformConfigs = platformConfigs) + + // From HasFireSimGeneratorUtilities + // For the firesim utilities to use the same directory as the test suite + override lazy val testDir = genDir + + // From TestSuiteCommon + val targetTuple = generatorArgs.tupleName + val commonMakeArgs = Seq(s"DESIGN=${generatorArgs.topModuleClass}", + s"TARGET_CONFIG=${generatorArgs.targetConfigs}", + s"PLATFORM_CONFIG=${generatorArgs.platformConfigs}") + override lazy val platform = hostParams(midas.Platform) + + def invokeMlSimulator(backend: String, name: String, debug: Boolean) = { + make(s"${outDir.getAbsolutePath}/${name}.%s".format(if (debug) "vpd" else "out"), + s"EMUL=${backend}" + ) + } + + def runTest(backend: String, name: String, debug: Boolean) = { + behavior of s"${name} running on ${backend} in MIDAS-level simulation" + compileMlSimulator(backend, debug) + if (isCmdAvailable(backend)) { + it should s"pass" in { + assert(invokeMlSimulator(backend, name, debug) == 0) + } + } + } + + //def runReplay(backend: String, replayBackend: String, name: String) = { + // val dir = (new File(outDir, backend)).getAbsolutePath + // (Seq("make", s"replay-$replayBackend", + // s"SAMPLE=${dir}/${name}.sample", s"output_dir=$dir") ++ makeArgs).! + //} + + def runSuite(backend: String, debug: Boolean = false)(suite: RocketTestSuite) { + // compile emulators + behavior of s"${suite.makeTargetName} running on $backend" + if (isCmdAvailable(backend)) { + val postfix = suite match { + case _: BenchmarkTestSuite | _: BlockdevTestSuite | _: NICTestSuite => ".riscv" + case _ => "" + } + val results = suite.names.toSeq sliding (N, N) map { t => + val subresults = t map (name => + Future(name -> invokeMlSimulator(backend, s"$name$postfix", debug))) + Await result (Future sequence subresults, Duration.Inf) + } + results.flatten foreach { case (name, exitcode) => + it should s"pass $name" in { assert(exitcode == 0) } + } + //replayBackends foreach { replayBackend => + // if (platformParams(midas.EnableSnapshot) && isCmdAvailable("vcs")) { + // assert((Seq("make", s"vcs-$replayBackend") ++ makeArgs).! == 0) // compile vcs + // suite.names foreach { name => + // it should s"replay $name in $replayBackend" in { + // assert(runReplay(backend, replayBackend, s"$name$postfix") == 0) + // } + // } + // } else { + // suite.names foreach { name => + // ignore should s"replay $name in $backend" + // } + // } + //} + } else { + ignore should s"pass $backend" + } + } + + clean + mkdirs + elaborateAndCompileWithMidas + generateTestSuiteMakefrags + runTest("verilator", "rv64ui-p-simple", false) + runSuite("verilator")(benchmarks) + runSuite("verilator")(FastBlockdevTests) +} + +class RocketF1Tests extends FireSimTestSuite("FireSimNoNIC", "FireSimRocketChipConfig", "FireSimConfig") +class RocketF1ClockDivTests extends FireSimTestSuite("FireSimNoNIC", "FireSimRocketChipConfig", "FireSimClockDivConfig") +class BoomF1Tests extends FireSimTestSuite("FireBoomNoNIC", "FireSimBoomConfig", "FireSimConfig") +class RocketNICF1Tests extends FireSimTestSuite("FireSim", "FireSimRocketChipConfig", "FireSimConfig") { + runSuite("verilator")(NICLoopbackTests) +} From c8c706a1d4375250c3c9476d0075ac7d7e71f07d Mon Sep 17 00:00:00 2001 From: David Biancolin Date: Sun, 24 Mar 2019 23:14:32 +0000 Subject: [PATCH 9/9] Fix up midas dependencies --- build.sbt | 6 +++--- firesim | 2 +- src/main/scala/firesim/TargetMixins.scala | 7 ++----- src/main/scala/firesim/Targets.scala | 3 ++- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/build.sbt b/build.sbt index 2c96f11..5c7a9bd 100644 --- a/build.sbt +++ b/build.sbt @@ -29,8 +29,7 @@ lazy val chisel = (project in rocketChipDir / "chisel3") // Contains annotations & firrtl passes you may wish to use in rocket-chip without // introducing a circular dependency between RC and MIDAS -lazy val midasTargetUtils = (project in firesimDir / "midas/targetutils") - .settings(commonSettings).dependsOn(chisel) +lazy val midasTargetUtils = ProjectRef(firesimDir, "targetutils") // Rocket-chip dependencies (subsumes making RC a RootProject) lazy val hardfloat = (project in rocketChipDir / "hardfloat") @@ -64,9 +63,10 @@ lazy val icenet = project.settings(commonSettings).dependsOn(rocketchip, testchi lazy val boom = project.settings(commonSettings).dependsOn(rocketchip) // The library components of FireSim +lazy val midas = ProjectRef(firesimDir, "midas") lazy val firesim = ProjectRef(firesimDir, "common") lazy val firechip = (project in file(".")) .settings(commonSettings) - .dependsOn(boom, icenet, testchipip, sifive_blocks, midasTargetUtils, + .dependsOn(boom, icenet, testchipip, sifive_blocks, midasTargetUtils, midas, firesim % "test->test;compile->compile") diff --git a/firesim b/firesim index 83e9096..d5e7dee 160000 --- a/firesim +++ b/firesim @@ -1 +1 @@ -Subproject commit 83e9096bb81ba99e11dedf32d2aef6474edcf80e +Subproject commit d5e7deedc0fe9f270f2da5c36d73337542b153c7 diff --git a/src/main/scala/firesim/TargetMixins.scala b/src/main/scala/firesim/TargetMixins.scala index 5a86250..8495be9 100644 --- a/src/main/scala/firesim/TargetMixins.scala +++ b/src/main/scala/firesim/TargetMixins.scala @@ -10,8 +10,7 @@ import freechips.rocketchip.util._ import freechips.rocketchip.rocket.TracedInstruction import boom.system.BoomSubsystem import midas.targetutils.ExcludeInstanceAsserts -// TODO: FIX THIS -//import midas.models.AXI4BundleWithEdge +import midas.models.AXI4BundleWithEdge class TraceOutputTop(val numTraces: Int)(implicit val p: Parameters) extends Bundle { @@ -56,9 +55,7 @@ trait CanHaveMisalignedMasterAXI4MemPort { this: BaseSubsystem => trait CanHaveMisalignedMasterAXI4MemPortModuleImp extends LazyModuleImp { val outer: CanHaveMisalignedMasterAXI4MemPort - // TODO: Resolve this dependency chain: RC (AXI4B) -> MIDAS (AXI4BWEdge) -> FC - //val mem_axi4 = IO(new HeterogeneousBag(outer.memAXI4Node.in map AXI4BundleWithEdge.apply)) - val mem_axi4 = IO(HeterogeneousBag.fromNode(outer.memAXI4Node.in)) + val mem_axi4 = IO(new HeterogeneousBag(outer.memAXI4Node.in map AXI4BundleWithEdge.apply)) (mem_axi4 zip outer.memAXI4Node.in).foreach { case (io, (bundle, _)) => io <> bundle } def connectSimAXIMem() { diff --git a/src/main/scala/firesim/Targets.scala b/src/main/scala/firesim/Targets.scala index 2937697..0ebb60e 100755 --- a/src/main/scala/firesim/Targets.scala +++ b/src/main/scala/firesim/Targets.scala @@ -17,6 +17,7 @@ import testchipip._ import testchipip.SerialAdapter.SERIAL_IF_WIDTH import sifive.blocks.devices.uart._ import midas.targetutils.ExcludeInstanceAssertsAnnotation +import midas.models.AXI4BundleWithEdge import java.io.File case object NumNodes extends Field[Int] @@ -183,7 +184,7 @@ class FireBoomNoNICModuleImpTraced[+L <: FireBoomNoNIC](l: L) extends FireBoomNo class SupernodeIO( nNodes: Int, serialWidth: Int, - bagPrototype: HeterogeneousBag[AXI4Bundle])(implicit p: Parameters) + bagPrototype: HeterogeneousBag[AXI4BundleWithEdge])(implicit p: Parameters) extends Bundle { val serial = Vec(nNodes, new SerialIO(serialWidth))