WIP
This commit is contained in:
124
generators/firechip/src/main/scala/Generator.scala
Executable file
124
generators/firechip/src/main/scala/Generator.scala
Executable file
@@ -0,0 +1,124 @@
|
||||
//See LICENSE for license details.
|
||||
|
||||
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
|
||||
generateTclEnvFile
|
||||
}
|
||||
54
generators/firechip/src/main/scala/SimConfigs.scala
Normal file
54
generators/firechip/src/main/scala/SimConfigs.scala
Normal file
@@ -0,0 +1,54 @@
|
||||
//See LICENSE for license details.
|
||||
package firesim.firesim
|
||||
|
||||
import freechips.rocketchip.config.{Parameters, Config, Field}
|
||||
|
||||
import midas.{EndpointKey}
|
||||
import midas.widgets.{EndpointMap}
|
||||
import midas.models._
|
||||
|
||||
import firesim.endpoints._
|
||||
import firesim.configs._
|
||||
|
||||
/*******************************************************************************
|
||||
* 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 WithSerialWidget ++
|
||||
new WithUARTWidget ++
|
||||
new WithSimpleNICWidget ++
|
||||
new WithBlockDevWidget ++
|
||||
new WithDefaultMemModel ++
|
||||
new WithTracerVWidget ++
|
||||
new BasePlatformConfig)
|
||||
|
||||
class FireSimClockDivConfig extends Config(
|
||||
new WithDefaultMemModel(clockDivision = 2) ++
|
||||
new FireSimConfig)
|
||||
|
||||
class FireSimDDR3Config extends Config(
|
||||
new FCFS16GBQuadRank ++
|
||||
new FireSimConfig)
|
||||
|
||||
class FireSimDDR3LLC4MBConfig extends Config(
|
||||
new FCFS16GBQuadRankLLC4MB ++
|
||||
new FireSimConfig)
|
||||
|
||||
class FireSimDDR3FRFCFSConfig extends Config(
|
||||
new FRFCFS16GBQuadRank ++
|
||||
new FireSimConfig)
|
||||
|
||||
class FireSimDDR3FRFCFSLLC4MBConfig extends Config(
|
||||
new FRFCFS16GBQuadRankLLC4MB ++
|
||||
new FireSimConfig)
|
||||
|
||||
class FireSimDDR3FRFCFSLLC4MB3ClockDivConfig extends Config(
|
||||
new FRFCFS16GBQuadRankLLC4MB3Div ++
|
||||
new FireSimConfig)
|
||||
|
||||
205
generators/firechip/src/main/scala/TargetConfigs.scala
Normal file
205
generators/firechip/src/main/scala/TargetConfigs.scala
Normal file
@@ -0,0 +1,205 @@
|
||||
package firesim.firesim
|
||||
|
||||
import java.io.File
|
||||
|
||||
import chisel3.util.{log2Up}
|
||||
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 freechips.rocketchip.devices.debug.DebugModuleParams
|
||||
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 => {
|
||||
val rebarBootROM = new File(s"./generators/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) => {
|
||||
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(
|
||||
inBufFlits = 8192,
|
||||
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)
|
||||
))
|
||||
})
|
||||
|
||||
// Disables clock-gating; doesn't play nice with our FAME-1 pass
|
||||
class WithoutClockGating extends Config((site, here, up) => {
|
||||
case DebugModuleParams => up(DebugModuleParams, site).copy(clockGate = false)
|
||||
})
|
||||
|
||||
// Testing configurations
|
||||
// This enables printfs used in testing
|
||||
class WithScalaTestFeatures extends Config((site, here, up) => {
|
||||
case PrintTracePort => 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 WithoutClockGating ++
|
||||
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))
|
||||
})
|
||||
|
||||
// single core config
|
||||
class FireSimRocketChipSingleCoreConfig extends Config(new FireSimRocketChipConfig)
|
||||
|
||||
// dual core config
|
||||
class FireSimRocketChipDualCoreConfig extends Config(
|
||||
new WithNDuplicatedRocketCores(2) ++
|
||||
new FireSimRocketChipSingleCoreConfig)
|
||||
|
||||
// quad core config
|
||||
class FireSimRocketChipQuadCoreConfig extends Config(
|
||||
new WithNDuplicatedRocketCores(4) ++
|
||||
new FireSimRocketChipSingleCoreConfig)
|
||||
|
||||
// hexa core config
|
||||
class FireSimRocketChipHexaCoreConfig extends Config(
|
||||
new WithNDuplicatedRocketCores(6) ++
|
||||
new FireSimRocketChipSingleCoreConfig)
|
||||
|
||||
// octa core config
|
||||
class FireSimRocketChipOctaCoreConfig extends Config(
|
||||
new WithNDuplicatedRocketCores(8) ++
|
||||
new FireSimRocketChipSingleCoreConfig)
|
||||
|
||||
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 WithoutClockGating ++
|
||||
// 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))
|
||||
case MaxHartIdBits => log2Up(site(BoomTilesKey).size)
|
||||
})
|
||||
|
||||
class FireSimBoomDualCoreConfig extends Config(
|
||||
new WithNDuplicatedBoomCores(2) ++
|
||||
new FireSimBoomConfig)
|
||||
|
||||
class FireSimBoomQuadCoreConfig extends Config(
|
||||
new WithNDuplicatedBoomCores(4) ++
|
||||
new FireSimBoomConfig)
|
||||
|
||||
//**********************************************************************************
|
||||
//* Supernode Configurations
|
||||
//*********************************************************************************/
|
||||
class WithNumNodes(n: Int) extends Config((pname, site, here) => {
|
||||
case NumNodes => n
|
||||
})
|
||||
|
||||
class SupernodeFireSimRocketChipConfig extends Config(
|
||||
new WithNumNodes(4) ++
|
||||
new WithExtMemSize(0x200000000L) ++ // 8GB
|
||||
new FireSimRocketChipConfig)
|
||||
|
||||
class SupernodeFireSimRocketChipSingleCoreConfig extends Config(
|
||||
new WithNumNodes(4) ++
|
||||
new WithExtMemSize(0x200000000L) ++ // 8GB
|
||||
new FireSimRocketChipSingleCoreConfig)
|
||||
|
||||
class SupernodeSixNodeFireSimRocketChipSingleCoreConfig extends Config(
|
||||
new WithNumNodes(6) ++
|
||||
new WithExtMemSize(0x40000000L) ++ // 1GB
|
||||
new FireSimRocketChipSingleCoreConfig)
|
||||
|
||||
class SupernodeEightNodeFireSimRocketChipSingleCoreConfig extends Config(
|
||||
new WithNumNodes(8) ++
|
||||
new WithExtMemSize(0x40000000L) ++ // 1GB
|
||||
new FireSimRocketChipSingleCoreConfig)
|
||||
|
||||
class SupernodeFireSimRocketChipDualCoreConfig extends Config(
|
||||
new WithNumNodes(4) ++
|
||||
new WithExtMemSize(0x200000000L) ++ // 8GB
|
||||
new FireSimRocketChipDualCoreConfig)
|
||||
|
||||
class SupernodeFireSimRocketChipQuadCoreConfig extends Config(
|
||||
new WithNumNodes(4) ++
|
||||
new WithExtMemSize(0x200000000L) ++ // 8GB
|
||||
new FireSimRocketChipQuadCoreConfig)
|
||||
|
||||
class SupernodeFireSimRocketChipHexaCoreConfig extends Config(
|
||||
new WithNumNodes(4) ++
|
||||
new WithExtMemSize(0x200000000L) ++ // 8GB
|
||||
new FireSimRocketChipHexaCoreConfig)
|
||||
|
||||
class SupernodeFireSimRocketChipOctaCoreConfig extends Config(
|
||||
new WithNumNodes(4) ++
|
||||
new WithExtMemSize(0x200000000L) ++ // 8GB
|
||||
new FireSimRocketChipOctaCoreConfig)
|
||||
|
||||
@@ -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"))
|
||||
131
generators/firechip/src/main/scala/TargetMixins.scala
Normal file
131
generators/firechip/src/main/scala/TargetMixins.scala
Normal file
@@ -0,0 +1,131 @@
|
||||
package firesim.firesim
|
||||
|
||||
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.subsystem._
|
||||
import freechips.rocketchip.rocket.TracedInstruction
|
||||
import firesim.endpoints.{TraceOutputTop, DeclockedTracedInstruction}
|
||||
import boom.system.BoomSubsystem
|
||||
|
||||
import midas.models.AXI4BundleWithEdge
|
||||
import midas.targetutils.ExcludeInstanceAsserts
|
||||
|
||||
/** Ties together Subsystem buses in the same fashion done in the example top of Rocket Chip */
|
||||
trait HasDefaultBusConfiguration {
|
||||
this: BaseSubsystem =>
|
||||
// The sbus masters the cbus; here we convert TL-UH -> TL-UL
|
||||
sbus.crossToBus(cbus, NoCrossing)
|
||||
|
||||
// The cbus masters the pbus; which might be clocked slower
|
||||
cbus.crossToBus(pbus, SynchronousCrossing())
|
||||
|
||||
// The fbus masters the sbus; both are TL-UH or TL-C
|
||||
FlipRendering { implicit p =>
|
||||
sbus.crossFromBus(fbus, SynchronousCrossing())
|
||||
}
|
||||
|
||||
// The sbus masters the mbus; here we convert TL-C -> TL-UH
|
||||
private val BankedL2Params(nBanks, coherenceManager) = p(BankedL2Key)
|
||||
private val (in, out, halt) = coherenceManager(this)
|
||||
if (nBanks != 0) {
|
||||
sbus.coupleTo("coherence_manager") { in :*= _ }
|
||||
mbus.coupleFrom("coherence_manager") { _ :=* BankBinder(mbus.blockBytes * (nBanks-1)) :*= out }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Copied from RC and modified to change the IO type of the Imp to include the Diplomatic edges
|
||||
* associated with each port. This drives FASED functional model sizing
|
||||
*/
|
||||
trait CanHaveFASEDOptimizedMasterAXI4MemPort { this: BaseSubsystem =>
|
||||
val module: CanHaveFASEDOptimizedMasterAXI4MemPortModuleImp
|
||||
|
||||
val memAXI4Node = p(ExtMem).map { case MemoryPortParams(memPortParams, nMemoryChannels) =>
|
||||
val portName = "axi4"
|
||||
val device = new MemoryDevice
|
||||
|
||||
val memAXI4Node = AXI4SlaveNode(Seq.tabulate(nMemoryChannels) { channel =>
|
||||
val base = AddressSet.misaligned(memPortParams.base, memPortParams.size)
|
||||
val filter = AddressSet(channel * mbus.blockBytes, ~((nMemoryChannels-1) * mbus.blockBytes))
|
||||
|
||||
AXI4SlavePortParameters(
|
||||
slaves = Seq(AXI4SlaveParameters(
|
||||
address = base.flatMap(_.intersect(filter)),
|
||||
resources = device.reg,
|
||||
regionType = RegionType.UNCACHED, // cacheable
|
||||
executable = true,
|
||||
supportsWrite = TransferSizes(1, mbus.blockBytes),
|
||||
supportsRead = TransferSizes(1, mbus.blockBytes),
|
||||
interleavedId = Some(0))), // slave does not interleave read responses
|
||||
beatBytes = memPortParams.beatBytes)
|
||||
})
|
||||
|
||||
memAXI4Node := mbus.toDRAMController(Some(portName)) {
|
||||
AXI4UserYanker() := AXI4IdIndexer(memPortParams.idBits) := TLToAXI4()
|
||||
}
|
||||
|
||||
memAXI4Node
|
||||
}
|
||||
}
|
||||
|
||||
/** Actually generates the corresponding IO in the concrete Module */
|
||||
trait CanHaveFASEDOptimizedMasterAXI4MemPortModuleImp extends LazyModuleImp {
|
||||
val outer: CanHaveFASEDOptimizedMasterAXI4MemPort
|
||||
|
||||
val mem_axi4 = outer.memAXI4Node.map(x => IO(HeterogeneousBag(AXI4BundleWithEdge.fromNode(x.in))))
|
||||
(mem_axi4 zip outer.memAXI4Node) foreach { case (io, node) =>
|
||||
(io zip node.in).foreach { case (io, (bundle, _)) => io <> bundle }
|
||||
}
|
||||
|
||||
def connectSimAXIMem() {
|
||||
(mem_axi4 zip outer.memAXI4Node).foreach { case (io, node) =>
|
||||
(io zip node.in).foreach { case (io, (_, edge)) =>
|
||||
val mem = LazyModule(new SimAXIMem(edge, size = p(ExtMem).get.master.size))
|
||||
Module(mem.module).io.axi4.head <> io
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Wires out tile trace ports to the top; and wraps them in a Bundle that the
|
||||
* TracerV endpoint can match on.
|
||||
*/
|
||||
object PrintTracePort extends Field[Boolean](false)
|
||||
|
||||
trait HasTraceIO {
|
||||
this: HasTiles =>
|
||||
val module: HasTraceIOImp
|
||||
|
||||
// Bind all the trace nodes to a BB; we'll use this to generate the IO in the imp
|
||||
val traceNexus = BundleBridgeNexus[Vec[TracedInstruction]]
|
||||
val tileTraceNodes = tiles.map(tile => tile.traceNode)
|
||||
tileTraceNodes foreach { traceNexus := _ }
|
||||
}
|
||||
|
||||
trait HasTraceIOImp extends LazyModuleImp {
|
||||
val outer: HasTraceIO
|
||||
|
||||
val traceIO = IO(Output(new TraceOutputTop(
|
||||
DeclockedTracedInstruction.fromNode(outer.traceNexus.in))))
|
||||
(traceIO.traces zip outer.traceNexus.in).foreach({ case (port, (tileTrace, _)) =>
|
||||
port := DeclockedTracedInstruction.fromVec(tileTrace)
|
||||
})
|
||||
|
||||
// Enabled to test TracerV trace capture
|
||||
if (p(PrintTracePort)) {
|
||||
val traceprint = Wire(UInt(512.W))
|
||||
traceprint := traceIO.asUInt
|
||||
printf("TRACEPORT: %x\n", traceprint)
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent MIDAS from synthesizing assertions in the dummy TLB included in BOOM
|
||||
trait ExcludeInvalidBoomAssertions extends LazyModuleImp {
|
||||
ExcludeInstanceAsserts(("NonBlockingDCache", "dtlb"))
|
||||
}
|
||||
|
||||
176
generators/firechip/src/main/scala/Targets.scala
Executable file
176
generators/firechip/src/main/scala/Targets.scala
Executable file
@@ -0,0 +1,176 @@
|
||||
package firesim.firesim
|
||||
|
||||
import chisel3._
|
||||
import freechips.rocketchip._
|
||||
import freechips.rocketchip.subsystem._
|
||||
import freechips.rocketchip.diplomacy._
|
||||
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, BoomSubsystemModuleImp}
|
||||
import icenet._
|
||||
import testchipip._
|
||||
import testchipip.SerialAdapter.SERIAL_IF_WIDTH
|
||||
import sifive.blocks.devices.uart._
|
||||
import midas.models.AXI4BundleWithEdge
|
||||
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 HasDefaultBusConfiguration
|
||||
with CanHaveFASEDOptimizedMasterAXI4MemPort
|
||||
with HasPeripheryBootROM
|
||||
with HasNoDebug
|
||||
with HasPeripherySerial
|
||||
with HasPeripheryUART
|
||||
with HasPeripheryIceNIC
|
||||
with HasPeripheryBlockDevice
|
||||
with HasTraceIO
|
||||
{
|
||||
override lazy val module = new FireSimModuleImp(this)
|
||||
}
|
||||
|
||||
class FireSimModuleImp[+L <: FireSim](l: L) extends RocketSubsystemModuleImp(l)
|
||||
with HasRTCModuleImp
|
||||
with CanHaveFASEDOptimizedMasterAXI4MemPortModuleImp
|
||||
with HasPeripheryBootROMModuleImp
|
||||
with HasNoDebugModuleImp
|
||||
with HasPeripherySerialModuleImp
|
||||
with HasPeripheryUARTModuleImp
|
||||
with HasPeripheryIceNICModuleImpValidOnly
|
||||
with HasPeripheryBlockDeviceModuleImp
|
||||
with HasTraceIOImp
|
||||
|
||||
|
||||
class FireSimNoNIC(implicit p: Parameters) extends RocketSubsystem
|
||||
with HasDefaultBusConfiguration
|
||||
with CanHaveFASEDOptimizedMasterAXI4MemPort
|
||||
with HasPeripheryBootROM
|
||||
with HasNoDebug
|
||||
with HasPeripherySerial
|
||||
with HasPeripheryUART
|
||||
with HasPeripheryBlockDevice
|
||||
with HasTraceIO
|
||||
{
|
||||
override lazy val module = new FireSimNoNICModuleImp(this)
|
||||
}
|
||||
|
||||
class FireSimNoNICModuleImp[+L <: FireSimNoNIC](l: L) extends RocketSubsystemModuleImp(l)
|
||||
with HasRTCModuleImp
|
||||
with CanHaveFASEDOptimizedMasterAXI4MemPortModuleImp
|
||||
with HasPeripheryBootROMModuleImp
|
||||
with HasNoDebugModuleImp
|
||||
with HasPeripherySerialModuleImp
|
||||
with HasPeripheryUARTModuleImp
|
||||
with HasPeripheryBlockDeviceModuleImp
|
||||
with HasTraceIOImp
|
||||
|
||||
|
||||
class FireBoom(implicit p: Parameters) extends BoomSubsystem
|
||||
with HasDefaultBusConfiguration
|
||||
with CanHaveFASEDOptimizedMasterAXI4MemPort
|
||||
with HasPeripheryBootROM
|
||||
with HasNoDebug
|
||||
with HasPeripherySerial
|
||||
with HasPeripheryUART
|
||||
with HasPeripheryIceNIC
|
||||
with HasPeripheryBlockDevice
|
||||
with HasTraceIO
|
||||
{
|
||||
override lazy val module = new FireBoomModuleImp(this)
|
||||
}
|
||||
|
||||
class FireBoomModuleImp[+L <: FireBoom](l: L) extends BoomSubsystemModuleImp(l)
|
||||
with HasRTCModuleImp
|
||||
with CanHaveFASEDOptimizedMasterAXI4MemPortModuleImp
|
||||
with HasPeripheryBootROMModuleImp
|
||||
with HasNoDebugModuleImp
|
||||
with HasPeripherySerialModuleImp
|
||||
with HasPeripheryUARTModuleImp
|
||||
with HasPeripheryIceNICModuleImpValidOnly
|
||||
with HasPeripheryBlockDeviceModuleImp
|
||||
with HasTraceIOImp
|
||||
with ExcludeInvalidBoomAssertions
|
||||
|
||||
class FireBoomNoNIC(implicit p: Parameters) extends BoomSubsystem
|
||||
with HasDefaultBusConfiguration
|
||||
with CanHaveFASEDOptimizedMasterAXI4MemPort
|
||||
with HasPeripheryBootROM
|
||||
with HasNoDebug
|
||||
with HasPeripherySerial
|
||||
with HasPeripheryUART
|
||||
with HasPeripheryBlockDevice
|
||||
with HasTraceIO
|
||||
{
|
||||
override lazy val module = new FireBoomNoNICModuleImp(this)
|
||||
}
|
||||
|
||||
class FireBoomNoNICModuleImp[+L <: FireBoomNoNIC](l: L) extends BoomSubsystemModuleImp(l)
|
||||
with HasRTCModuleImp
|
||||
with CanHaveFASEDOptimizedMasterAXI4MemPortModuleImp
|
||||
with HasPeripheryBootROMModuleImp
|
||||
with HasNoDebugModuleImp
|
||||
with HasPeripherySerialModuleImp
|
||||
with HasPeripheryUARTModuleImp
|
||||
with HasPeripheryBlockDeviceModuleImp
|
||||
with HasTraceIOImp
|
||||
with ExcludeInvalidBoomAssertions
|
||||
|
||||
case object NumNodes extends Field[Int]
|
||||
|
||||
class SupernodeIO(
|
||||
nNodes: Int,
|
||||
serialWidth: Int,
|
||||
bagPrototype: HeterogeneousBag[AXI4BundleWithEdge])(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.get))
|
||||
|
||||
io.mem_axi.zip(nodes.map(_.mem_axi4)).foreach {
|
||||
case (out, mem_axi4) => out <> mem_axi4.get
|
||||
}
|
||||
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
|
||||
} }
|
||||
}
|
||||
|
||||
138
generators/firechip/src/test/scala/ScalaTestSuite.scala
Normal file
138
generators/firechip/src/test/scala/ScalaTestSuite.scala
Normal file
@@ -0,0 +1,138 @@
|
||||
//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 scala.io.Source
|
||||
|
||||
import freechips.rocketchip.diplomacy._
|
||||
import freechips.rocketchip.system.{RocketTestSuite, BenchmarkTestSuite}
|
||||
import freechips.rocketchip.system.TestGeneration._
|
||||
import freechips.rocketchip.system.DefaultTestSuites._
|
||||
|
||||
import firesim.util.GeneratorArgs
|
||||
|
||||
abstract class FireSimTestSuite(
|
||||
topModuleClass: String,
|
||||
targetConfigs: String,
|
||||
platformConfigs: String,
|
||||
N: Int = 8
|
||||
) extends firesim.midasexamples.TestSuiteCommon with HasFireSimGeneratorUtilities {
|
||||
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 ++ "_WithScalaTestFeatures",
|
||||
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, additionalArgs: Seq[String] = Nil) = {
|
||||
make((Seq(s"${outDir.getAbsolutePath}/${name}.%s".format(if (debug) "vpd" else "out"),
|
||||
s"EMUL=${backend}")
|
||||
++ additionalArgs):_*)
|
||||
}
|
||||
|
||||
def runTest(backend: String, name: String, debug: Boolean, additionalArgs: Seq[String] = Nil) = {
|
||||
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, additionalArgs) == 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"
|
||||
}
|
||||
}
|
||||
|
||||
// Checks the collected trace log matches the behavior of a chisel printf
|
||||
def diffTracelog(verilatedLog: String) {
|
||||
behavior of "captured instruction trace"
|
||||
it should s"match the chisel printf in ${verilatedLog}" in {
|
||||
def getLines(file: File, dropLines: Int = 0): Seq[String] = {
|
||||
val lines = Source.fromFile(file).getLines.toList
|
||||
lines.filter(_.startsWith("TRACEPORT")).drop(dropLines)
|
||||
}
|
||||
val resetLength = 50
|
||||
val verilatedOutput = getLines(new File(outDir, s"/${verilatedLog}"))
|
||||
val synthPrintOutput = getLines(new File(genDir, s"/TRACEFILE"), resetLength + 1)
|
||||
assert(verilatedOutput.size == synthPrintOutput.size, "Outputs differ in length")
|
||||
assert(verilatedOutput.nonEmpty)
|
||||
for ( (vPrint, sPrint) <- verilatedOutput.zip(synthPrintOutput) ) {
|
||||
assert(vPrint == sPrint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clean
|
||||
mkdirs
|
||||
elaborateAndCompileWithMidas
|
||||
generateTestSuiteMakefrags
|
||||
runTest("verilator", "rv64ui-p-simple", false, Seq(s"""EXTRA_SIM_ARGS=+trace-test-output0"""))
|
||||
diffTracelog("rv64ui-p-simple.out")
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user