This commit is contained in:
David Biancolin 2019-05-27 22:53:05 +00:00
parent bc54b24b85
commit c0d4e848ba
17 changed files with 1399 additions and 29 deletions

6
.gitmodules vendored
View File

@ -31,3 +31,9 @@
[submodule "generators/hwacha"]
path = generators/hwacha
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

View File

@ -9,9 +9,9 @@ lazy val commonSettings = Seq(
case _ => MergeStrategy.first}},
scalacOptions ++= Seq("-deprecation","-unchecked","-Xsource:2.11"),
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 += "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",
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full),
resolvers ++= Seq(
@ -19,18 +19,14 @@ lazy val commonSettings = Seq(
Resolver.sonatypeRepo("releases"),
Resolver.mavenLocal))
lazy val rebarFirrtl = (project in file("tools/firrtl"))
.settings(commonSettings)
val rocketChipDir = file("generators/rocket-chip")
lazy val rocketchip = RootProject(file("generators/rocket-chip"))
lazy val rebarrocketchip = project
.dependsOn(rocketchip)
.settings(commonSettings)
lazy val testchipip = (project in file("generators/testchipip"))
.dependsOn(rebarrocketchip)
.settings(commonSettings)
lazy val firesimAsLibrary = sys.env.get("FIRESIM_IS_TOP") == None
lazy val firesimDir = if (firesimAsLibrary) {
file("sims/firesim/sim/")
} else {
file("../../sim/")
}
// Checks for -DROCKET_USE_MAVEN.
// 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"))
.dependsOn(boom, hwacha, sifive_blocks)
.settings(commonSettings)
@ -52,26 +84,38 @@ lazy val example = conditionalDependsOn(project in file("generators/example"))
lazy val utilities = conditionalDependsOn(project in file("generators/utilities"))
.settings(commonSettings)
lazy val hwacha = (project in file ("generators/hwacha"))
.dependsOn(rebarrocketchip)
lazy val icenet = (project in file("generators/icenet"))
.dependsOn(rebarRocketchip, testchipip)
.settings(commonSettings)
lazy val hwacha = (project in file("generators/hwacha"))
.dependsOn(rebarRocketchip)
.settings(commonSettings)
lazy val boom = (project in file("generators/boom"))
.dependsOn(rebarrocketchip)
.dependsOn(rebarRocketchip)
.settings(commonSettings)
lazy val tapeout = conditionalDependsOn(project in file("./tools/barstools/tapeout/"))
.dependsOn(rebarFirrtl)
.settings(commonSettings)
lazy val mdf = (project in file("./tools/barstools/mdf/scalalib/"))
.settings(commonSettings)
lazy val `barstools-macros` = (project in file("./tools/barstools/macros/"))
.dependsOn(mdf, rebarrocketchip, rebarFirrtl)
lazy val barstoolsMacros = (project in file("./tools/barstools/macros/"))
.dependsOn(mdf, rebarRocketchip)
.enablePlugins(sbtassembly.AssemblyPlugin)
.settings(commonSettings)
lazy val sifive_blocks = (project in file("generators/sifive-blocks"))
.dependsOn(rebarrocketchip)
.dependsOn(rebarRocketchip)
.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)

View File

@ -8,23 +8,25 @@ SHELL=/bin/bash
#########################################################################################
lookup_scala_srcs = $(shell find -L $(1)/ -iname "*.scala" 2> /dev/null)
PACKAGES=rocket-chip testchipip boom hwacha sifive-blocks example
SCALA_SOURCES=$(foreach pkg,$(PACKAGES),$(call lookup_scala_srcs,$(base_dir)/generators/$(pkg)/src/main/scala))
PACKAGES=$(addprefix generators/, rocket-chip testchipip boom hwacha sifive-blocks example) \
$(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_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"
#########################################################################################
# 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)
$(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 $@
touch $@

View 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
}

View 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)

View 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)

View File

@ -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"))

View 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"))
}

View 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
} }
}

View 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)
}

1
generators/icenet Submodule

@ -0,0 +1 @@
Subproject commit bba264d68d366180f6f9b55061ee9408425d8229

1
sims/firesim Submodule

@ -0,0 +1 @@
Subproject commit ccfd85aa287bd158b87ab9160cb599ec7534553b

79
tests/big-blkdev.c Normal file
View File

@ -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;
}

98
tests/nic-loopback.c Normal file
View File

@ -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;
}

View File

@ -8,22 +8,22 @@
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)
{
return (reg_read16(SIMPLENIC_COUNTS) >> 4) & 0xf;
return (reg_read32(SIMPLENIC_COUNTS) >> 8) & 0xff;
}
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)
{
return (reg_read16(SIMPLENIC_COUNTS) >> 12) & 0xf;
return (reg_read32(SIMPLENIC_COUNTS) >> 24) & 0xff;
}
static void nic_send(void *data, unsigned long len)

254
tests/pingd.c Normal file
View File

@ -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;
}

View File

@ -86,6 +86,18 @@ ifeq ($(SUB_PROJECT),hwacha)
TB ?= TestDriver
TOP ?= ExampleRocketSystem
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