WIP
This commit is contained in:
parent
bc54b24b85
commit
c0d4e848ba
|
@ -31,3 +31,9 @@
|
||||||
[submodule "generators/hwacha"]
|
[submodule "generators/hwacha"]
|
||||||
path = generators/hwacha
|
path = generators/hwacha
|
||||||
url = git@github.com:ucb-bar/hwacha.git
|
url = git@github.com:ucb-bar/hwacha.git
|
||||||
|
[submodule "sims/firesim"]
|
||||||
|
path = sims/firesim
|
||||||
|
url = https://github.com/firesim/firesim.git
|
||||||
|
[submodule "generators/icenet"]
|
||||||
|
path = generators/icenet
|
||||||
|
url = https://github.com/firesim/icenet.git
|
||||||
|
|
84
build.sbt
84
build.sbt
|
@ -9,9 +9,9 @@ lazy val commonSettings = Seq(
|
||||||
case _ => MergeStrategy.first}},
|
case _ => MergeStrategy.first}},
|
||||||
scalacOptions ++= Seq("-deprecation","-unchecked","-Xsource:2.11"),
|
scalacOptions ++= Seq("-deprecation","-unchecked","-Xsource:2.11"),
|
||||||
libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.5" % "test",
|
libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.5" % "test",
|
||||||
libraryDependencies += "org.json4s" %% "json4s-native" % "3.6.1",
|
libraryDependencies += "org.json4s" %% "json4s-jackson" % "3.6.1",
|
||||||
libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value,
|
libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value,
|
||||||
libraryDependencies += "edu.berkeley.cs" %% "firrtl-interpreter" % "1.2-SNAPSHOT",
|
//libraryDependencies += "edu.berkeley.cs" %% "firrtl-interpreter" % "1.2-SNAPSHOT",
|
||||||
libraryDependencies += "com.github.scopt" %% "scopt" % "3.7.0",
|
libraryDependencies += "com.github.scopt" %% "scopt" % "3.7.0",
|
||||||
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full),
|
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full),
|
||||||
resolvers ++= Seq(
|
resolvers ++= Seq(
|
||||||
|
@ -19,18 +19,14 @@ lazy val commonSettings = Seq(
|
||||||
Resolver.sonatypeRepo("releases"),
|
Resolver.sonatypeRepo("releases"),
|
||||||
Resolver.mavenLocal))
|
Resolver.mavenLocal))
|
||||||
|
|
||||||
lazy val rebarFirrtl = (project in file("tools/firrtl"))
|
val rocketChipDir = file("generators/rocket-chip")
|
||||||
.settings(commonSettings)
|
|
||||||
|
|
||||||
lazy val rocketchip = RootProject(file("generators/rocket-chip"))
|
lazy val firesimAsLibrary = sys.env.get("FIRESIM_IS_TOP") == None
|
||||||
|
lazy val firesimDir = if (firesimAsLibrary) {
|
||||||
lazy val rebarrocketchip = project
|
file("sims/firesim/sim/")
|
||||||
.dependsOn(rocketchip)
|
} else {
|
||||||
.settings(commonSettings)
|
file("../../sim/")
|
||||||
|
}
|
||||||
lazy val testchipip = (project in file("generators/testchipip"))
|
|
||||||
.dependsOn(rebarrocketchip)
|
|
||||||
.settings(commonSettings)
|
|
||||||
|
|
||||||
// Checks for -DROCKET_USE_MAVEN.
|
// Checks for -DROCKET_USE_MAVEN.
|
||||||
// If it's there, use a maven dependency.
|
// If it's there, use a maven dependency.
|
||||||
|
@ -45,6 +41,42 @@ def conditionalDependsOn(prj: Project): Project = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Subproject definitions begin
|
||||||
|
|
||||||
|
// Biancolin: get to the bottom of these
|
||||||
|
//lazy val rebarFirrtl = (project in file("tools/firrtl"))
|
||||||
|
// .settings(commonSettings)
|
||||||
|
// Overlaps with the dependency-injected version
|
||||||
|
// lazy val rocketchip = RootProject(rocketChipDir)
|
||||||
|
|
||||||
|
// 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 = ProjectRef(firesimDir, "targetutils")
|
||||||
|
|
||||||
|
// Rocket-chip dependencies (subsumes making RC a RootProject)
|
||||||
|
lazy val hardfloat = (project in rocketChipDir / "hardfloat")
|
||||||
|
.settings(commonSettings).dependsOn(midasTargetUtils)
|
||||||
|
|
||||||
|
lazy val rocketMacros = (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 rebarRocketchip = (project in rocketChipDir / "src")
|
||||||
|
.settings(
|
||||||
|
commonSettings,
|
||||||
|
scalaSource in Compile := baseDirectory.value / "main" / "scala",
|
||||||
|
resourceDirectory in Compile := baseDirectory.value / "main" / "resources")
|
||||||
|
.dependsOn(chisel, hardfloat, rocketMacros)
|
||||||
|
|
||||||
|
lazy val testchipip = (project in file("generators/testchipip"))
|
||||||
|
.dependsOn(rebarRocketchip)
|
||||||
|
.settings(commonSettings)
|
||||||
|
|
||||||
lazy val example = conditionalDependsOn(project in file("generators/example"))
|
lazy val example = conditionalDependsOn(project in file("generators/example"))
|
||||||
.dependsOn(boom, hwacha, sifive_blocks)
|
.dependsOn(boom, hwacha, sifive_blocks)
|
||||||
.settings(commonSettings)
|
.settings(commonSettings)
|
||||||
|
@ -52,26 +84,38 @@ lazy val example = conditionalDependsOn(project in file("generators/example"))
|
||||||
lazy val utilities = conditionalDependsOn(project in file("generators/utilities"))
|
lazy val utilities = conditionalDependsOn(project in file("generators/utilities"))
|
||||||
.settings(commonSettings)
|
.settings(commonSettings)
|
||||||
|
|
||||||
lazy val hwacha = (project in file ("generators/hwacha"))
|
lazy val icenet = (project in file("generators/icenet"))
|
||||||
.dependsOn(rebarrocketchip)
|
.dependsOn(rebarRocketchip, testchipip)
|
||||||
|
.settings(commonSettings)
|
||||||
|
|
||||||
|
lazy val hwacha = (project in file("generators/hwacha"))
|
||||||
|
.dependsOn(rebarRocketchip)
|
||||||
.settings(commonSettings)
|
.settings(commonSettings)
|
||||||
|
|
||||||
lazy val boom = (project in file("generators/boom"))
|
lazy val boom = (project in file("generators/boom"))
|
||||||
.dependsOn(rebarrocketchip)
|
.dependsOn(rebarRocketchip)
|
||||||
.settings(commonSettings)
|
.settings(commonSettings)
|
||||||
|
|
||||||
lazy val tapeout = conditionalDependsOn(project in file("./tools/barstools/tapeout/"))
|
lazy val tapeout = conditionalDependsOn(project in file("./tools/barstools/tapeout/"))
|
||||||
.dependsOn(rebarFirrtl)
|
|
||||||
.settings(commonSettings)
|
.settings(commonSettings)
|
||||||
|
|
||||||
lazy val mdf = (project in file("./tools/barstools/mdf/scalalib/"))
|
lazy val mdf = (project in file("./tools/barstools/mdf/scalalib/"))
|
||||||
.settings(commonSettings)
|
.settings(commonSettings)
|
||||||
|
|
||||||
lazy val `barstools-macros` = (project in file("./tools/barstools/macros/"))
|
lazy val barstoolsMacros = (project in file("./tools/barstools/macros/"))
|
||||||
.dependsOn(mdf, rebarrocketchip, rebarFirrtl)
|
.dependsOn(mdf, rebarRocketchip)
|
||||||
.enablePlugins(sbtassembly.AssemblyPlugin)
|
.enablePlugins(sbtassembly.AssemblyPlugin)
|
||||||
.settings(commonSettings)
|
.settings(commonSettings)
|
||||||
|
|
||||||
lazy val sifive_blocks = (project in file("generators/sifive-blocks"))
|
lazy val sifive_blocks = (project in file("generators/sifive-blocks"))
|
||||||
.dependsOn(rebarrocketchip)
|
.dependsOn(rebarRocketchip)
|
||||||
.settings(commonSettings)
|
.settings(commonSettings)
|
||||||
|
|
||||||
|
// Library components of FireSim
|
||||||
|
lazy val midas = ProjectRef(firesimDir, "midas")
|
||||||
|
lazy val firesimLib = ProjectRef(firesimDir, "firesimLib")
|
||||||
|
|
||||||
|
lazy val firechip = (project in file("generators/firechip"))
|
||||||
|
.dependsOn(boom, icenet, testchipip, sifive_blocks, midasTargetUtils, midas, firesimLib % "test->test;compile->compile")
|
||||||
|
.settings(commonSettings)
|
||||||
|
|
||||||
|
|
12
common.mk
12
common.mk
|
@ -8,23 +8,25 @@ SHELL=/bin/bash
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
lookup_scala_srcs = $(shell find -L $(1)/ -iname "*.scala" 2> /dev/null)
|
lookup_scala_srcs = $(shell find -L $(1)/ -iname "*.scala" 2> /dev/null)
|
||||||
|
|
||||||
PACKAGES=rocket-chip testchipip boom hwacha sifive-blocks example
|
PACKAGES=$(addprefix generators/, rocket-chip testchipip boom hwacha sifive-blocks example) \
|
||||||
SCALA_SOURCES=$(foreach pkg,$(PACKAGES),$(call lookup_scala_srcs,$(base_dir)/generators/$(pkg)/src/main/scala))
|
$(addprefix sims/firesim/sim/, . firesim-lib midas midas/targetutils)
|
||||||
|
SCALA_SOURCES=$(foreach pkg,$(PACKAGES),$(call lookup_scala_srcs,$(base_dir)/$(pkg)/src/main/scala))
|
||||||
|
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
# rocket and testchipip classes
|
# rocket and testchipip classes
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
ROCKET_CLASSES ?= "$(ROCKETCHIP_DIR)/target/scala-$(SCALA_VERSION_MAJOR)/classes:$(ROCKETCHIP_DIR)/chisel3/target/scala-$(SCALA_VERSION_MAJOR)/*"
|
# NB: target/ lives under source ----V , due to how we're handling midas dependency injection
|
||||||
|
ROCKET_CLASSES ?= "$(ROCKETCHIP_DIR)/src/target/scala-$(SCALA_VERSION_MAJOR)/classes:$(ROCKETCHIP_DIR)/chisel3/target/scala-$(SCALA_VERSION_MAJOR)/*"
|
||||||
TESTCHIPIP_CLASSES ?= "$(TESTCHIP_DIR)/target/scala-$(SCALA_VERSION_MAJOR)/classes"
|
TESTCHIPIP_CLASSES ?= "$(TESTCHIP_DIR)/target/scala-$(SCALA_VERSION_MAJOR)/classes"
|
||||||
|
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
# jar creation variables and rules
|
# jar creation variables and rules
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
FIRRTL_JAR ?= $(ROCKETCHIP_DIR)/lib/firrtl.jar
|
FIRRTL_JAR := $(base_dir)/lib/firrtl.jar
|
||||||
|
|
||||||
$(FIRRTL_JAR): $(call lookup_scala_srcs, $(REBAR_FIRRTL_DIR)/src/main/scala)
|
$(FIRRTL_JAR): $(call lookup_scala_srcs, $(REBAR_FIRRTL_DIR)/src/main/scala)
|
||||||
$(MAKE) -C $(REBAR_FIRRTL_DIR) SBT="$(SBT)" root_dir=$(REBAR_FIRRTL_DIR) build-scala
|
$(MAKE) -C $(REBAR_FIRRTL_DIR) SBT="$(SBT)" root_dir=$(REBAR_FIRRTL_DIR) build-scala
|
||||||
mkdir -p $(dir $@)
|
mkdir -p $(@D)
|
||||||
cp -p $(REBAR_FIRRTL_DIR)/utils/bin/firrtl.jar $@
|
cp -p $(REBAR_FIRRTL_DIR)/utils/bin/firrtl.jar $@
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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)
|
||||||
|
|
|
@ -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"))
|
|
@ -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"))
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit bba264d68d366180f6f9b55061ee9408425d8229
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit ccfd85aa287bd158b87ab9160cb599ec7534553b
|
|
@ -0,0 +1,79 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "mmio.h"
|
||||||
|
#include "blkdev.h"
|
||||||
|
|
||||||
|
#define SECTOR_WORDS (BLKDEV_SECTOR_SIZE / sizeof(uint64_t))
|
||||||
|
#define TEST_SECTORS 128
|
||||||
|
|
||||||
|
unsigned long sector_buf[SECTOR_WORDS];
|
||||||
|
|
||||||
|
void write_sector(unsigned int secnum)
|
||||||
|
{
|
||||||
|
int req_tag, resp_tag;
|
||||||
|
|
||||||
|
for (int i = 0; i < SECTOR_WORDS; i++)
|
||||||
|
sector_buf[i] = (secnum << 6) | i;
|
||||||
|
|
||||||
|
while (reg_read8(BLKDEV_NREQUEST) == 0);
|
||||||
|
req_tag = blkdev_send_request((unsigned long) sector_buf, secnum, 1, 1);
|
||||||
|
while (reg_read8(BLKDEV_NCOMPLETE) == 0);
|
||||||
|
resp_tag = reg_read8(BLKDEV_COMPLETE);
|
||||||
|
|
||||||
|
if (req_tag != resp_tag) {
|
||||||
|
printf("Response tag %d does not match request tag %d\n",
|
||||||
|
req_tag, resp_tag);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_sector(unsigned int secnum)
|
||||||
|
{
|
||||||
|
int req_tag, resp_tag;
|
||||||
|
|
||||||
|
while (reg_read8(BLKDEV_NREQUEST) == 0);
|
||||||
|
req_tag = blkdev_send_request((unsigned long) sector_buf, secnum, 1, 0);
|
||||||
|
while (reg_read8(BLKDEV_NCOMPLETE) == 0);
|
||||||
|
resp_tag = reg_read8(BLKDEV_COMPLETE);
|
||||||
|
|
||||||
|
if (req_tag != resp_tag) {
|
||||||
|
printf("Response tag %d does not match request tag %d\n",
|
||||||
|
req_tag, resp_tag);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < SECTOR_WORDS; i++) {
|
||||||
|
unsigned long expected = (secnum << 6) | i;
|
||||||
|
unsigned long actual = sector_buf[i];
|
||||||
|
if (actual != expected) {
|
||||||
|
printf("Word %d in sector %x does not match expected\n",
|
||||||
|
i, secnum);
|
||||||
|
printf("Expected %lx, got %lx\n",
|
||||||
|
expected, actual);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
unsigned int nsectors = blkdev_nsectors();
|
||||||
|
unsigned int stride = nsectors / TEST_SECTORS;
|
||||||
|
|
||||||
|
printf("Writing %u of %u sectors\n", TEST_SECTORS, nsectors);
|
||||||
|
|
||||||
|
for (int i = 0; i < TEST_SECTORS; i++) {
|
||||||
|
int sector = i * stride;
|
||||||
|
write_sector(sector);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Checking sectors\n", nsectors);
|
||||||
|
|
||||||
|
for (int i = 0; i < TEST_SECTORS; i++) {
|
||||||
|
int sector = i * stride;
|
||||||
|
check_sector(sector);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
#include "mmio.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "nic.h"
|
||||||
|
#include "encoding.h"
|
||||||
|
|
||||||
|
#define NPACKETS 10
|
||||||
|
#define TEST_OFFSET 3
|
||||||
|
#define TEST_LEN 356
|
||||||
|
#define ARRAY_LEN 360
|
||||||
|
#define NTRIALS 3
|
||||||
|
|
||||||
|
uint32_t src[NPACKETS][ARRAY_LEN];
|
||||||
|
uint32_t dst[NPACKETS][ARRAY_LEN];
|
||||||
|
uint64_t lengths[NPACKETS];
|
||||||
|
|
||||||
|
static inline void send_recv()
|
||||||
|
{
|
||||||
|
uint64_t send_packet, recv_addr;
|
||||||
|
int ncomps, send_comps_left = NPACKETS, recv_comps_left = NPACKETS;
|
||||||
|
int recv_idx = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < NPACKETS; i++) {
|
||||||
|
uint64_t pkt_size = TEST_LEN * sizeof(uint32_t);
|
||||||
|
uint64_t src_addr = (uint64_t) &src[i][TEST_OFFSET];
|
||||||
|
send_packet = (pkt_size << 48) | src_addr;
|
||||||
|
recv_addr = (uint64_t) dst[i];
|
||||||
|
reg_write64(SIMPLENIC_SEND_REQ, send_packet);
|
||||||
|
reg_write64(SIMPLENIC_RECV_REQ, recv_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (send_comps_left > 0 || recv_comps_left > 0) {
|
||||||
|
ncomps = nic_send_comp_avail();
|
||||||
|
asm volatile ("fence");
|
||||||
|
for (int i = 0; i < ncomps; i++)
|
||||||
|
reg_read16(SIMPLENIC_SEND_COMP);
|
||||||
|
send_comps_left -= ncomps;
|
||||||
|
|
||||||
|
ncomps = nic_recv_comp_avail();
|
||||||
|
asm volatile ("fence");
|
||||||
|
for (int i = 0; i < ncomps; i++) {
|
||||||
|
lengths[recv_idx] = reg_read16(SIMPLENIC_RECV_COMP);
|
||||||
|
recv_idx++;
|
||||||
|
}
|
||||||
|
recv_comps_left -= ncomps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_test(void)
|
||||||
|
{
|
||||||
|
unsigned long start, end;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
memset(dst, 0, sizeof(dst));
|
||||||
|
asm volatile ("fence");
|
||||||
|
|
||||||
|
start = rdcycle();
|
||||||
|
send_recv();
|
||||||
|
end = rdcycle();
|
||||||
|
|
||||||
|
printf("send/recv %lu cycles\n", end - start);
|
||||||
|
|
||||||
|
for (i = 0; i < NPACKETS; i++) {
|
||||||
|
if (lengths[i] != TEST_LEN * sizeof(uint32_t)) {
|
||||||
|
printf("recv got wrong # bytes\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j < TEST_LEN; j++) {
|
||||||
|
if (dst[i][j] != src[i][j + TEST_OFFSET]) {
|
||||||
|
printf("Data mismatch @ %d, %d: %x != %x\n",
|
||||||
|
i, j, dst[i][j], src[i][j + TEST_OFFSET]);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < NPACKETS; i++) {
|
||||||
|
for (j = 0; j < ARRAY_LEN; j++)
|
||||||
|
src[i][j] = i * ARRAY_LEN + j;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < NTRIALS; i++) {
|
||||||
|
printf("Trial %d\n", i);
|
||||||
|
run_test();
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("All correct\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -8,22 +8,22 @@
|
||||||
|
|
||||||
static inline int nic_send_req_avail(void)
|
static inline int nic_send_req_avail(void)
|
||||||
{
|
{
|
||||||
return reg_read16(SIMPLENIC_COUNTS) & 0xf;
|
return reg_read32(SIMPLENIC_COUNTS) & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int nic_recv_req_avail(void)
|
static inline int nic_recv_req_avail(void)
|
||||||
{
|
{
|
||||||
return (reg_read16(SIMPLENIC_COUNTS) >> 4) & 0xf;
|
return (reg_read32(SIMPLENIC_COUNTS) >> 8) & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int nic_send_comp_avail(void)
|
static inline int nic_send_comp_avail(void)
|
||||||
{
|
{
|
||||||
return (reg_read16(SIMPLENIC_COUNTS) >> 8) & 0xf;
|
return (reg_read32(SIMPLENIC_COUNTS) >> 16) & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int nic_recv_comp_avail(void)
|
static inline int nic_recv_comp_avail(void)
|
||||||
{
|
{
|
||||||
return (reg_read16(SIMPLENIC_COUNTS) >> 12) & 0xf;
|
return (reg_read32(SIMPLENIC_COUNTS) >> 24) & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nic_send(void *data, unsigned long len)
|
static void nic_send(void *data, unsigned long len)
|
||||||
|
|
|
@ -0,0 +1,254 @@
|
||||||
|
#include "mmio.h"
|
||||||
|
#include "nic.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define ETH_MAX_WORDS 190
|
||||||
|
#define NET_IP_ALIGN 2
|
||||||
|
#define ETH_HEADER_SIZE 14
|
||||||
|
#define MAC_ADDR_SIZE 6
|
||||||
|
#define IP_ADDR_SIZE 4
|
||||||
|
|
||||||
|
#define IPV4_ETHTYPE 0x0800
|
||||||
|
#define ARP_ETHTYPE 0x0806
|
||||||
|
#define ICMP_PROT 1
|
||||||
|
#define ECHO_REPLY 0
|
||||||
|
#define ECHO_REQUEST 8
|
||||||
|
#define ARP_REQUEST 1
|
||||||
|
#define ARP_REPLY 2
|
||||||
|
#define HTYPE_ETH 1
|
||||||
|
|
||||||
|
static inline uint16_t ntohs(uint16_t nint)
|
||||||
|
{
|
||||||
|
return ((nint & 0xff) << 8) | ((nint >> 8) & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint16_t htons(uint16_t nint)
|
||||||
|
{
|
||||||
|
return ntohs(nint);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct eth_header {
|
||||||
|
uint8_t padding[NET_IP_ALIGN];
|
||||||
|
uint8_t dst_mac[MAC_ADDR_SIZE];
|
||||||
|
uint8_t src_mac[MAC_ADDR_SIZE];
|
||||||
|
uint16_t ethtype;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct arp_header {
|
||||||
|
uint16_t htype;
|
||||||
|
uint16_t ptype;
|
||||||
|
uint8_t hlen;
|
||||||
|
uint8_t plen;
|
||||||
|
uint16_t oper;
|
||||||
|
uint8_t sha[MAC_ADDR_SIZE];
|
||||||
|
uint8_t spa[IP_ADDR_SIZE];
|
||||||
|
uint8_t tha[MAC_ADDR_SIZE];
|
||||||
|
uint8_t tpa[IP_ADDR_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ipv4_header {
|
||||||
|
uint8_t ver_ihl;
|
||||||
|
uint8_t dscp_ecn;
|
||||||
|
uint16_t length;
|
||||||
|
uint16_t ident;
|
||||||
|
uint16_t flags_frag_off;
|
||||||
|
uint8_t ttl;
|
||||||
|
uint8_t prot;
|
||||||
|
uint16_t cksum;
|
||||||
|
uint32_t src_addr;
|
||||||
|
uint32_t dst_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct icmp_header {
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t code;
|
||||||
|
uint16_t cksum;
|
||||||
|
uint32_t rest;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int checksum(uint16_t *data, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint32_t sum = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
sum += ntohs(data[i]);
|
||||||
|
|
||||||
|
while ((sum >> 16) != 0)
|
||||||
|
sum = (sum & 0xffff) + (sum >> 16);
|
||||||
|
|
||||||
|
sum = ~sum & 0xffff;
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ceil_div(n, d) (((n) - 1) / (d) + 1)
|
||||||
|
|
||||||
|
static int process_arp(void *buf, uint8_t *mac)
|
||||||
|
{
|
||||||
|
struct eth_header *eth = buf;
|
||||||
|
struct arp_header *arp;
|
||||||
|
size_t size = ETH_HEADER_SIZE + sizeof(*arp);
|
||||||
|
uint8_t tmp_addr[IP_ADDR_SIZE];
|
||||||
|
|
||||||
|
// Verify arp packet
|
||||||
|
arp = buf + sizeof(*eth);
|
||||||
|
if (ntohs(arp->oper) != ARP_REQUEST) {
|
||||||
|
printf("Wrong arp operation: %d\n", ntohs(arp->oper));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ntohs(arp->htype) != HTYPE_ETH) {
|
||||||
|
printf("Wrong ARP HTYPE\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ntohs(arp->ptype) != IPV4_ETHTYPE) {
|
||||||
|
printf("Wrong ARP PTYPE\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arp->hlen != 6) {
|
||||||
|
printf("Wrong ARP HLEN: %d\n", arp->hlen);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arp->plen != 4) {
|
||||||
|
printf("Wrong ARP PLEN: %d\n", arp->plen);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the source the destination, and add our mac address
|
||||||
|
memcpy(eth->dst_mac, eth->src_mac, MAC_ADDR_SIZE);
|
||||||
|
memcpy(eth->src_mac, mac, MAC_ADDR_SIZE);
|
||||||
|
|
||||||
|
// create ARP reply
|
||||||
|
arp->oper = htons(ARP_REPLY);
|
||||||
|
|
||||||
|
// Make tha the sha, and fill in sha with actual mac address
|
||||||
|
memcpy(arp->tha, arp->sha, MAC_ADDR_SIZE);
|
||||||
|
memcpy(arp->sha, mac, MAC_ADDR_SIZE);
|
||||||
|
|
||||||
|
// Swap spa and tpa in arp packet
|
||||||
|
memcpy(tmp_addr, arp->tpa, IP_ADDR_SIZE);
|
||||||
|
memcpy(arp->tpa, arp->spa, IP_ADDR_SIZE);
|
||||||
|
memcpy(arp->spa, tmp_addr, IP_ADDR_SIZE);
|
||||||
|
|
||||||
|
size = ceil_div(size + NET_IP_ALIGN, 8) * 8;
|
||||||
|
nic_send(buf, size);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static int process_icmp(void *buf, uint8_t *mac)
|
||||||
|
{
|
||||||
|
struct eth_header *eth = buf;
|
||||||
|
struct ipv4_header *ipv4;
|
||||||
|
struct icmp_header *icmp;
|
||||||
|
int ihl, icmp_size;
|
||||||
|
ssize_t size;
|
||||||
|
uint32_t tmp_addr;
|
||||||
|
|
||||||
|
// verify IPv4
|
||||||
|
ipv4 = buf + sizeof(*eth);
|
||||||
|
ihl = ipv4->ver_ihl & 0xf;
|
||||||
|
|
||||||
|
if (checksum((uint16_t *) ipv4, ihl << 1) != 0) {
|
||||||
|
printf("Bad IP header checksum %04x\n", ipv4->cksum);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ipv4->prot != ICMP_PROT) {
|
||||||
|
printf("Wrong IP protocol %d\n", ipv4->prot);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify ICMP
|
||||||
|
icmp = (buf + sizeof(*eth) + (ihl << 2));
|
||||||
|
|
||||||
|
if (icmp->type != ECHO_REQUEST) {
|
||||||
|
printf("Wrong ICMP type %d\n", icmp->type);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (icmp->code != 0) {
|
||||||
|
printf("Wrong ICMP code %d\n", icmp->code);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
icmp_size = ntohs(ipv4->length) - (ihl << 2);
|
||||||
|
if (checksum((uint16_t *) icmp, icmp_size >> 1) != 0) {
|
||||||
|
printf("Bad ICMP checksum %04x\n", icmp->cksum);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the destination and source MACs
|
||||||
|
memcpy(eth->dst_mac, eth->src_mac, MAC_ADDR_SIZE);
|
||||||
|
memcpy(eth->src_mac, mac, MAC_ADDR_SIZE);
|
||||||
|
|
||||||
|
// Swap the source and destination IP addresses
|
||||||
|
tmp_addr = ipv4->dst_addr;
|
||||||
|
ipv4->dst_addr = ipv4->src_addr;
|
||||||
|
ipv4->src_addr = tmp_addr;
|
||||||
|
|
||||||
|
// compute the IPv4 header checksum
|
||||||
|
ipv4->cksum = 0;
|
||||||
|
ipv4->cksum = htons(checksum((uint16_t *) ipv4, ihl << 1));
|
||||||
|
|
||||||
|
// set the ICMP type to reply and compute checksum
|
||||||
|
icmp->cksum = 0;
|
||||||
|
icmp->type = ECHO_REPLY;
|
||||||
|
icmp->cksum = htons(checksum((uint16_t *) icmp, icmp_size >> 1));
|
||||||
|
size = ntohs(ipv4->length) + ETH_HEADER_SIZE;
|
||||||
|
|
||||||
|
size = ceil_div(size + NET_IP_ALIGN, 8) * 8;
|
||||||
|
nic_send(buf, size);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int process_packet(void *buf, uint8_t *mac)
|
||||||
|
{
|
||||||
|
struct eth_header *eth;
|
||||||
|
|
||||||
|
// read the ICMP request
|
||||||
|
nic_recv(buf);
|
||||||
|
eth = buf;
|
||||||
|
printf("Got packet: [ethtype=%04x]\n", ntohs(eth->ethtype));
|
||||||
|
// Check ethernet type
|
||||||
|
switch (ntohs(eth->ethtype)) {
|
||||||
|
case IPV4_ETHTYPE:
|
||||||
|
return process_icmp(buf, mac);
|
||||||
|
case ARP_ETHTYPE:
|
||||||
|
return process_arp(buf, mac);
|
||||||
|
default:
|
||||||
|
printf("Wrong ethtype %x\n", ntohs(eth->ethtype));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t buffer[ETH_MAX_WORDS];
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
uint64_t macaddr_long;
|
||||||
|
uint8_t *macaddr;
|
||||||
|
|
||||||
|
macaddr_long = nic_macaddr();
|
||||||
|
macaddr = (uint8_t *) &macaddr_long;
|
||||||
|
|
||||||
|
printf("macaddr - %02x", macaddr[0]);
|
||||||
|
for (int i = 1; i < MAC_ADDR_SIZE; i++)
|
||||||
|
printf(":%02x", macaddr[i]);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (process_packet(buffer, macaddr))
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
12
variables.mk
12
variables.mk
|
@ -86,6 +86,18 @@ ifeq ($(SUB_PROJECT),hwacha)
|
||||||
TB ?= TestDriver
|
TB ?= TestDriver
|
||||||
TOP ?= ExampleRocketSystem
|
TOP ?= ExampleRocketSystem
|
||||||
endif
|
endif
|
||||||
|
# Stand-in firechip variables
|
||||||
|
ifeq ($(SUB_PROJECT),firechip)
|
||||||
|
SBT_PROJECT ?= $(SUB_PROJECT)
|
||||||
|
MODEL ?= TestHarness
|
||||||
|
VLOG_MODEL ?= TestHarness
|
||||||
|
MODEL_PACKAGE ?= firesim.firesim
|
||||||
|
CONFIG ?= FireSimRocketChipConfig
|
||||||
|
CONFIG_PACKAGE ?= firesim.firesim
|
||||||
|
GENERATOR_PACKAGE ?= firesim.firesim
|
||||||
|
TB ?= TestDriver
|
||||||
|
TOP ?= ExampleRocketSystem
|
||||||
|
endif
|
||||||
|
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
# path to rocket-chip and testchipip
|
# path to rocket-chip and testchipip
|
||||||
|
|
Loading…
Reference in New Issue