From b0053b5d346e39a0308855abadb99c5d86ba53ea Mon Sep 17 00:00:00 2001 From: Avimitin Date: Sat, 24 Aug 2024 15:19:56 +0800 Subject: [PATCH 1/5] [nix] add 'dev-mode' into nix It is incovenient for users to always input strings like ".#t1.blastoise.ip.cases.mlir.hello.emu-result". So here is an env to help improve the current situation. With the "dev-mode" shell, users will have many bash function to help them set the current development "mode". For example, if users want to test "intrinsic.linear_optimisation" with VCS emulator, and compare the result with verilator-emulator, they will have to write "nix build .#t1.blastoise.ip.vcs-emu.cases.intrinsic.linear_optimisation", then ".#t1.blastoise.ip.verilator-emu.cases.intrinsic.linear_optimisation" With the new script, the test flow is separate into different phrases: * Firstly, get into the dev-mode shell: `nix develop .#dev-mode` * Then, set the config: `set_config blastoise` * Users can inspect RTL with simple command too: `build vcs-emu-rtl` * To switch between verilator and VCS, they can use: `set_emulator vcs-emu` or `set_emulator verilator-emu` * Finally, run the case: `test intrinsic.linear_optimisation` Signed-off-by: Avimitin --- nix/overlay.nix | 1 + nix/pkgs/dev-mode/default.nix | 8 ++ nix/pkgs/dev-mode/dev-mode.sh | 263 ++++++++++++++++++++++++++++++++++ tests/pytorch/default.nix | 2 +- 4 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 nix/pkgs/dev-mode/default.nix create mode 100644 nix/pkgs/dev-mode/dev-mode.sh diff --git a/nix/overlay.nix b/nix/overlay.nix index 20b69d081..a11d3d703 100644 --- a/nix/overlay.nix +++ b/nix/overlay.nix @@ -46,6 +46,7 @@ rec { t1-script = final.callPackage ../script { }; inherit (t1-script) t1-helper ci-helper; + dev-mode = final.callPackage ./pkgs/dev-mode { }; # stdenv for compiling rvv programs, with ilp32f newlib and clang rv32-stdenv = rv32_pkgs.stdenv.override { diff --git a/nix/pkgs/dev-mode/default.nix b/nix/pkgs/dev-mode/default.nix new file mode 100644 index 000000000..e76256bc2 --- /dev/null +++ b/nix/pkgs/dev-mode/default.nix @@ -0,0 +1,8 @@ +{ mkShellNoCC, jq, ncurses, gettext }: +mkShellNoCC { + name = "t1-dev-mode"; + nativeBuildInputs = [ jq ncurses gettext ]; + shellHook = '' + source ${./dev-mode.sh} + ''; +} diff --git a/nix/pkgs/dev-mode/dev-mode.sh b/nix/pkgs/dev-mode/dev-mode.sh new file mode 100644 index 000000000..20f791403 --- /dev/null +++ b/nix/pkgs/dev-mode/dev-mode.sh @@ -0,0 +1,263 @@ +export TMPDIR=/tmp + +# prefer terminal safe colored and bold text when tput is supported +if tput setaf 0 &>/dev/null; then + ALL_OFF="$(tput sgr0)" + BOLD="$(tput bold)" + BLUE="${BOLD}$(tput setaf 4)" + GREEN="${BOLD}$(tput setaf 2)" + RED="${BOLD}$(tput setaf 1)" + YELLOW="${BOLD}$(tput setaf 3)" +else + ALL_OFF="\e[0m" + BOLD="\e[1m" + BLUE="${BOLD}\e[34m" + GREEN="${BOLD}\e[32m" + RED="${BOLD}\e[31m" + YELLOW="${BOLD}\e[33m" +fi +readonly ALL_OFF BOLD BLUE GREEN RED YELLOW + +info() { + local mesg=$1; shift + printf "${GREEN}[T1]${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" +} + +info2() { + local mesg=$1; shift + printf "${BLUE} ->${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" +} + +error() { + local mesg=$1; shift + printf "${RED}[T1] $(gettext "ERROR:")${ALL_OFF}${BOLD} ${mesg}${ALL_OFF}\n" "$@" >&2 +} + +_ROOT_PATTERN="flake.nix" +if [ ! -r "$_ROOT_PATTERN" ]; then + error "Not in T1 root directory" "Please run nix develop at the root of the T1 project directory" + exit 1 +fi + +mkdir -p .cache/dev-mode +_CTX=.cache/dev-mode/state.json +if [ ! -r "$_CTX" ]; then + printf "{}" > "$_CTX" +fi + +_CFG="" +get_config() { + local cfg=$(jq -r ".config" "$_CTX") + _CFG="$cfg" + echo "$_CFG" +} + +_config_is_set() { + _CFG=$(get_config) + if [[ -z "$_CFG" || "$_CFG" = "null" ]]; then + info "Config not set yet, use 'set_config ' to set config" + info2 "Available configs: ${BLUE}$(list_config | xargs)${ALL_OFF}" + return 1 + else + return 0 + fi +} + +list_config() { + nix --no-warn-dirty eval ".#t1.allConfigs" --json | jq -r 'keys[]' +} + +set_config() { + if [[ -z "$@" ]]; then + error "No argument was given, use 'set_config ' to set config" + return 1 + fi + + local config=$1; shift + local configArray=( $(list_config) ) + # TODO: this is not an elegant way + configArray+=("t1rocket") + + local verifiedConfig="" + for c in ${configArray[@]}; do + if [[ "$c" == "$config" ]]; then + verifiedConfig="$c" + fi + done + if [[ -z "$verifiedConfig" ]]; then + error "Config '$config' is not supported, available configs: ${configArray[*]}" + return 1 + fi + + local newCtx=$(jq --arg config "$config" '.config = $config' $_CTX) + printf "$newCtx" > "$_CTX" + + _CFG=$(get_config) + + info "Config is set to ${BLUE}${_CFG}${ALL_OFF}" +} + +_get_ip_attrs() { + nix --no-warn-dirty eval --json ".#legacyPackages.x86_64-linux" \ + --apply "pkgs: pkgs.lib.filterAttrs (_: v: pkgs.lib.isDerivation v) pkgs.t1.$_CFG.ip" \ + | jq -r 'keys[]' +} + +list_emulator() { + _get_ip_attrs | grep -E '(-emu$|-emu-trace$)' +} + +_EMU="" +get_emulator() { + local emu=$(jq -r ".emulator" "$_CTX") + if [[ -z "$emu" || "$emu" = "null" ]]; then + error "Emulator not set yet, please use 'set_emulator '" + return 1 + fi + + _EMU="$emu" + echo "$_EMU" +} + +_emulator_is_set() { + _EMU=$(get_emulator) + if [[ -z "$_EMU" || "$_EMU" = "null" ]]; then + return 1 + else + return 0 + fi +} + +set_emulator() { + if [[ -z "$@" ]]; then + error "No argument was given, use 'set_emulator ' to set main testing emulator" + return 1 + fi + + local emulator=$1; shift + local allEmuArray=( $(list_emulator) ) + + local verifiedEmulator="" + for e in ${allEmuArray[@]}; do + if [[ "$e" == "$emulator" ]]; then + verifiedEmulator="$e" + fi + done + if [[ -z "$verifiedEmulator" ]]; then + error "Emulator '$emulator' is not supported, available emulators: ${allEmuArray[*]}" + return 1 + fi + + local newCtx=$(jq --arg emulator "$verifiedEmulator" '.emulator = $emulator' $_CTX) + printf "$newCtx" > "$_CTX" + + _EMU=$(get_emulator) + + info "Emulator is set to ${BLUE}${_EMU}${ALL_OFF}" +} + +build() { + if [[ -z "$@" || "$@" = "help" ]]; then + error "Use ${BLUE}'build '${ALL_OFF} to build" + info2 "Available attrs" + _get_ip_attrs + return 1 + fi + + local attr=$1; shift + local availableAttrsArray=( $(_get_ip_attrs) ) + local verifiedAttr="" + for a in ${availableAttrsArray[@]}; do + if [ "$a" = "$attr" ]; then + verifiedAttr="$a" + fi + done + if [ -z "$verifiedAttr" ]; then + error "Invalid attr '$attr', available attrs:" + info2 "${availableAttrsArray[*]}" + return 1 + fi + + if ! _config_is_set; then + return 1 + fi + + local fullAttr=".#t1.$_CFG.ip.$attr" + info "Building $fullAttr to result dir ./result with flag '$@'" + nix build --no-warn-dirty --print-build-logs "$fullAttr" $@ +} + +run_test() { + if [[ -z "$@" || "$@" = "help" ]]; then + error "Use 'test ' to run a test" + return 1 + fi + + local case=$1; shift + + if [[ -z "$_EMU" ]]; then + error "Emulator is not set yet" + info2 "Use 'set_emulator ' to set the main testing emulator" + return 1 + fi + + if ! printf "$case" | grep -Eq '\S\.\S'; then + error "Invalid case form '$case', expect '.'" + return 1 + fi + + local hasAttr=$(nix eval --json --no-warn-dirty ".#t1.$_CFG.ip.$_EMU.cases" --apply "cases: cases ? $case") + if [[ "x$hasAttr" = "xfalse" ]]; then + error "Unknown cases $case" + return 1 + fi + + DEBUG=${DEBUG:-0} + caseAttr=".#t1.$_CFG.ip.$_EMU.cases.$case.emu-result" + if (( DEBUG )); then + caseAttr="$caseAttr.debug" + fi + + local args="$@" + if [[ "$_EMU" =~ "vcs-" ]]; then + args="$args --impure" + + if [[ -z "$SNPSLMD_LICENSE_FILE" ]]; then + error "SNPSLMD_LICENSE_FILE not set" + return 1 + fi + + if [[ -z "$VC_STATIC_HOME" ]]; then + error "VC_STATIC_HOME not set" + return 1 + fi + fi + + info "Running test case $case with emulator $_EMU, output result to ./result" + nix build --no-warn-dirty "$caseAttr" $args + ls -l ./result/ +} + +main() { + info "Welcome to T1 dev mode, here are some convenient commands" + info2 "set_config: set current configs" + info2 "list_config: get all available configs" + info2 "get_config: print current config" + info2 "set_emulator: set current emulators" + info2 "list_emulator: get all available emulators" + info2 "get_emulator: print the main testing emulator" + info2 "build: build T1 artifacts with config $_CFG" + info2 "run_test: run test case with specific emulator" + + echo + + if _config_is_set; then + info "Config is set to ${BLUE}$_CFG${ALL_OFF}, use ${GREEN}'set_config '${ALL_OFF} to modify config" + fi + + if _emulator_is_set; then + info "Emulator is set to ${BLUE}${_EMU}${ALL_OFF}, use ${GREEN}'set_emulator '${ALL_OFF} to modify emulator" + fi +} + +main diff --git a/tests/pytorch/default.nix b/tests/pytorch/default.nix index cebefa214..5e8f57715 100644 --- a/tests/pytorch/default.nix +++ b/tests/pytorch/default.nix @@ -16,7 +16,7 @@ let ({ inherit caseName; - featuresRequired = getTestRequiredFeatures sourcePath; + passthru.featuresRequired = getTestRequiredFeatures sourcePath; nativeBuildInputs = [ buddy-mlir.pyenv buddy-mlir ]; From 95a4a120272ac37fd20ca09b6218c3ef6e1f5b5d Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Wed, 24 Jul 2024 02:22:00 +0800 Subject: [PATCH 2/5] [build system] add t1-rocketv in build system for link t1 with rocket --- build.sc | 31 +++++++++++++++++++++++++++++++ common.sc | 17 +++++++++++++++++ nix/t1/t1.nix | 2 ++ 3 files changed, 50 insertions(+) diff --git a/build.sc b/build.sc index 3aa7d8710..17f308090 100644 --- a/build.sc +++ b/build.sc @@ -135,6 +135,21 @@ trait RocketV def chiselIvy = None } +object t1rocket extends T1Rocket + +trait T1Rocket + extends millbuild.common.T1RocketModule + with ScalafmtModule { + def scalaVersion = T(v.scala) + def rocketModule = rocketv + def t1Module = t1 + + def chiselModule = Some(chisel) + def chiselPluginJar = T(Some(chisel.pluginModule.jar())) + def chiselPluginIvy = None + def chiselIvy = None +} + object ipemu extends IPEmulator trait IPEmulator @@ -161,6 +176,20 @@ trait RocketEmulator extends millbuild.common.RocketEmulatorModule { def chiselIvy = None } +object t1rocketemu extends T1RocketEmulator + +trait T1RocketEmulator + extends millbuild.common.T1RocketEmulatorModule { + def scalaVersion = T(v.scala) + + def t1rocketModule = t1rocket + + def chiselModule = Some(chisel) + def chiselPluginJar = T(Some(chisel.pluginModule.jar())) + def chiselPluginIvy = None + def chiselIvy = None +} + object panamaconverter extends PanamaConverter trait PanamaConverter @@ -188,6 +217,8 @@ trait Elaborator ipemu, rocketv, rocketemu, + t1rocket, + t1rocketemu, ) def mainargsIvy = v.mainargs diff --git a/common.sc b/common.sc index 7f6e5d5c5..0f39a2376 100644 --- a/common.sc +++ b/common.sc @@ -90,6 +90,16 @@ trait RocketVModule def moduleDeps = super.moduleDeps ++ Seq(axi4Module, hardfloatModule) } +// Link T1 example: RocketV+T1 +trait T1RocketModule + extends ScalaModule + with HasChisel { + def rocketModule: ScalaModule + def t1Module: ScalaModule + + def moduleDeps = super.moduleDeps ++ Seq(rocketModule, t1Module) +} + trait EmuHelperModule extends ScalaModule with HasChisel @@ -101,6 +111,13 @@ trait IPEmulatorModule def moduleDeps = super.moduleDeps ++ Seq(t1Module) } +trait T1RocketEmulatorModule + extends ScalaModule + with HasChisel { + def t1rocketModule: ScalaModule + def moduleDeps = super.moduleDeps ++ Seq(t1rocketModule) +} + trait ElaboratorModule extends ScalaModule with HasChisel { diff --git a/nix/t1/t1.nix b/nix/t1/t1.nix index aafed98a2..b7eda72bd 100644 --- a/nix/t1/t1.nix +++ b/nix/t1/t1.nix @@ -30,6 +30,8 @@ let ./../../elaborator ./../../configgen/src ./../../rocketv + ./../../t1rocket + ./../../t1rocketemu ./../../rocketemu/src ]; }; From 769a15dda1f206c3d583f29d8b7f2739ce6a8097 Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Mon, 26 Aug 2024 16:00:11 +0800 Subject: [PATCH 3/5] [t1rocket] implement T1RocketTile --- elaborator/src/t1rocket/T1RocketTile.scala | 102 ++++ t1rocket/src/T1RocketTile.scala | 572 +++++++++++++++++++++ 2 files changed, 674 insertions(+) create mode 100644 elaborator/src/t1rocket/T1RocketTile.scala create mode 100644 t1rocket/src/T1RocketTile.scala diff --git a/elaborator/src/t1rocket/T1RocketTile.scala b/elaborator/src/t1rocket/T1RocketTile.scala new file mode 100644 index 000000000..3cb8398e2 --- /dev/null +++ b/elaborator/src/t1rocket/T1RocketTile.scala @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2024 Jiuyang Liu +package org.chipsalliance.t1.elaborator.t1rocketv + +import chisel3.util.BitPat +import chisel3.util.experimental.BitSet +import mainargs._ +import org.chipsalliance.t1.elaborator.Elaborator +import org.chipsalliance.t1.rtl.vrf.RamType +import org.chipsalliance.t1.rtl.vrf.RamType.{p0rp1w, p0rw, p0rwp1rw} +import org.chipsalliance.t1.tile.{T1RocketTile, T1RocketTileParameter} + +// --instructionSets rv32_i --instructionSets rv_a --instructionSets rv_c --instructionSets rv_v --instructionSets Zve32x --instructionSets zvl1024b --cacheBlockBytes 32 --nPMPs 8 --cacheable 80000000-ffffffff --sideEffects 00000000-1fffffff --dcacheNSets 64 --dcacheNWays 4 --dcacheRowBits 32 --iCacheNSets 32 --iCacheNWays 4 --iCachePrefetch false --dLen 256 --vrfBankSize 2 --vrfRamType p0rp1w +object T1RocketTile extends Elaborator { + implicit object BitSetRead extends TokensReader.Simple[BitSet] { + def shortName = "bitset" + def read(strs: Seq[String]) = { + Right( + strs.head + .split(",") + .map { opt => + if (opt.contains("-")) { + val range = opt.split("-") + require(range.size == 2) + val from = BigInt(range.head, 16) + val to = BigInt(range.last, 16) + 1 + BitSet.fromRange(from, to - from, range.head.length * 4) + } else if (opt.contains("+")) { + val range = opt.split("\\+") + require(range.size == 2) + val from = BigInt(range.head, 16) + val length = BigInt(range.last, 16) + BitSet.fromRange(from, length, range.head.length * 4) + } else { + BitPat(s"b$opt") + } + } + .reduce(_.union(_)) + ) + } + } + + implicit object RamTypeRead extends TokensReader.Simple[RamType] { + def shortName = "ramtype" + def read(strs: Seq[String]) = { + Right( + strs.head match { + case "p0rw" => p0rw + case "p0rp1w" => p0rp1w + case "p0rwp1rw" => p0rwp1rw + } + ) + } + } + + @main + case class T1RocketTileParameterMain( + @arg(name = "instructionSets") instructionSets: Seq[String], + @arg(name = "cacheBlockBytes") cacheBlockBytes: Int, + @arg(name = "nPMPs") nPMPs: Int, + @arg(name = "cacheable") cacheable: BitSet, + @arg(name = "sideEffects") sideEffects: BitSet, + @arg(name = "dcacheNSets") dcacheNSets: Int, + @arg(name = "dcacheNWays") dcacheNWays: Int, + @arg(name = "dcacheRowBits") dcacheRowBits: Int, + @arg(name = "iCacheNSets") iCacheNSets: Int, + @arg(name = "iCacheNWays") iCacheNWays: Int, + @arg(name = "iCachePrefetch") iCachePrefetch: Boolean, + @arg(name = "dLen") dLen: Int, + @arg(name = "vrfBankSize") vrfBankSize: Int, + @arg(name = "vrfRamType") vrfRamType: RamType + ) { + def convert: T1RocketTileParameter = T1RocketTileParameter( + instructionSets: Seq[String], + cacheBlockBytes: Int, + nPMPs: Int, + cacheable: BitSet, + sideEffects: BitSet, + dcacheNSets: Int, + dcacheNWays: Int, + dcacheRowBits: Int, + iCacheNSets: Int, + iCacheNWays: Int, + iCachePrefetch: Boolean, + dLen: Int, + vrfBankSize: Int, + vrfRamType: RamType + ) + } + + implicit def T1RocketTileParameterMainParser: ParserForClass[T1RocketTileParameterMain] = + ParserForClass[T1RocketTileParameterMain] + + @main + def config(@arg(name = "parameter") parameter: T1RocketTileParameterMain) = configImpl(parameter.convert) + + @main + def design(@arg(name = "parameter") parameter: os.Path, @arg(name = "run-firtool") runFirtool: mainargs.Flag) = + designImpl[T1RocketTile, T1RocketTileParameter](parameter, runFirtool.value) + + def main(args: Array[String]): Unit = ParserForMethods(this).runOrExit(args) +} diff --git a/t1rocket/src/T1RocketTile.scala b/t1rocket/src/T1RocketTile.scala new file mode 100644 index 000000000..d0b61be83 --- /dev/null +++ b/t1rocket/src/T1RocketTile.scala @@ -0,0 +1,572 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2024 Jiuyang Liu +package org.chipsalliance.t1.tile + +import chisel3._ +import chisel3.experimental.hierarchy.{Instance, Instantiate} +import chisel3.experimental.{SerializableModule, SerializableModuleGenerator, SerializableModuleParameter} +import chisel3.util.experimental.BitSet +import chisel3.util.log2Ceil +import chisel3.probe.{Probe, ProbeValue, define} +import org.chipsalliance.amba.axi4.bundle.{AXI4BundleParameter, AXI4ROIrrevocable, AXI4RWIrrevocable} +import org.chipsalliance.rocketv.{BHTParameter, FPU, FPUParameter, Frontend, FrontendParameter, HellaCache, HellaCacheArbiter, HellaCacheArbiterParameter, HellaCacheParameter, PTW, PTWParameter, Rocket, RocketParameter, RocketTileParameter, RocketProbe, FPUProbe} +import org.chipsalliance.rvdecoderdb.Instruction +import org.chipsalliance.t1.rtl.decoder.T1CustomInstruction +import org.chipsalliance.t1.rtl.vrf.RamType +import org.chipsalliance.t1.rtl.vrf.RamType.{p0rp1w, p0rw, p0rwp1rw} +import org.chipsalliance.t1.rtl.lsu.LSUProbe +import org.chipsalliance.t1.rtl.vrf.VRFProbe +import org.chipsalliance.t1.rtl.{LaneAdder, LaneAdderParam, LaneDiv, LaneDivFP, LaneDivFPParam, LaneDivParam, LaneFloat, LaneFloatParam, LaneMul, LaneMulParam, LaneShifter, LaneShifterParameter, LogicParam, MaskedLogic, OtherUnit, OtherUnitParam, T1, T1Parameter, VFUInstantiateParameter, T1Probe, LaneProbe} + +object T1RocketTileParameter { + implicit def bitSetP: upickle.default.ReadWriter[BitSet] = upickle.default + .readwriter[String] + .bimap[BitSet]( + bs => bs.terms.map("b" + _.rawString).mkString("\n"), + str => if (str.isEmpty) BitSet.empty else BitSet.fromString(str) + ) + + implicit val vrfRamTypeP: upickle.default.ReadWriter[RamType] = upickle.default.ReadWriter.merge( + upickle.default.macroRW[p0rw.type], + upickle.default.macroRW[p0rp1w.type], + upickle.default.macroRW[p0rwp1rw.type] + ) + + implicit def rwP: upickle.default.ReadWriter[T1RocketTileParameter] = upickle.default.macroRW[T1RocketTileParameter] +} + +case class T1RocketTileParameter( + instructionSets: Seq[String], + cacheBlockBytes: Int, + nPMPs: Int, + cacheable: BitSet, + sideEffects: BitSet, + dcacheNSets: Int, + dcacheNWays: Int, + dcacheRowBits: Int, + iCacheNSets: Int, + iCacheNWays: Int, + iCachePrefetch: Boolean, + dLen: Int, + vrfBankSize: Int, + vrfRamType: RamType) + extends SerializableModuleParameter { + require(instructionSets.count(Seq("Zve32x", "Zve32f").contains) == 1, "at least support one Zve32x or Zve32f") + + val useAsyncReset: Boolean = false + val clockGate: Boolean = false + + val paddrBits: Int = xLen + // TODO: add S in the future + val priv: String = "m" + val hartIdLen: Int = 1 + val useBPWatch: Boolean = false + val mcontextWidth: Int = 0 + val scontextWidth: Int = 0 + val asidBits: Int = 0 + val resetVectorBits: Int = paddrBits + val nBreakpoints: Int = 0 + // TODO: set to 0 + val dtlbNSets: Int = 1 + val dtlbNWays: Int = 32 + val itlbNSets: Int = 1 + val itlbNWays: Int = 32 + val itlbNSectors: Int = 4 + val itlbNSuperpageEntries: Int = 4 + val nPTECacheEntries: Int = 9 + val nL2TLBWays: Int = 1 + val nL2TLBEntries: Int = 0 + // T1 doens't check exception. + val legal: BitSet = BitSet.fromRange(0, 1 << paddrBits) + val read: BitSet = BitSet.fromRange(0, 1 << paddrBits) + val write: BitSet = BitSet.fromRange(0, 1 << paddrBits) + val putPartial: BitSet = BitSet.fromRange(0, 1 << paddrBits) + val logic: BitSet = BitSet.fromRange(0, 1 << paddrBits) + val arithmetic: BitSet = BitSet.fromRange(0, 1 << paddrBits) + val exec: BitSet = BitSet.fromRange(0, 1 << paddrBits) + val btbEntries: Int = 28 + val btbNMatchBits: Int = 14 + val btbUpdatesOutOfOrder: Boolean = false + val nPages: Int = 6 + val nRAS: Int = 6 + val bhtParameter: Option[BHTParameter] = Some(BHTParameter(nEntries = 512, counterLength = 1, historyLength = 8, historyBits = 3)) + // TODO: remove it + val mulDivLatency: Int = 0 + val divUnroll: Int = 1 + val divEarlyOut: Boolean = false + val divEarlyOutGranularity: Int = 1 + val mulUnroll: Int = 1 + val mulEarlyOut: Boolean = false + val sfmaLatency: Int = 3 + val dfmaLatency: Int = 4 + val divSqrt: Boolean = true + // TODO: check decoder + val flushOnFenceI: Boolean = true + val fastLoadByte: Boolean = false + val fastLoadWord: Boolean = true + val maxUncachedInFlight: Int = 1 + val separateUncachedResp: Boolean = false + + + // calculate + def usingUser: Boolean = priv.contains("u") + + def usingSupervisor: Boolean = priv.contains("s") + + def vLen: Int = instructionSets.collectFirst { + case s"zvl${vlen}b" => vlen.toInt + }.get + + // static for now + def hasBeu: Boolean = false + + def usingNMI: Boolean = false + + def usingHypervisor: Boolean = false + + def usingDataScratchpad: Boolean = false + + def nLocalInterrupts: Int = 0 + + def dcacheArbPorts: Int = 2 + + def tagECC: Option[String] = None + + def dataECC: Option[String] = None + + def pgLevelBits: Int = 10 - log2Ceil(xLen / 32) + + def instructions: Seq[Instruction] = + org.chipsalliance.rvdecoderdb + .instructions( + org.chipsalliance.rvdecoderdb.extractResource(getClass.getClassLoader) + ) + .filter(instruction => + ( + instructionSets ++ + // Four mandatory instruction sets. + Seq("rv_i", "rv_zicsr", "rv_zifencei", "rv_system") + ).contains(instruction.instructionSet.name) + ) + .toSeq + .filter { + // special case for rv32 pseudo from rv64 + case i if i.pseudoFrom.isDefined && Seq("slli", "srli", "srai").contains(i.name) => true + case i if i.pseudoFrom.isDefined => false + case _ => true + } + .sortBy(i => (i.instructionSet.name, i.name)) + + private def hasInstructionSet(setName: String): Boolean = + instructions.flatMap(_.instructionSets.map(_.name)).contains(setName) + + def usingBTB: Boolean = btbEntries > 0 + + def xLen: Int = + (hasInstructionSet("rv32_i"), hasInstructionSet("rv64_i")) match { + case (true, true) => throw new Exception("cannot support both rv32 and rv64 together") + case (true, false) => 32 + case (false, true) => 64 + case (false, false) => throw new Exception("no basic instruction found.") + } + + def fLen: Option[Int] = + ( + hasInstructionSet("rv_f") || hasInstructionSet("rv64_f"), + hasInstructionSet("rv_d") || hasInstructionSet("rv64_d") + ) match { + case (false, false) => None + case (true, false) => Some(32) + case (false, true) => Some(64) + case (true, true) => Some(64) + } + + def usingVM = hasInstructionSet("sfence.vma") + + def pgLevels: Int = xLen match { + case 32 => 2 + case 64 => 3 + } + + def usingAtomics = hasInstructionSet("rv_a") || hasInstructionSet("rv64_a") + + def usingCompressed = hasInstructionSet("rv_c") + + def minFLen: Option[Int] = + if (hasInstructionSet("rv_zfh") || hasInstructionSet("rv64_zfh") || hasInstructionSet("rv_d_zfh")) + Some(16) + else + fLen + + def rocketParameter: RocketParameter = RocketParameter( + useAsyncReset, + clockGate, + instructionSets.toSet, + vLen, + usingUser, + hartIdLen, + nPMPs, + asidBits, + nBreakpoints, + usingBTB, + useBPWatch, + mcontextWidth, + scontextWidth, + mulDivLatency, + divUnroll, + divEarlyOut, + divEarlyOutGranularity, + mulUnroll, + mulEarlyOut, + paddrBits, + cacheBlockBytes, + hasBeu, + fastLoadByte, + fastLoadWord, + dcacheNSets, + flushOnFenceI, + usingT1 = true + ) + + def hellaCacheParameter: HellaCacheParameter = HellaCacheParameter( + useAsyncReset: Boolean, + clockGate: Boolean, + xLen: Int, + fLen.getOrElse(0): Int, + usingVM: Boolean, + paddrBits: Int, + cacheBlockBytes: Int, + dcacheNWays: Int, + dcacheNSets: Int, + dcacheRowBits: Int, + dtlbNSets: Int, + dtlbNWays: Int, + tagECC: Option[String], + dataECC: Option[String], + maxUncachedInFlight: Int, + separateUncachedResp: Boolean, + legal: BitSet, + cacheable: BitSet, + read: BitSet, + write: BitSet, + putPartial: BitSet, + logic: BitSet, + arithmetic: BitSet, + exec: BitSet, + sideEffects: BitSet + ) + + def hellaCacheArbiterParameter: HellaCacheArbiterParameter = HellaCacheArbiterParameter( + useAsyncReset: Boolean, + xLen: Int, + fLen.getOrElse(0): Int, + paddrBits: Int, + cacheBlockBytes: Int, + dcacheNSets: Int, + usingVM: Boolean, + separateUncachedResp: Boolean + ) + + def ptwParameter: PTWParameter = PTWParameter( + useAsyncReset: Boolean, + clockGate: Boolean, + usingVM: Boolean, + usingHypervisor: Boolean, + xLen: Int, + fLen.getOrElse(0): Int, + paddrBits: Int, + asidBits: Int, + pgLevels: Int, + nPTECacheEntries: Int, + nL2TLBWays: Int, + nL2TLBEntries: Int, + nPMPs: Int + ) + + def frontendParameter: FrontendParameter = FrontendParameter( + useAsyncReset = useAsyncReset: Boolean, + clockGate = clockGate: Boolean, + xLen = xLen: Int, + usingAtomics = usingAtomics: Boolean, + usingDataScratchpad = usingDataScratchpad: Boolean, + usingVM = usingVM: Boolean, + usingCompressed = usingCompressed: Boolean, + usingBTB = usingBTB: Boolean, + itlbNSets = itlbNSets: Int, + itlbNWays = itlbNWays: Int, + itlbNSectors = itlbNSectors: Int, + itlbNSuperpageEntries = itlbNSuperpageEntries: Int, + blockBytes = cacheBlockBytes: Int, + iCacheNSets = iCacheNSets: Int, + iCacheNWays = iCacheNWays: Int, + iCachePrefetch = iCachePrefetch: Boolean, + btbEntries = btbEntries: Int, + btbNMatchBits = btbNMatchBits: Int, + btbUpdatesOutOfOrder = btbUpdatesOutOfOrder: Boolean, + nPages = nPages: Int, + nRAS = nRAS: Int, + nPMPs = nPMPs: Int, + paddrBits = paddrBits: Int, + pgLevels = pgLevels: Int, + asidBits = asidBits: Int, + bhtParameter = bhtParameter: Option[BHTParameter], + legal = legal: BitSet, + cacheable = cacheable: BitSet, + read = read: BitSet, + write = write: BitSet, + putPartial = putPartial: BitSet, + logic = logic: BitSet, + arithmetic = arithmetic: BitSet, + exec = exec: BitSet, + sideEffects = sideEffects: BitSet + ) + + def fpuParameter: Option[FPUParameter] = fLen.zip(minFLen).map { + case (fLen, minFLen) => + FPUParameter( + useAsyncReset: Boolean, + clockGate: Boolean, + xLen: Int, + fLen: Int, + minFLen: Int, + sfmaLatency: Int, + dfmaLatency: Int, + divSqrt: Boolean, + hartIdLen: Int + ) + } + + val vfuInstantiateParameter = if (instructionSets.contains("Zve32f")) + VFUInstantiateParameter( + slotCount = 4, + logicModuleParameters = Seq( + (SerializableModuleGenerator(classOf[MaskedLogic], LogicParam(32, 1)), Seq(0, 1, 2, 3)) + ), + aluModuleParameters = Seq( + (SerializableModuleGenerator(classOf[LaneAdder], LaneAdderParam(32, 1)), Seq(0)), + (SerializableModuleGenerator(classOf[LaneAdder], LaneAdderParam(32, 1)), Seq(1)), + (SerializableModuleGenerator(classOf[LaneAdder], LaneAdderParam(32, 1)), Seq(2)), + (SerializableModuleGenerator(classOf[LaneAdder], LaneAdderParam(32, 1)), Seq(3)) + ), + shifterModuleParameters = Seq( + (SerializableModuleGenerator(classOf[LaneShifter], LaneShifterParameter(32, 1)), Seq(0, 1, 2, 3)) + ), + mulModuleParameters = Seq( + (SerializableModuleGenerator(classOf[LaneMul], LaneMulParam(32, 2)), Seq(0, 1, 2, 3)) + ), + divModuleParameters = Seq(), + divfpModuleParameters = + Seq((SerializableModuleGenerator(classOf[LaneDivFP], LaneDivFPParam(32, 1)), Seq(0, 1, 2, 3))), + otherModuleParameters = + Seq(( + SerializableModuleGenerator( + classOf[OtherUnit], + OtherUnitParam(32, log2Ceil(vLen) + 1, log2Ceil(vLen * 8 / dLen), log2Ceil(dLen / 32), 4, 1) + ), + Seq(0, 1, 2, 3))), + floatModuleParameters = + Seq((SerializableModuleGenerator(classOf[LaneFloat], LaneFloatParam(32, 3)), Seq(0, 1, 2, 3))), + zvbbModuleParameters = Seq() + ) else + VFUInstantiateParameter( + slotCount = 4, + logicModuleParameters = Seq( + (SerializableModuleGenerator(classOf[MaskedLogic], LogicParam(32, 1)), Seq(0, 1, 2, 3)) + ), + aluModuleParameters = Seq( + (SerializableModuleGenerator(classOf[LaneAdder], LaneAdderParam(32, 1)), Seq(0)), + (SerializableModuleGenerator(classOf[LaneAdder], LaneAdderParam(32, 1)), Seq(1)), + (SerializableModuleGenerator(classOf[LaneAdder], LaneAdderParam(32, 1)), Seq(2)), + (SerializableModuleGenerator(classOf[LaneAdder], LaneAdderParam(32, 1)), Seq(3)) + ), + shifterModuleParameters = Seq( + (SerializableModuleGenerator(classOf[LaneShifter], LaneShifterParameter(32, 1)), Seq(0, 1, 2, 3)) + ), + mulModuleParameters = Seq( + (SerializableModuleGenerator(classOf[LaneMul], LaneMulParam(32, 2)), Seq(0, 1, 2, 3)) + ), + divModuleParameters = Seq( + (SerializableModuleGenerator(classOf[LaneDiv], LaneDivParam(32, 1)), Seq(0, 1, 2, 3)) + ), + divfpModuleParameters = Seq(), + otherModuleParameters = + Seq(( + SerializableModuleGenerator( + classOf[OtherUnit], + OtherUnitParam(32, log2Ceil(vLen) + 1, log2Ceil(vLen * 8 / dLen), log2Ceil(dLen / 32), 4, 1) + ), + Seq(0, 1, 2, 3))), + floatModuleParameters = Seq(), + zvbbModuleParameters = Seq() + ) + + def t1Parameter: T1Parameter = T1Parameter( + vLen = vLen, + dLen = dLen, + extensions = instructionSets.filter(Seq("Zve32x", "Zve32f").contains), + // empty for now. + t1customInstructions = Seq(), + vrfBankSize = vrfBankSize, + vrfRamType = vrfRamType, + vfuInstantiateParameter = vfuInstantiateParameter + ) + + def instructionFetchParameter: AXI4BundleParameter = frontendParameter.instructionFetchParameter + + def itimParameter: Option[AXI4BundleParameter] = frontendParameter.itimParameter + + def loadStoreParameter: AXI4BundleParameter = hellaCacheParameter.loadStoreParameter + + def dtimParameter: Option[AXI4BundleParameter] = hellaCacheParameter.dtimParameter + + def t1HighBandwidthParameter: AXI4BundleParameter = t1Parameter.axi4BundleParameter + + def t1HightOutstandingParameter: AXI4BundleParameter = t1Parameter.axi4BundleParameter.copy(dataWidth = 32) +} + +class T1RocketProbe(parameter: T1RocketTileParameter) extends Bundle { + val rocketProbe: RocketProbe = Output(new RocketProbe(parameter.rocketParameter)) + val fpuProbe: Option[FPUProbe] = parameter.fpuParameter.map(param => Output(new FPUProbe(param))) + val t1Probe: T1Probe = Output(new T1Probe(parameter.t1Parameter)) +} + +class T1RocketTileInterface(parameter: T1RocketTileParameter) extends Bundle { + val clock = Input(Clock()) + val reset = Input(if (parameter.useAsyncReset) AsyncReset() else Bool()) + // todo: Const + val hartid = Flipped(UInt(parameter.hartIdLen.W)) + val resetVector = Input(Const(UInt(parameter.resetVectorBits.W))) + + val debug: Bool = Input(Bool()) + val mtip: Bool = Input(Bool()) + val msip: Bool = Input(Bool()) + val meip: Bool = Input(Bool()) + val seip: Option[Bool] = Option.when(parameter.usingSupervisor)(Bool()) + val lip: Vec[Bool] = Vec(parameter.nLocalInterrupts, Bool()) + val nmi = Option.when(parameter.usingNMI)(Bool()) + val nmiInterruptVector = Option.when(parameter.usingNMI)(UInt(parameter.resetVectorBits.W)) + val nmiIxceptionVector = Option.when(parameter.usingNMI)(UInt(parameter.resetVectorBits.W)) + // TODO: buserror should be handled by NMI + val buserror: Bool = Input(Bool()) + val wfi: Bool = Output(Bool()) + val halt: Bool = Output(Bool()) + + val instructionFetchAXI: AXI4ROIrrevocable = + org.chipsalliance.amba.axi4.bundle.AXI4ROIrrevocable(parameter.instructionFetchParameter) + val itimAXI: Option[AXI4RWIrrevocable] = + parameter.itimParameter.map(p => Flipped(org.chipsalliance.amba.axi4.bundle.AXI4RWIrrevocable(p))) + + val loadStoreAXI: AXI4RWIrrevocable = + org.chipsalliance.amba.axi4.bundle.AXI4RWIrrevocable(parameter.loadStoreParameter) + val dtimAXI: Option[AXI4RWIrrevocable] = + parameter.dtimParameter.map(p => Flipped(org.chipsalliance.amba.axi4.bundle.AXI4RWIrrevocable(p))) + + val highBandwidthAXI: AXI4RWIrrevocable = org.chipsalliance.amba.axi4.bundle.AXI4RWIrrevocable(parameter.t1HighBandwidthParameter) + val highOutstandingAXI: AXI4RWIrrevocable = org.chipsalliance.amba.axi4.bundle.AXI4RWIrrevocable(parameter.t1HightOutstandingParameter) + + // TODO: merge it. + val t1RocketProbe: T1RocketProbe = Output(Probe(new T1RocketProbe(parameter), layers.Verification)) +} + +class T1RocketTile(val parameter: T1RocketTileParameter) + extends FixedIORawModule(new T1RocketTileInterface(parameter)) + with SerializableModule[T1RocketTileParameter] { + val rocket: Instance[Rocket] = Instantiate(new Rocket(parameter.rocketParameter)) + val frontend: Instance[Frontend] = Instantiate(new Frontend(parameter.frontendParameter)) + val hellaCache: Instance[HellaCache] = Instantiate(new HellaCache(parameter.hellaCacheParameter)) + val hellaCacheArbiter: Instance[HellaCacheArbiter] = Instantiate( + new HellaCacheArbiter(parameter.hellaCacheArbiterParameter) + ) + val ptw: Instance[PTW] = Instantiate(new PTW(parameter.ptwParameter)) + val fpu: Option[Instance[FPU]] = parameter.fpuParameter.map(fpuParameter => Instantiate(new FPU(fpuParameter))) + val t1: Instance[T1] = Instantiate(new T1(parameter.t1Parameter)) + + rocket.io.clock := io.clock + rocket.io.reset := io.reset + rocket.io.hartid := io.hartid + rocket.io.interrupts.debug := io.debug + rocket.io.interrupts.mtip := io.mtip + rocket.io.interrupts.msip := io.msip + rocket.io.interrupts.meip := io.meip + rocket.io.interrupts.seip.foreach(_ := io.seip.get) + rocket.io.interrupts.lip := io.lip + rocket.io.interrupts.nmi.foreach { nmi => + nmi.rnmi := io.nmi.get + nmi.rnmi_interrupt_vector := io.nmiInterruptVector.get + nmi.rnmi_exception_vector := io.nmiIxceptionVector.get + } + // @todo make it optional + rocket.io.buserror := io.buserror + io.wfi := rocket.io.wfi + io.loadStoreAXI <> hellaCache.io.loadStoreAXI + io.dtimAXI.zip(hellaCache.io.dtimAXI).foreach { case (io, hellaCache) => io <> hellaCache } + io.instructionFetchAXI <> frontend.io.instructionFetchAXI + io.itimAXI.zip(frontend.io.itimAXI).foreach { case (io, frontend) => io <> frontend } + // design for halt and beu, only use the halt function for now. + io.halt := Seq(frontend.io.nonDiplomatic.errors.uncorrectable, hellaCache.io.errors.uncorrectable) + .flatMap(_.map(_.valid)) + .foldLeft(false.B)(_ || _) + + // rocket core io + rocket.io.imem <> frontend.io.nonDiplomatic.cpu + hellaCacheArbiter.io.requestor(0) <> rocket.io.dmem + rocket.io.ptw <> ptw.io.dpath + rocket.io.fpu.zip(fpu.map(_.io.core)).foreach { case (core, fpu) => core <> fpu } + // match connect + t1.io.issue <> rocket.io.t1.get.issue + rocket.io.t1.get.retire <> t1.io.retire + // used by trace module + rocket.io.bpwatch := DontCare + // don't use for now, this is design for report the custom cease status. + // rocket.io.cease + // it will be used in the future w/ trace support. + rocket.io.traceStall := false.B + + // frontend io + frontend.io.clock := io.clock + frontend.io.reset := io.reset + frontend.io.resetVector := io.resetVector + ptw.io.requestor(0) <> frontend.io.nonDiplomatic.ptw + + // hellacache io + hellaCache.io.clock := io.clock + hellaCache.io.reset := io.reset + ptw.io.requestor(1) <> hellaCache.io.ptw + hellaCache.io.cpu <> hellaCacheArbiter.io.mem + + // ptw io + ptw.io.clock := io.clock + ptw.io.reset := io.reset + if (hellaCacheArbiter.io.requestor.size > 1) { + hellaCacheArbiter.io.requestor(1) <> ptw.io.mem + } else { + ptw.io.mem <> DontCare + } + + // hellacache arbiter io + hellaCacheArbiter.io.clock := io.clock + hellaCacheArbiter.io.reset := io.reset + + fpu.foreach { fpu => + fpu.io.clock := io.clock + fpu.io.reset := io.reset + // @todo: remove it from FPU. + fpu.io.cp_req <> DontCare + fpu.io.cp_resp <> DontCare + } + t1.io.clock := io.clock + t1.io.reset := io.reset + io.highBandwidthAXI <> t1.io.highBandwidthLoadStorePort + io.highOutstandingAXI <> t1.io.indexedLoadStorePort + + // probe + layer.block(layers.Verification) { + val probeWire = Wire(new T1RocketProbe(parameter)) + define(io.t1RocketProbe, ProbeValue(probeWire)) + probeWire.rocketProbe := probe.read(rocket.io.rocketProbe) + probeWire.t1Probe := probe.read(t1.io.t1Probe) + probeWire.fpuProbe.foreach { fpuProbe => + fpuProbe := probe.read(fpu.get.io.fpuProbe) + } + } +} From de660d8115a0f441933d2c22e5d6e9ff745f68fc Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Mon, 26 Aug 2024 16:01:03 +0800 Subject: [PATCH 4/5] [t1rocket] implement t1rocket Testbench --- t1rocketemu/src/AXI4SlaveAgent.scala | 205 +++++++++++++++++ t1rocketemu/src/FPToIEEE.scala | 74 +++++++ t1rocketemu/src/TestBench.scala | 317 +++++++++++++++++++++++++++ 3 files changed, 596 insertions(+) create mode 100644 t1rocketemu/src/AXI4SlaveAgent.scala create mode 100644 t1rocketemu/src/FPToIEEE.scala create mode 100644 t1rocketemu/src/TestBench.scala diff --git a/t1rocketemu/src/AXI4SlaveAgent.scala b/t1rocketemu/src/AXI4SlaveAgent.scala new file mode 100644 index 000000000..3af3f3727 --- /dev/null +++ b/t1rocketemu/src/AXI4SlaveAgent.scala @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2022-2024 Jiuyang Liu + +package org.chipsalliance.t1.t1rocketemu.dpi + +// TODO: upstream to AMBA as VIP +import chisel3._ +import chisel3.util.circt.dpi.{RawClockedVoidFunctionCall, RawUnclockedNonVoidFunctionCall} +import chisel3.util.{isPow2, log2Ceil} +import org.chipsalliance.amba.axi4.bundle.{ARChannel, ARFlowControl, AWChannel, AWFlowControl, AXI4BundleParameter, AXI4ROIrrevocableVerilog, AXI4RWIrrevocableVerilog, AXI4WOIrrevocableVerilog, BChannel, BFlowControl, RChannel, RFlowControl, WChannel, WFlowControl} + +case class AXI4SlaveAgentParameter(name: String, axiParameter: AXI4BundleParameter, outstanding: Int, readPayloadSize: Int, writePayloadSize: Int) + +class AXI4SlaveAgentInterface(parameter: AXI4SlaveAgentParameter) extends Bundle { + val clock: Clock = Input(Clock()) + val reset: Reset = Input(Reset()) + val channelId: UInt = Input(Const(UInt(64.W))) + // don't issue read DPI + val gateRead: Bool = Input(Bool()) + // don't issue write DPI + val gateWrite: Bool = Input(Bool()) + val channel = Flipped( + org.chipsalliance.amba.axi4.bundle.verilog.irrevocable(parameter.axiParameter) + ) +} + +class WritePayload(length: Int, dataWidth: Int) extends Bundle { + val data = Vec(length, UInt(dataWidth.W)) + // For dataWidth <= 8, align strb to u8 for a simple C-API + val strb = Vec(length, UInt(math.max(8, dataWidth / 8).W)) +} + +class ReadPayload(length: Int,dataWidth: Int) extends Bundle { + val data = Vec(length, UInt(dataWidth.W)) +} + +// consume transaction from DPI, drive RTL signal +class AXI4SlaveAgent(parameter: AXI4SlaveAgentParameter) + extends FixedIORawModule[AXI4SlaveAgentInterface](new AXI4SlaveAgentInterface(parameter)) { + dontTouch(io) + io.channel match { + case channel: AXI4RWIrrevocableVerilog => + new WriteManager(channel) + new ReadManager(channel) + case channel: AXI4ROIrrevocableVerilog => + new ReadManager(channel) + case channel: AXI4WOIrrevocableVerilog => + new WriteManager(channel) + } + + private class WriteManager( + channel: AWChannel with AWFlowControl with WChannel with WFlowControl with BChannel with BFlowControl) { + withClockAndReset(io.clock, io.reset) { + /** There is an aw in the register. */ + val awIssued = RegInit(false.B) + /** There is a w in the register. */ + val last = RegInit(false.B) + + /** memory to store the write payload + * @todo limit the payload size based on the RTL configuration. + */ + val writePayload = RegInit(0.U.asTypeOf(new WritePayload(parameter.writePayloadSize, parameter.axiParameter.dataWidth))) + /** AWID, latch at AW fire, used at B fire. */ + val awid = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWID))) + val awaddr = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWADDR))) + val awlen = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWLEN))) + val awsize = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWSIZE))) + val awburst = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWBURST))) + val awlock = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWLOCK))) + val awcache = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWCACHE))) + val awprot = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWPROT))) + val awqos = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWQOS))) + val awregion = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWREGION))) + val awuser = RegInit(0.U.asTypeOf(chiselTypeOf(channel.AWUSER))) + + /** index the payload, used to write [[writePayload]] */ + val writeIdx = RegInit(0.U.asTypeOf(UInt(8.W))) + val bFire = channel.BREADY && channel.BVALID + val awFire = channel.AWREADY && channel.AWVALID + val wLastFire = channel.WVALID && channel.WREADY && channel.WLAST + val awExist = channel.AWVALID || awIssued + val wExist = channel.WVALID && channel.WLAST || last + + // AW + channel.AWREADY := !awIssued || (wExist && channel.BREADY) + when(channel.AWREADY && channel.AWVALID) { + awid := channel.AWID + awaddr := channel.AWADDR + awlen := channel.AWLEN + awsize := channel.AWSIZE + awburst := channel.AWBURST + awlock := channel.AWLOCK + awcache := channel.AWCACHE + awprot := channel.AWPROT + awqos := channel.AWQOS + awregion := channel.AWREGION + awuser := channel.AWUSER + } + when(awFire ^ bFire) { + awIssued := awFire + } + + // W + val writePayloadUpdate = WireDefault(writePayload) + channel.WREADY := !last || (awExist && channel.BREADY) + when(channel.WVALID && channel.WREADY) { + writePayload.data(writeIdx) := channel.WDATA + writePayloadUpdate.data(writeIdx) := channel.WDATA + writePayload.strb(writeIdx) := channel.WSTRB.pad(writePayload.strb.getWidth) + writePayloadUpdate.strb(writeIdx) := channel.WSTRB.pad(writePayload.strb.getWidth) + writeIdx := writeIdx + 1.U + when(channel.WLAST) { + writeIdx := 0.U + } + } + when(wLastFire ^ bFire) { + last := wLastFire + } + + // B + channel.BVALID := awExist && wExist + channel.BID := Mux(awIssued, awid, channel.AWID) + channel.BRESP := 0.U(2.W) // OK + channel.BUSER := Mux(awIssued, awuser, channel.AWUSER) + when(channel.BVALID && channel.BREADY) { + RawClockedVoidFunctionCall(s"axi_write_${parameter.name}")( + io.clock, + when.cond && !io.gateWrite, + io.channelId, + // handle AW and W at same beat. + Mux(awIssued, awid.asTypeOf(UInt(64.W)), channel.AWID), + Mux(awIssued, awaddr.asTypeOf(UInt(64.W)), channel.AWADDR), + Mux(awIssued, awlen.asTypeOf(UInt(64.W)), channel.AWLEN), + Mux(awIssued, awsize.asTypeOf(UInt(64.W)), channel.AWSIZE), + Mux(awIssued, awburst.asTypeOf(UInt(64.W)), channel.AWBURST), + Mux(awIssued, awlock.asTypeOf(UInt(64.W)), channel.AWLOCK), + Mux(awIssued, awcache.asTypeOf(UInt(64.W)), channel.AWCACHE), + Mux(awIssued, awprot.asTypeOf(UInt(64.W)), channel.AWPROT), + Mux(awIssued, awqos.asTypeOf(UInt(64.W)), channel.AWQOS), + Mux(awIssued, awregion.asTypeOf(UInt(64.W)), channel.AWREGION), + writePayloadUpdate + ) + } + } + } + + private class ReadManager(channel: ARChannel with ARFlowControl with RChannel with RFlowControl) { + withClockAndReset(io.clock, io.reset) { + class CAMValue extends Bundle { + val arid = UInt(16.W) + val arlen = UInt(8.W) + val readPayload = new ReadPayload(parameter.readPayloadSize, parameter.axiParameter.dataWidth) + val readPayloadIndex = UInt(8.W) + val valid = Bool() + val user: UInt = UInt(channel.ARUSER.getWidth.W) + } + /** CAM to maintain order of read requests. This is maintained as FIFO. */ + val cam: Vec[CAMValue] = RegInit(0.U.asTypeOf(Vec(parameter.outstanding, new CAMValue))) + require(isPow2(parameter.outstanding), "Need to handle pointers") + val arPtr = RegInit(0.U.asTypeOf(UInt(log2Ceil(parameter.outstanding).W))) + val rPtr = RegInit(0.U.asTypeOf(UInt(log2Ceil(parameter.outstanding).W))) + + // AR + channel.ARREADY := !cam(arPtr).valid + when(channel.ARREADY && channel.ARVALID) { + cam(arPtr).arid := channel.ARID + cam(arPtr).arlen := channel.ARLEN + cam(arPtr).user := channel.ARUSER + cam(arPtr).readPayload := RawUnclockedNonVoidFunctionCall(s"axi_read_${parameter.name}", new ReadPayload(parameter.readPayloadSize, parameter.axiParameter.dataWidth))( + when.cond && !io.gateRead, + io.channelId, + channel.ARID.asTypeOf(UInt(64.W)), + channel.ARADDR.asTypeOf(UInt(64.W)), + channel.ARLEN.asTypeOf(UInt(64.W)), + channel.ARSIZE.asTypeOf(UInt(64.W)), + channel.ARBURST.asTypeOf(UInt(64.W)), + channel.ARLOCK.asTypeOf(UInt(64.W)), + channel.ARCACHE.asTypeOf(UInt(64.W)), + channel.ARPROT.asTypeOf(UInt(64.W)), + channel.ARQOS.asTypeOf(UInt(64.W)), + channel.ARREGION.asTypeOf(UInt(64.W)) + ) + cam(arPtr).readPayloadIndex := 0.U + cam(arPtr).valid := true.B + arPtr := arPtr + 1.U + } + + // R + channel.RVALID := cam(rPtr).valid + channel.RID := cam(rPtr).arid + channel.RDATA := cam(rPtr).readPayload.data(cam(rPtr).readPayloadIndex) + channel.RRESP := 0.U // OK + channel.RLAST := (cam(rPtr).arlen === cam(rPtr).readPayloadIndex) && cam(rPtr).valid + channel.RUSER := cam(rPtr).user + when(channel.RREADY && channel.RVALID) { + // increase index + cam(rPtr).readPayloadIndex := cam(rPtr).readPayloadIndex + 1.U + when(channel.RLAST) { + cam(rPtr).valid := false.B + rPtr := rPtr + 1.U + } + } + } + } +} diff --git a/t1rocketemu/src/FPToIEEE.scala b/t1rocketemu/src/FPToIEEE.scala new file mode 100644 index 000000000..82af4541a --- /dev/null +++ b/t1rocketemu/src/FPToIEEE.scala @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2012-2014 The Regents of the University of California +// SPDX-FileCopyrightText: 2016-2017 SiFive, Inc +// SPDX-FileCopyrightText: 2024 Jiuyang Liu +package org.chipsalliance.t1.t1rocketemu + +import chisel3._ +import chisel3.experimental.hierarchy.instantiable +import chisel3.experimental.{SerializableModule, SerializableModuleParameter} +import chisel3.util._ +import org.chipsalliance.rocketv.{FPUHelper, FType} + +object FPToIEEEParameter { + implicit def rwP: upickle.default.ReadWriter[FPToIEEEParameter] = upickle.default.macroRW[FPToIEEEParameter] +} + +class FPToIEEEInput(fLen: Int) extends Bundle { + val typeTag = UInt(2.W) + val data = UInt((fLen + 1).W) +} + +case class FPToIEEEParameter( + useAsyncReset: Boolean, + xLen: Int, + fLen: Int, + minFLen: Int) + extends SerializableModuleParameter +class FPToIEEEInterface(parameter: FPToIEEEParameter) extends Bundle { + val clock = Input(Clock()) + val reset = Input(if (parameter.useAsyncReset) AsyncReset() else Bool()) + val in = Flipped(Valid(new FPToIEEEInput(parameter.fLen))) + val out = Valid(UInt(parameter.fLen.W)) +} + +@instantiable +class FPToIEEE(val parameter: FPToIEEEParameter) + extends FixedIORawModule(new FPToIEEEInterface(parameter)) + with SerializableModule[FPToIEEEParameter] + with ImplicitClock + with ImplicitReset { + override protected def implicitClock: Clock = io.clock + override protected def implicitReset: Reset = io.reset + + val minFLen: Int = parameter.minFLen + val fLen: Int = parameter.fLen + val xLen: Int = parameter.xLen + val helper = new FPUHelper(minFLen, fLen, xLen) + val maxExpWidth = helper.maxExpWidth + val maxSigWidth = helper.maxSigWidth + val floatTypes = helper.floatTypes + val maxType = helper.maxType + val minXLen = helper.minXLen + val nIntTypes = helper.nIntTypes + def ieee(x: UInt, t: FType = maxType) = helper.ieee(x, t) + + val in = io.in.bits + val valid = io.in.valid + + def sextTo(x: UInt, n: Int): UInt = { + require(x.getWidth <= n) + if (x.getWidth == n) x + else Cat(Fill(n - x.getWidth, x(x.getWidth - 1)), x) + } + + val store = VecInit( + floatTypes.map(t => + if (t == FType.H) Fill(maxType.ieeeWidth / minXLen, sextTo(ieee(in.data)(15, 0), minXLen)) + else Fill(maxType.ieeeWidth / t.ieeeWidth, ieee(in.data)(t.ieeeWidth - 1, 0)) + ) + )(in.typeTag) + + io.out.valid := valid + io.out.bits := store +} diff --git a/t1rocketemu/src/TestBench.scala b/t1rocketemu/src/TestBench.scala new file mode 100644 index 000000000..b5c8b02ed --- /dev/null +++ b/t1rocketemu/src/TestBench.scala @@ -0,0 +1,317 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2022 Jiuyang Liu + +package org.chipsalliance.t1.t1rocketemu + +import chisel3._ +import chisel3.experimental.{BaseModule, ExtModule, SerializableModuleGenerator} +import chisel3.experimental.dataview.DataViewable +import chisel3.util.circt.dpi.{RawClockedNonVoidFunctionCall, RawUnclockedNonVoidFunctionCall} +import chisel3.util.{HasExtModuleInline, Mux1H, PopCount, Queue, UIntToOH, Valid} +import org.chipsalliance.amba.axi4.bundle._ +import org.chipsalliance.t1.t1rocketemu.dpi._ +import org.chipsalliance.t1.tile.{T1RocketTile, T1RocketTileParameter} + +class TestBench(generator: SerializableModuleGenerator[T1RocketTile, T1RocketTileParameter]) + extends RawModule + with ImplicitClock + with ImplicitReset { + layer.enable(layers.Verification) + val clockGen = Module(new ExtModule with HasExtModuleInline { + override def desiredName = "ClockGen" + setInline( + s"$desiredName.sv", + s"""module $desiredName(output reg clock, output reg reset); + | export "DPI-C" function dump_wave; + | function dump_wave(input string file); + |`ifdef VCS + | $$fsdbDumpfile(file); + | $$fsdbDumpvars("+all"); + | $$fsdbDumpon; + |`endif + |`ifdef VERILATOR + | $$dumpfile(file); + | $$dumpvars(0); + |`endif + | endfunction; + | + | import "DPI-C" context function void t1rocket_cosim_init(); + | initial begin + | t1rocket_cosim_init(); + | clock = 1'b0; + | reset = 1'b1; + | end + | initial #(100) reset = 1'b0; + | always #10 clock = ~clock; + |endmodule + |""".stripMargin + ) + val clock = IO(Output(Bool())) + val reset = IO(Output(Bool())) + }) + def clock = clockGen.clock.asClock + def reset = clockGen.reset + override def implicitClock = clockGen.clock.asClock + override def implicitReset = clockGen.reset + val dut: T1RocketTile with BaseModule = Module(generator.module()) + dut.io.clock := clock + dut.io.reset := reset + + // control simulation + val simulationTime: UInt = RegInit(0.U(64.W)) + simulationTime := simulationTime + 1.U + + // this initial way cannot happen before reset + val initFlag: Bool = RegInit(false.B) + when(!initFlag) { + initFlag := true.B + printf(cf"""{"event":"SimulationStart","cycle":${simulationTime}}\n""") + } + val watchdog: UInt = RawUnclockedNonVoidFunctionCall("cosim_watchdog", UInt(8.W))(simulationTime(9, 0) === 0.U) + when(watchdog =/= 0.U) { + stop(cf"""{"event":"SimulationStop","reason": ${watchdog},"cycle":${simulationTime}}\n""") + } + + // get resetVector from simulator + dut.io.resetVector := RawUnclockedNonVoidFunctionCall("get_resetvector", Const(UInt(64.W)))(simulationTime === 0.U) + + dut.io.hartid := 0.U + dut.io.debug := 0.U + dut.io.mtip := 0.U + dut.io.msip := 0.U + dut.io.meip := 0.U + dut.io.buserror := 0.U + + // memory driver + Seq( + dut.io.highBandwidthAXI, // index 0 + dut.io.highOutstandingAXI // index 1 + ).map(_.viewAs[AXI4RWIrrevocableVerilog]) + .lazyZip( + Seq("highBandwidthAXI", "highOutstandingAXI") + ) + .zipWithIndex + .foreach { + case ((bundle: AXI4RWIrrevocableVerilog, channelName: String), index: Int) => + val agent = Module( + new AXI4SlaveAgent( + AXI4SlaveAgentParameter( + name = channelName, + axiParameter = bundle.parameter, + outstanding = 4, + readPayloadSize = 1, + writePayloadSize = 1 + ) + ) + ).suggestName(s"axi4_channel${index}_${channelName}") + agent.io.channel match { + case io: AXI4RWIrrevocableVerilog => io <> bundle + } + agent.io.clock := clock + agent.io.reset := reset + agent.io.channelId := index.U + agent.io.gateRead := false.B + agent.io.gateWrite := false.B + } + + val instFetchAXI = dut.io.instructionFetchAXI.viewAs[AXI4ROIrrevocableVerilog] + val instFetchAgent = Module( + new AXI4SlaveAgent( + AXI4SlaveAgentParameter( + name = "instructionFetchAXI", + axiParameter = instFetchAXI.parameter, + outstanding = 4, + readPayloadSize = 1, + writePayloadSize = 1 + ) + ).suggestName("axi4_channel2_instructionFetchAXI") + ) + instFetchAgent.io.channel match { + case io: AXI4ROIrrevocableVerilog => io <> instFetchAXI + } + instFetchAgent.io.clock := clock + instFetchAgent.io.reset := reset + instFetchAgent.io.channelId := 0.U + instFetchAgent.io.gateRead := false.B + instFetchAgent.io.gateWrite := false.B + + val loadStoreAXI = dut.io.loadStoreAXI.viewAs[AXI4RWIrrevocableVerilog] + val loadStoreAgent = Module( + new AXI4SlaveAgent( + AXI4SlaveAgentParameter( + name = "loadStoreAXI", + axiParameter = loadStoreAXI.parameter, + outstanding = 4, + // TODO: add payloadSize config to parameter + readPayloadSize = 8, // todo: align with parameter in the future + writePayloadSize = 8 + ) + ).suggestName("axi4_channel3_loadStoreAXI") + ) + loadStoreAgent.io.channel match { + case io: AXI4RWIrrevocableVerilog => io <> loadStoreAXI + } + loadStoreAgent.io.clock := clock + loadStoreAgent.io.reset := reset + loadStoreAgent.io.channelId := 3.U + loadStoreAgent.io.gateRead := false.B + loadStoreAgent.io.gateWrite := false.B + + // probes + val t1RocketProbe = probe.read(dut.io.t1RocketProbe) + val rocketProbe = t1RocketProbe.rocketProbe.suggestName(s"rocketProbe") + val t1Probe = t1RocketProbe.t1Probe.suggestName(s"t1Probe") + val lsuProbe = t1Probe.lsuProbe.suggestName(s"t1LSUProbe") + val laneProbes = t1Probe.laneProbes.zipWithIndex.map { + case (p, idx) => + val wire = WireDefault(p).suggestName(s"lane${idx}Probe") + wire + } + val laneVrfProbes = t1Probe.laneProbes.map(_.vrfProbe).zipWithIndex.map { + case (p, idx) => + val wire = WireDefault(p).suggestName(s"lane${idx}VrfProbe") + wire + } + val storeUnitProbe = t1Probe.lsuProbe.storeUnitProbe.suggestName("storeUnitProbe") + val otherUnitProbe = t1Probe.lsuProbe.otherUnitProbe.suggestName("otherUnitProbe") + + // output the probes + // rocket reg write + when(rocketProbe.rfWen && !rocketProbe.isVector && rocketProbe.rfWaddr =/= 0.U && !(rocketProbe.waitWen && rocketProbe.waitWaddr =/= 0.U))( + printf( + cf"""{"event":"RegWrite","idx":${rocketProbe.rfWaddr},"data":"${rocketProbe.rfWdata}%x","cycle":${simulationTime}}\n""" + ) + ) + + when(rocketProbe.waitWen && !rocketProbe.isVector && rocketProbe.waitWaddr =/= 0.U)( + printf( + cf"""{"event":"RegWriteWait","idx":${rocketProbe.waitWaddr},"cycle":${simulationTime}}\n""" + ) + ) + + // [[option]] rocket fpu reg write + generator.parameter.fpuParameter.zip(t1RocketProbe.fpuProbe).zip(rocketProbe.fpuScoreboard).map { + case((fpuParameter, fpu), fpuScoreboard) => { + val fpToIEEE = Module(new FPToIEEE(FPToIEEEParameter( + fpuParameter.useAsyncReset, + fpuParameter.xLen, + fpuParameter.fLen, + fpuParameter.minFLen + ))) + val isVectorForLLWrite = RegNext(rocketProbe.isVector, false.B) + + fpToIEEE.io.clock := clock + fpToIEEE.io.reset := reset + fpToIEEE.io.in.valid := fpu.pipeWrite.rfWen || (fpu.loadOrVectorWrite.rfWen && !isVectorForLLWrite) + fpToIEEE.io.in.bits.data := Mux(fpu.pipeWrite.rfWen, fpu.pipeWrite.rfWdata, fpu.loadOrVectorWrite.rfWdata) + fpToIEEE.io.in.bits.typeTag := Mux(fpu.pipeWrite.rfWen, fpu.pipeWrite.rfWtypeTag, fpu.loadOrVectorWrite.rfWtypeTag) + + val rfWen = fpToIEEE.io.out.valid + val rfWaddr = Mux(fpu.pipeWrite.rfWen, fpu.pipeWrite.rfWaddr, fpu.loadOrVectorWrite.rfWaddr) + val rfWdata = fpToIEEE.io.out.bits + when(rfWen) { + printf( + cf"""{"event":"FregWrite","idx":$rfWaddr,"data":"$rfWdata%x","cycle":$simulationTime}\n""" + ) + } + + when(fpuScoreboard.fpuSetScoreBoard && !rfWen) { + printf( + cf"""{"event":"FregWriteWait","idx":${fpuScoreboard.scoreBoardSetAddress},"cycle":${simulationTime}}\n""" + ) + } + when(fpuScoreboard.memSetScoreBoard && !rfWen) { + printf( + cf"""{"event":"FregWriteWait","idx":${fpuScoreboard.scoreBoardSetAddress},"cycle":${simulationTime}}\n""" + ) + } + } + } + + // t1 vrf write + laneVrfProbes.zipWithIndex.foreach { + case (lane, i) => + when(lane.valid)( + printf( + cf"""{"event":"VrfWrite","issue_idx":${lane.requestInstruction},"vd":${lane.requestVd},"offset":${lane.requestOffset},"mask":"${lane.requestMask}%x","data":"${lane.requestData}%x","lane":$i,"cycle":${simulationTime}}\n""" + ) + ) + } + + // t1 memory write from store unit + when(storeUnitProbe.valid)( + printf( + cf"""{"event":"MemoryWrite","lsu_idx":${storeUnitProbe.index},"mask":"${storeUnitProbe.mask}%x","data":"${storeUnitProbe.data}%x","address":"${storeUnitProbe.address}%x","cycle":${simulationTime}}\n""" + ) + ) + + // t1 memory write from other unit + when(otherUnitProbe.valid)( + printf( + cf"""{"event":"MemoryWrite","lsu_idx":${otherUnitProbe.index},"mask":"${otherUnitProbe.mask}%x","data":"${otherUnitProbe.data}%x","address":"${otherUnitProbe.address}%x","cycle":${simulationTime}}\n""" + ) + ) + + // t1 issue + when(t1Probe.issue.valid)( + printf(cf"""{"event":"Issue","idx":${t1Probe.issue.bits},"cycle":${simulationTime}}\n""") + ) + + // t1 retire + when(t1Probe.retire.valid)( + printf( + cf"""{"event":"CheckRd","data":"${t1Probe.retire.bits}%x","issue_idx":${t1Probe.responseCounter},"cycle":${simulationTime}}\n""" + ) + ) + + // t1 lsu enq + when(t1Probe.lsuProbe.reqEnq.orR)( + printf(cf"""{"event":"LsuEnq","enq":${t1Probe.lsuProbe.reqEnq},"cycle":${simulationTime}}\n""") + ) + + // t1 vrf scoreboard + val vrfWriteScoreboard: Seq[Valid[UInt]] = Seq.tabulate(2 * generator.parameter.t1Parameter.chainingSize) { _ => + RegInit(0.U.asTypeOf(Valid(UInt(16.W)))) + } + vrfWriteScoreboard.foreach(scoreboard => dontTouch(scoreboard)) + val instructionValid = + (laneProbes.map(laneProbe => laneProbe.instructionValid ## laneProbe.instructionValid) :+ + lsuProbe.lsuInstructionValid :+ t1Probe.instructionValid).reduce(_ | _) + val scoreboardEnq = + Mux(t1Probe.instructionIssue, UIntToOH(t1Probe.issueTag), 0.U((2 * generator.parameter.t1Parameter.chainingSize).W)) + vrfWriteScoreboard.zipWithIndex.foreach { + case (scoreboard, tag) => + val writeEnq: UInt = VecInit( + // vrf write from lane + laneProbes.flatMap(laneProbe => + laneProbe.slots.map(slot => slot.writeTag === tag.U && slot.writeQueueEnq && slot.writeMask.orR) + ) ++ laneProbes.flatMap(laneProbe => + laneProbe.crossWriteProbe.map(cp => cp.bits.writeTag === tag.U && cp.valid && cp.bits.writeMask.orR) + ) ++ + // vrf write from lsu + lsuProbe.slots.map(slot => slot.dataInstruction === tag.U && slot.writeValid && slot.dataMask.orR) ++ + // vrf write from Sequencer + Some(t1Probe.writeQueueEnq.bits === tag.U && t1Probe.writeQueueEnq.valid && t1Probe.writeQueueEnqMask.orR) + ).asUInt + // always equal to array index + scoreboard.bits := scoreboard.bits + PopCount(writeEnq) + when(scoreboard.valid && !instructionValid(tag)) { + printf( + cf"""{"event":"VrfScoreboard","count":${scoreboard.bits},"issue_idx":${tag},"cycle":${simulationTime}}\n""" + ) + scoreboard.valid := false.B + } + when(scoreboardEnq(tag)) { + scoreboard.valid := true.B + assert(!scoreboard.valid) + scoreboard.bits := 0.U + } + } + + // t1 quit + val quitFlag: Bool = RegInit(false.B) + quitFlag := RawClockedNonVoidFunctionCall("cosim_quit", Bool())(clock, !quitFlag) + when(quitFlag && t1Probe.idle && rocketProbe.idle) { + stop(cf"""{"event":"SimulationEnd", "cycle":${simulationTime}}\n""") + } +} From 32e33bc8084f53447a3b368774198f2e6ff07425 Mon Sep 17 00:00:00 2001 From: Jiuyang Liu Date: Mon, 26 Aug 2024 16:01:54 +0800 Subject: [PATCH 5/5] [build system] add elaborator to T1RocketTestbench --- elaborator/src/Main.scala | 70 +++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/elaborator/src/Main.scala b/elaborator/src/Main.scala index 17ee483a2..8cd5bc48f 100644 --- a/elaborator/src/Main.scala +++ b/elaborator/src/Main.scala @@ -7,6 +7,7 @@ import mainargs._ import org.chipsalliance.t1.rtl.T1Parameter import org.chipsalliance.rocketv.RocketTileParameter import chisel3.panamalib.option._ +import org.chipsalliance.t1.tile.T1RocketTileParameter object Main { implicit object PathRead extends TokensReader.Simple[os.Path] { @@ -28,11 +29,15 @@ object Main { ).foldLeft( Seq( chisel3.stage.ChiselGeneratorAnnotation(gen), - chisel3.panamaconverter.stage.FirtoolOptionsAnnotation(FirtoolOptions(Set( - BuildMode(BuildModeDebug), - PreserveValues(PreserveValuesModeNamed), - DisableUnknownAnnotations(true) - ))), + chisel3.panamaconverter.stage.FirtoolOptionsAnnotation( + FirtoolOptions( + Set( + BuildMode(BuildModeDebug), + PreserveValues(PreserveValuesModeNamed), + DisableUnknownAnnotations(true) + ) + ) + ) ): firrtl.AnnotationSeq ) { case (annos, stage) => stage.transform(annos) } .flatMap { @@ -42,9 +47,9 @@ object Main { case chisel3.panamaconverter.stage.PanamaCIRCTConverterAnnotation(converter) => if (binderMlirbcOut.nonEmpty) panamaCIRCTConverter = converter None - case _: chisel3.panamaconverter.stage.FirtoolOptionsAnnotation => None - case _: chisel3.stage.DesignAnnotation[_] => None - case _: chisel3.stage.ChiselCircuitAnnotation => None + case _: chisel3.panamaconverter.stage.FirtoolOptionsAnnotation => None + case _: chisel3.stage.DesignAnnotation[_] => None + case _: chisel3.stage.ChiselCircuitAnnotation => None case a => Some(a) } @@ -63,31 +68,48 @@ object Main { case class IPConfig( @arg(name = "ip-config", short = 'c') ipConfig: os.Path) { def generator = upickle.default - .read[chisel3.experimental.SerializableModuleGenerator[org.chipsalliance.t1.rtl.T1, org.chipsalliance.t1.rtl.T1Parameter]](ujson.read(os.read(ipConfig))) + .read[chisel3.experimental.SerializableModuleGenerator[ + org.chipsalliance.t1.rtl.T1, + org.chipsalliance.t1.rtl.T1Parameter + ]](ujson.read(os.read(ipConfig))) def parameter: T1Parameter = generator.parameter } case class RocketConfig( @arg(name = "rocket-config", short = 'c') rocketConfig: os.Path) { def generator = upickle.default - .read[chisel3.experimental.SerializableModuleGenerator[org.chipsalliance.rocketv.RocketTile, org.chipsalliance.rocketv.RocketTileParameter]](ujson.read(os.read(rocketConfig))) + .read[chisel3.experimental.SerializableModuleGenerator[ + org.chipsalliance.rocketv.RocketTile, + org.chipsalliance.rocketv.RocketTileParameter + ]](ujson.read(os.read(rocketConfig))) def parameter: RocketTileParameter = generator.parameter } - implicit def ipConfig: ParserForClass[IPConfig] = ParserForClass[IPConfig] - implicit def rocketConfig: ParserForClass[RocketConfig] = ParserForClass[RocketConfig] - - // format: off - @main def ip(elaborateConfig: ElaborateConfig, ipConfig: IPConfig): Unit = elaborateConfig.elaborate(() => - ipConfig.generator.module() - ) - @main def ipemu(elaborateConfig: ElaborateConfig, ipConfig: IPConfig): Unit = elaborateConfig.elaborate(() => - new org.chipsalliance.t1.ipemu.TestBench(ipConfig.generator) - ) - @main def rocketemu(elaborateConfig: ElaborateConfig, rocketConfig: RocketConfig): Unit = elaborateConfig.elaborate(() => - new org.chipsalliance.t1.rocketv.TestBench(rocketConfig.generator) - ) - // format: on + case class T1RocketConfig( + @arg(name = "t1rocket-config", short = 'c') rocketConfig: os.Path) { + def generator = upickle.default + .read[chisel3.experimental.SerializableModuleGenerator[ + org.chipsalliance.t1.tile.T1RocketTile, + org.chipsalliance.t1.tile.T1RocketTileParameter + ]](ujson.read(os.read(rocketConfig))) + def parameter: T1RocketTileParameter = generator.parameter + } + + implicit def ipConfig: ParserForClass[IPConfig] = ParserForClass[IPConfig] + implicit def rocketConfig: ParserForClass[RocketConfig] = ParserForClass[RocketConfig] + implicit def t1RocketConfig: ParserForClass[T1RocketConfig] = ParserForClass[T1RocketConfig] + + @main def ip(elaborateConfig: ElaborateConfig, ipConfig: IPConfig): Unit = + elaborateConfig.elaborate(() => ipConfig.generator.module()) + + @main def ipemu(elaborateConfig: ElaborateConfig, ipConfig: IPConfig): Unit = + elaborateConfig.elaborate(() => new org.chipsalliance.t1.ipemu.TestBench(ipConfig.generator)) + + @main def rocketemu(elaborateConfig: ElaborateConfig, rocketConfig: RocketConfig): Unit = + elaborateConfig.elaborate(() => new org.chipsalliance.t1.rocketv.TestBench(rocketConfig.generator)) + + @main def t1rocketemu(elaborateConfig: ElaborateConfig, t1rocketConfig: T1RocketConfig): Unit = + elaborateConfig.elaborate(() => new org.chipsalliance.t1.t1rocketemu.TestBench(t1rocketConfig.generator)) def main(args: Array[String]): Unit = ParserForMethods(this).runOrExit(args) }