From 607c2b5a73674fb9d1c6d8926d2fafb737855604 Mon Sep 17 00:00:00 2001 From: Jerry Zhao Date: Fri, 12 May 2023 08:21:18 -0700 Subject: [PATCH] Unify multi-node btw chipyard/firechip | unify harness clocking --- fpga/src/main/scala/arty/Configs.scala | 4 + fpga/src/main/scala/arty/HarnessBinders.scala | 2 +- fpga/src/main/scala/arty/TestHarness.scala | 29 +- fpga/src/main/scala/arty100t/Configs.scala | 8 +- fpga/src/main/scala/arty100t/Harness.scala | 56 ++-- .../main/scala/arty100t/HarnessBinders.scala | 39 ++- fpga/src/main/scala/vc707/Configs.scala | 16 +- fpga/src/main/scala/vc707/TestHarness.scala | 58 ++-- fpga/src/main/scala/vcu118/Configs.scala | 17 +- .../main/scala/vcu118/HarnessBinders.scala | 10 +- fpga/src/main/scala/vcu118/TestHarness.scala | 50 ++-- .../scala/vcu118/bringup/HarnessBinders.scala | 10 +- .../scala/vcu118/bringup/TestHarness.scala | 12 +- .../main/scala/clocking/ClockBinders.scala | 1 + .../scala/clocking/ClockGroupCombiner.scala | 16 +- .../clocking/ClockGroupNamePrefixer.scala | 32 +-- .../main/scala/clocking/HasChipyardPRCI.scala | 3 +- .../main/scala/config/AbstractConfig.scala | 6 +- .../src/main/scala/config/ChipConfigs.scala | 2 +- .../src/main/scala/config/RocketConfigs.scala | 11 +- .../main/scala/config/TracegenConfigs.scala | 1 - .../config/fragments/ClockingFragments.scala | 9 - .../main/scala/example/FlatTestHarness.scala | 5 +- .../main/scala/harness/HarnessBinders.scala | 160 +++++------ .../main/scala/harness/HarnessClocks.scala | 48 ++-- .../harness/HasHarnessInstantiators.scala | 95 +++++++ .../src/main/scala/harness/TestHarness.scala | 45 +-- .../src/main/scala/BridgeBinders.scala | 39 ++- .../firechip/src/main/scala/FireSim.scala | 261 +++--------------- .../src/main/scala/TargetConfigs.scala | 28 +- generators/testchipip | 2 +- 31 files changed, 441 insertions(+), 634 deletions(-) create mode 100644 generators/chipyard/src/main/scala/harness/HasHarnessInstantiators.scala diff --git a/fpga/src/main/scala/arty/Configs.scala b/fpga/src/main/scala/arty/Configs.scala index ad8b9a32..9f113575 100644 --- a/fpga/src/main/scala/arty/Configs.scala +++ b/fpga/src/main/scala/arty/Configs.scala @@ -21,8 +21,12 @@ class WithArtyTweaks extends Config( new WithArtyJTAGHarnessBinder ++ new WithArtyUARTHarnessBinder ++ new WithDebugResetPassthrough ++ + + new chipyard.harness.WithHarnessBinderClockFreqMHz(32) ++ new chipyard.harness.WithAllClocksFromHarnessClockInstantiator ++ new chipyard.config.WithDTSTimebase(32768) ++ + new chipyard.config.WithSystemBusFrequency(32) ++ + new chipyard.config.WithPeripheryBusFrequency(32) ++ new testchipip.WithNoSerialTL ) diff --git a/fpga/src/main/scala/arty/HarnessBinders.scala b/fpga/src/main/scala/arty/HarnessBinders.scala index 84d47967..1d96cecf 100644 --- a/fpga/src/main/scala/arty/HarnessBinders.scala +++ b/fpga/src/main/scala/arty/HarnessBinders.scala @@ -31,7 +31,7 @@ class WithArtyResetHarnessBinder extends ComposeHarnessBinder({ class WithArtyJTAGHarnessBinder extends OverrideHarnessBinder({ (system: HasPeripheryDebug, th: ArtyFPGATestHarness, ports: Seq[Data]) => { ports.map { - case j: JTAGChipIO => withClockAndReset(th.buildtopClock, th.hReset) { + case j: JTAGChipIO => { val jtag_wire = Wire(new JTAGIO) jtag_wire.TDO.data := j.TDO jtag_wire.TDO.driven := true.B diff --git a/fpga/src/main/scala/arty/TestHarness.scala b/fpga/src/main/scala/arty/TestHarness.scala index 6f7c5ea5..4968b189 100644 --- a/fpga/src/main/scala/arty/TestHarness.scala +++ b/fpga/src/main/scala/arty/TestHarness.scala @@ -8,13 +8,10 @@ import org.chipsalliance.cde.config.{Parameters} import sifive.fpgashells.shell.xilinx.artyshell.{ArtyShell} -import chipyard.harness.{ApplyHarnessBinders, BuildTop, HasHarnessSignalReferences} +import chipyard.harness.{HasHarnessInstantiators} import chipyard.iobinders.{HasIOBinders} -class ArtyFPGATestHarness(override implicit val p: Parameters) extends ArtyShell with HasHarnessSignalReferences { - - val lazyDut = LazyModule(p(BuildTop)(p)).suggestName("chiptop") - +class ArtyFPGATestHarness(override implicit val p: Parameters) extends ArtyShell with HasHarnessInstantiators { // Convert harness resets from Bool to Reset type. val hReset = Wire(Reset()) hReset := ~ck_rst @@ -22,24 +19,10 @@ class ArtyFPGATestHarness(override implicit val p: Parameters) extends ArtyShell val dReset = Wire(AsyncReset()) dReset := reset_core.asAsyncReset - // default to 32MHz clock - withClockAndReset(clock_32MHz, hReset) { - val dut = Module(lazyDut.module) - } + def success = {require(false, "Success not supported"); false.B } - val buildtopClock = clock_32MHz - val buildtopReset = hReset - val success = false.B + def implicitClock = clock_32MHz + def implicitReset = hReset - val dutReset = dReset - - // must be after HasHarnessSignalReferences assignments - lazyDut match { case d: HasIOBinders => - ApplyHarnessBinders(this, d.lazySystem, d.portMap) - } - - val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters())) - implicitHarnessClockBundle.clock := buildtopClock - implicitHarnessClockBundle.reset := buildtopReset - harnessClockInstantiator.instantiateHarnessClocks(implicitHarnessClockBundle) + instantiateChipTops() } diff --git a/fpga/src/main/scala/arty100t/Configs.scala b/fpga/src/main/scala/arty100t/Configs.scala index 16683141..20790e12 100644 --- a/fpga/src/main/scala/arty100t/Configs.scala +++ b/fpga/src/main/scala/arty100t/Configs.scala @@ -26,6 +26,12 @@ class WithArty100TTweaks extends Config( new WithArty100TUARTTSI ++ new WithArty100TDDRTL ++ new WithNoDesignKey ++ + new chipyard.harness.WithHarnessBinderClockFreqMHz(50) ++ + new chipyard.config.WithMemoryBusFrequency(50.0) ++ + new chipyard.config.WithSystemBusFrequency(50.0) ++ + new chipyard.config.WithPeripheryBusFrequency(50.0) ++ + new chipyard.harness.WithAllClocksFromHarnessClockInstantiator ++ + new chipyard.clocking.WithPassthroughClockGenerator ++ new chipyard.config.WithNoDebug ++ // no jtag new chipyard.config.WithNoUART ++ // use UART for the UART-TSI thing instad new chipyard.config.WithTLBackingMemory ++ // FPGA-shells converts the AXI to TL for us @@ -34,8 +40,6 @@ class WithArty100TTweaks extends Config( class RocketArty100TConfig extends Config( new WithArty100TTweaks ++ - new chipyard.config.WithMemoryBusFrequency(50.0) ++ - new chipyard.config.WithPeripheryBusFrequency(50.0) ++ // Match the sbus and pbus frequency new chipyard.config.WithBroadcastManager ++ // no l2 new chipyard.RocketConfig) diff --git a/fpga/src/main/scala/arty100t/Harness.scala b/fpga/src/main/scala/arty100t/Harness.scala index d4e7ebc9..78035cda 100644 --- a/fpga/src/main/scala/arty100t/Harness.scala +++ b/fpga/src/main/scala/arty100t/Harness.scala @@ -4,8 +4,9 @@ import chisel3._ import chisel3.util._ import freechips.rocketchip.diplomacy._ import org.chipsalliance.cde.config.{Parameters} -import freechips.rocketchip.tilelink.{TLClientNode, TLBlockDuringReset} +import freechips.rocketchip.tilelink._ import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters} +import freechips.rocketchip.subsystem.{SystemBusKey} import sifive.fpgashells.shell.xilinx._ import sifive.fpgashells.shell._ @@ -14,21 +15,21 @@ import sifive.fpgashells.ip.xilinx.{IBUF, PowerOnResetFPGAOnly} import sifive.blocks.devices.uart._ -import chipyard.{ChipTop, CanHaveMasterTLMemPort, ExtTLMem} +import chipyard._ import chipyard.harness._ import chipyard.iobinders.{HasIOBinders} -class Arty100THarness(override implicit val p: Parameters) extends Arty100TShell with HasHarnessSignalReferences -{ +class Arty100THarness(override implicit val p: Parameters) extends Arty100TShell { def dp = designParameters - val chiptop = LazyModule(p(BuildTop)(p)) + require(dp(MultiChipNChips) == 0, "Arty100T harness does not support multi-chip") val clockOverlay = dp(ClockInputOverlayKey).map(_.place(ClockInputDesignInput())).head val harnessSysPLL = dp(PLLFactoryKey) val harnessSysPLLNode = harnessSysPLL() - println(s"Arty100T FPGA Base Clock Freq: ${dp(DefaultClockFrequencyKey)} MHz") - val dutClock = ClockSinkNode(freqMHz = dp(DefaultClockFrequencyKey)) + val dutFreqMHz = (dp(SystemBusKey).dtsFrequency.get / (1000 * 1000)).toInt + val dutClock = ClockSinkNode(freqMHz = dutFreqMHz) + println(s"Arty100T FPGA Base Clock Freq: ${dutFreqMHz} MHz") val dutWrangler = LazyModule(new ResetWrangler()) val dutGroup = ClockGroup() dutClock := dutWrangler.node := dutGroup := harnessSysPLLNode @@ -39,12 +40,10 @@ class Arty100THarness(override implicit val p: Parameters) extends Arty100TShell val uartOverlay = dp(UARTOverlayKey).head.place(UARTDesignInput(io_uart_bb)) val ddrOverlay = dp(DDROverlayKey).head.place(DDRDesignInput(dp(ExtTLMem).get.master.base, dutWrangler.node, harnessSysPLLNode)).asInstanceOf[DDRArtyPlacedOverlay] - val ddrInParams = chiptop match { case td: ChipTop => - td.lazySystem match { case lsys: CanHaveMasterTLMemPort => - lsys.memTLNode.edges.in(0) - } - } - val ddrClient = TLClientNode(Seq(ddrInParams.master)) + val ddrClient = TLClientNode(Seq(TLMasterPortParameters.v1(Seq(TLMasterParameters.v1( + name = "chip_ddr", + sourceId = IdRange(0, 64) + ))))) val ddrBlockDuringReset = LazyModule(new TLBlockDuringReset(4)) ddrOverlay.overlayOutput.ddr := ddrBlockDuringReset.node := ddrClient @@ -53,17 +52,16 @@ class Arty100THarness(override implicit val p: Parameters) extends Arty100TShell val status_leds = all_leds.take(3) val other_leds = all_leds.drop(3) - def buildtopClock = dutClock.in.head._1.clock - def buildtopReset = dutClock.in.head._1.reset - def success = { require(false, "Unused"); false.B } - InModuleBody { + override lazy val module = new HarnessLikeImpl + + class HarnessLikeImpl extends Impl with HasHarnessInstantiators { clockOverlay.overlayOutput.node.out(0)._1.reset := ~resetPin val clk_100mhz = clockOverlay.overlayOutput.node.out.head._1.clock // Blink the status LEDs for sanity - withClock(clk_100mhz) { + withClockAndReset(clk_100mhz, dutClock.in.head._1.reset) { val period = (BigInt(100) << 20) / status_leds.size val counter = RegInit(0.U(log2Ceil(period).W)) val on = RegInit(0.U(log2Ceil(status_leds.size).W)) @@ -78,21 +76,17 @@ class Arty100THarness(override implicit val p: Parameters) extends Arty100TShell harnessSysPLL.plls.foreach(_._1.getReset.get := pllReset) - ddrOverlay.mig.module.clock := buildtopClock - ddrOverlay.mig.module.reset := buildtopReset - ddrBlockDuringReset.module.clock := buildtopClock - ddrBlockDuringReset.module.reset := buildtopReset || !ddrOverlay.mig.module.io.port.init_calib_complete + def implicitClock = dutClock.in.head._1.clock + def implicitReset = dutClock.in.head._1.reset + def success = { require(false, "Unused"); false.B } + + ddrOverlay.mig.module.clock := harnessBinderClock + ddrOverlay.mig.module.reset := harnessBinderReset + ddrBlockDuringReset.module.clock := harnessBinderClock + ddrBlockDuringReset.module.reset := harnessBinderReset.asBool || !ddrOverlay.mig.module.io.port.init_calib_complete other_leds(6) := ddrOverlay.mig.module.io.port.init_calib_complete - chiptop match { case d: HasIOBinders => - ApplyHarnessBinders(this, d.lazySystem, d.portMap) - } - - val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters())) - implicitHarnessClockBundle.clock := buildtopClock - implicitHarnessClockBundle.reset := buildtopReset - harnessClockInstantiator.instantiateHarnessClocks(implicitHarnessClockBundle) + instantiateChipTops() } - } diff --git a/fpga/src/main/scala/arty100t/HarnessBinders.scala b/fpga/src/main/scala/arty100t/HarnessBinders.scala index c403b604..f6750d37 100644 --- a/fpga/src/main/scala/arty100t/HarnessBinders.scala +++ b/fpga/src/main/scala/arty100t/HarnessBinders.scala @@ -6,6 +6,7 @@ import freechips.rocketchip.jtag.{JTAGIO} import freechips.rocketchip.subsystem.{PeripheryBusKey} import freechips.rocketchip.tilelink.{TLBundle} import freechips.rocketchip.util.{HeterogeneousBag} +import freechips.rocketchip.diplomacy.{LazyRawModuleImp} import sifive.blocks.devices.uart.{UARTPortIO, HasPeripheryUARTModuleImp, UARTParams} import sifive.blocks.devices.jtag.{JTAGPins, JTAGPinsFromPort} @@ -20,39 +21,37 @@ import chipyard.iobinders.JTAGChipIO import testchipip._ class WithArty100TUARTTSI(uartBaudRate: BigInt = 115200) extends OverrideHarnessBinder({ - (system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { + (system: CanHavePeripheryTLSerial, th: HasHarnessInstantiators, ports: Seq[ClockedIO[SerialIO]]) => { implicit val p = chipyard.iobinders.GetSystemParameters(system) ports.map({ port => - val ath = th.asInstanceOf[Arty100THarness] + val ath = th.asInstanceOf[LazyRawModuleImp].wrapper.asInstanceOf[Arty100THarness] val freq = p(PeripheryBusKey).dtsFrequency.get val bits = port.bits - port.clock := th.buildtopClock - withClockAndReset(th.buildtopClock, th.buildtopReset) { - val ram = TSIHarness.connectRAM(system.serdesser.get, bits, th.buildtopReset) - val uart_to_serial = Module(new UARTToSerial( - freq, UARTParams(0, initBaudRate=uartBaudRate))) - val serial_width_adapter = Module(new SerialWidthAdapter( - narrowW = 8, wideW = TSI.WIDTH)) - serial_width_adapter.io.narrow.flipConnect(uart_to_serial.io.serial) + port.clock := th.harnessBinderClock + val ram = TSIHarness.connectRAM(system.serdesser.get, bits, th.harnessBinderReset) + val uart_to_serial = Module(new UARTToSerial( + freq, UARTParams(0, initBaudRate=uartBaudRate))) + val serial_width_adapter = Module(new SerialWidthAdapter( + narrowW = 8, wideW = TSI.WIDTH)) + serial_width_adapter.io.narrow.flipConnect(uart_to_serial.io.serial) - ram.module.io.tsi.flipConnect(serial_width_adapter.io.wide) + ram.module.io.tsi.flipConnect(serial_width_adapter.io.wide) - ath.io_uart_bb.bundle <> uart_to_serial.io.uart - ath.other_leds(1) := uart_to_serial.io.dropped + ath.io_uart_bb.bundle <> uart_to_serial.io.uart + ath.other_leds(1) := uart_to_serial.io.dropped - ath.other_leds(9) := ram.module.io.tsi2tl_state(0) - ath.other_leds(10) := ram.module.io.tsi2tl_state(1) - ath.other_leds(11) := ram.module.io.tsi2tl_state(2) - ath.other_leds(12) := ram.module.io.tsi2tl_state(3) - } + ath.other_leds(9) := ram.module.io.tsi2tl_state(0) + ath.other_leds(10) := ram.module.io.tsi2tl_state(1) + ath.other_leds(11) := ram.module.io.tsi2tl_state(2) + ath.other_leds(12) := ram.module.io.tsi2tl_state(3) }) } }) class WithArty100TDDRTL extends OverrideHarnessBinder({ - (system: CanHaveMasterTLMemPort, th: HasHarnessSignalReferences, ports: Seq[HeterogeneousBag[TLBundle]]) => { + (system: CanHaveMasterTLMemPort, th: HasHarnessInstantiators, ports: Seq[HeterogeneousBag[TLBundle]]) => { require(ports.size == 1) - val artyTh = th.asInstanceOf[Arty100THarness] + val artyTh = th.asInstanceOf[LazyRawModuleImp].wrapper.asInstanceOf[Arty100THarness] val bundles = artyTh.ddrClient.out.map(_._1) val ddrClientBundle = Wire(new HeterogeneousBag(bundles.map(_.cloneType))) bundles.zip(ddrClientBundle).foreach { case (bundle, io) => bundle <> io } diff --git a/fpga/src/main/scala/vc707/Configs.scala b/fpga/src/main/scala/vc707/Configs.scala index 70bd7073..55ce8e06 100644 --- a/fpga/src/main/scala/vc707/Configs.scala +++ b/fpga/src/main/scala/vc707/Configs.scala @@ -18,7 +18,7 @@ import sifive.fpgashells.shell.xilinx.{VC7074GDDRSize} import testchipip.{SerialTLKey} import chipyard.{BuildSystem, ExtTLMem} -import chipyard.harness.{DefaultClockFrequencyKey} +import chipyard.harness._ class WithDefaultPeripherals extends Config((site, here, up) => { case PeripheryUARTKey => List(UARTParams(address = BigInt(0x64000000L))) @@ -29,7 +29,7 @@ class WithSystemModifications extends Config((site, here, up) => { case DTSTimebase => BigInt{(1e6).toLong} case BootROMLocated(x) => up(BootROMLocated(x), site).map { p => // invoke makefile for sdboot - val freqMHz = (site(DefaultClockFrequencyKey) * 1e6).toLong + val freqMHz = (site(SystemBusKey).dtsFrequency.get / (1000 * 1000)).toLong val make = s"make -C fpga/src/main/resources/vc707/sdboot PBUS_CLK=${freqMHz} bin" require (make.! == 0, "Failed to build bootrom") p.copy(hang = 0x10000, contentFileName = s"./fpga/src/main/resources/vc707/sdboot/build/sdboot.bin") @@ -39,6 +39,15 @@ class WithSystemModifications extends Config((site, here, up) => { }) class WithVC707Tweaks extends Config ( + // clocking + new chipyard.harness.WithAllClocksFromHarnessClockInstantiator ++ + new chipyard.clocking.WithPassthroughClockGenerator ++ + new chipyard.config.WithMemoryBusFrequency(50.0) ++ + new chipyard.config.WithSystemBusFrequency(50.0) ++ + new chipyard.config.WithPeripheryBusFrequency(50.0) ++ + + new chipyard.harness.WithHarnessBinderClockFreqMHz(50) ++ + new WithFPGAFrequency(50) ++ // default 50MHz freq // harness binders new chipyard.harness.WithAllClocksFromHarnessClockInstantiator ++ new WithVC707UARTHarnessBinder ++ @@ -54,8 +63,7 @@ class WithVC707Tweaks extends Config ( new WithSystemModifications ++ // setup busses, use sdboot bootrom, setup ext. mem. size new chipyard.config.WithNoDebug ++ // remove debug module new freechips.rocketchip.subsystem.WithoutTLMonitors ++ - new freechips.rocketchip.subsystem.WithNMemoryChannels(1) ++ - new WithFPGAFrequency(50) // default 50MHz freq + new freechips.rocketchip.subsystem.WithNMemoryChannels(1) ) class RocketVC707Config extends Config ( diff --git a/fpga/src/main/scala/vc707/TestHarness.scala b/fpga/src/main/scala/vc707/TestHarness.scala index 553cf06e..99232d6e 100644 --- a/fpga/src/main/scala/vc707/TestHarness.scala +++ b/fpga/src/main/scala/vc707/TestHarness.scala @@ -1,25 +1,25 @@ package chipyard.fpga.vc707 - import chisel3._ import chisel3.experimental.{IO} import freechips.rocketchip.diplomacy.{LazyModule, LazyRawModuleImp, BundleBridgeSource} import org.chipsalliance.cde.config.{Parameters} -import freechips.rocketchip.tilelink.{TLClientNode} -import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters} +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.subsystem.{SystemBusKey} +import freechips.rocketchip.diplomacy.{IdRange, TransferSizes} import sifive.fpgashells.shell.xilinx.{VC707Shell, UARTVC707ShellPlacer, PCIeVC707ShellPlacer, ChipLinkVC707PlacedOverlay} import sifive.fpgashells.ip.xilinx.{IBUF, PowerOnResetFPGAOnly} -import sifive.fpgashells.shell.{ClockInputOverlayKey, ClockInputDesignInput, UARTOverlayKey, UARTDesignInput, UARTShellInput, LEDOverlayKey, LEDDesignInput, SwitchOverlayKey, SwitchDesignInput, ButtonOverlayKey, ButtonDesignInput, SPIOverlayKey, SPIDesignInput, ChipLinkOverlayKey, ChipLinkDesignInput, PCIeOverlayKey, PCIeDesignInput, PCIeShellInput, DDROverlayKey, DDRDesignInput, JTAGDebugOverlayKey, JTAGDebugDesignInput} +import sifive.fpgashells.shell._ import sifive.fpgashells.clocks.{ClockGroup, ClockSinkNode, PLLFactoryKey, ResetWrangler} import sifive.fpgashells.devices.xilinx.xilinxvc707pciex1.{XilinxVC707PCIeX1IO} import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTPortIO} import sifive.blocks.devices.spi.{PeripherySPIKey, SPIPortIO} -import chipyard.{ChipTop, ExtTLMem, CanHaveMasterTLMemPort} +import chipyard._ import chipyard.iobinders.{HasIOBinders} -import chipyard.harness.{ApplyHarnessBinders, HasHarnessSignalReferences, BuildTop, DefaultClockFrequencyKey} +import chipyard.harness._ class VC707FPGATestHarness(override implicit val p: Parameters) extends VC707Shell { outer => @@ -28,8 +28,6 @@ class VC707FPGATestHarness(override implicit val p: Parameters) extends VC707She // Order matters; ddr depends on sys_clock val uart = Overlay(UARTOverlayKey, new UARTVC707ShellPlacer(this, UARTShellInput())) - val topDesign = LazyModule(p(BuildTop)(dp)).suggestName("chiptop") - // place all clocks in the shell require(dp(ClockInputOverlayKey).size >= 1) val sysClkNode = dp(ClockInputOverlayKey).head.place(ClockInputDesignInput()).overlayOutput.node @@ -41,8 +39,9 @@ class VC707FPGATestHarness(override implicit val p: Parameters) extends VC707She harnessSysPLL := sysClkNode // create and connect to the dutClock - println(s"VC707 FPGA Base Clock Freq: ${dp(DefaultClockFrequencyKey)} MHz") - val dutClock = ClockSinkNode(freqMHz = dp(DefaultClockFrequencyKey)) + val dutFreqMHz = (dp(SystemBusKey).dtsFrequency.get / (1000 * 1000)).toInt + val dutClock = ClockSinkNode(freqMHz = dutFreqMHz) + println(s"VC707 FPGA Base Clock Freq: ${dutFreqMHz} MHz") val dutWrangler = LazyModule(new ResetWrangler) val dutGroup = ClockGroup() dutClock := dutWrangler.node := dutGroup := harnessSysPLL @@ -77,21 +76,19 @@ class VC707FPGATestHarness(override implicit val p: Parameters) extends VC707She // Modify the last field of `DDRDesignInput` for 1GB RAM size val ddrNode = dp(DDROverlayKey).head.place(DDRDesignInput(dp(ExtTLMem).get.master.base, dutWrangler.node, harnessSysPLL, true)).overlayOutput.ddr + val ddrClient = TLClientNode(Seq(TLMasterPortParameters.v1(Seq(TLMasterParameters.v1( + name = "chip_ddr", + sourceId = IdRange(0, 64) + ))))) - // connect 1 mem. channel to the FPGA DDR - val inParams = topDesign match { case td: ChipTop => - td.lazySystem match { case lsys: CanHaveMasterTLMemPort => - lsys.memTLNode.edges.in(0) - } - } - val ddrClient = TLClientNode(Seq(inParams.master)) ddrNode := ddrClient // module implementation override lazy val module = new VC707FPGATestHarnessImp(this) } -class VC707FPGATestHarnessImp(_outer: VC707FPGATestHarness) extends LazyRawModuleImp(_outer) with HasHarnessSignalReferences { +class VC707FPGATestHarnessImp(_outer: VC707FPGATestHarness) extends LazyRawModuleImp(_outer) with HasHarnessInstantiators { + require (p(MultiChipNChips) == 0) val vc707Outer = _outer @@ -117,25 +114,12 @@ class VC707FPGATestHarnessImp(_outer: VC707FPGATestHarness) extends LazyRawModul val hReset = Wire(Reset()) hReset := _outer.dutClock.in.head._1.reset - val buildtopClock = _outer.dutClock.in.head._1.clock - val buildtopReset = WireInit(hReset) - val dutReset = hReset.asAsyncReset - val success = false.B + def implicitClock = _outer.dutClock.in.head._1.clock + def implicitReset = hReset + def success = { require(false, "Unused"); false.B } - childClock := buildtopClock - childReset := buildtopReset + childClock := implicitClock + childReset := implicitReset - // harness binders are non-lazy - _outer.topDesign match { case d: HasIOBinders => - ApplyHarnessBinders(this, d.lazySystem, d.portMap) - } - - // check the top-level reference clock is equal to the default - // non-exhaustive since you need all ChipTop clocks to equal the default - require(getRefClockFreq == p(DefaultClockFrequencyKey)) - - val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters())) - implicitHarnessClockBundle.clock := buildtopClock - implicitHarnessClockBundle.reset := buildtopReset - harnessClockInstantiator.instantiateHarnessClocks(implicitHarnessClockBundle) + instantiateChipTops() } diff --git a/fpga/src/main/scala/vcu118/Configs.scala b/fpga/src/main/scala/vcu118/Configs.scala index 0d82e107..7ba39f78 100644 --- a/fpga/src/main/scala/vcu118/Configs.scala +++ b/fpga/src/main/scala/vcu118/Configs.scala @@ -17,8 +17,8 @@ import sifive.fpgashells.shell.xilinx.{VCU118ShellPMOD, VCU118DDRSize} import testchipip.{SerialTLKey} -import chipyard.{BuildSystem, ExtTLMem} -import chipyard.harness.{DefaultClockFrequencyKey} +import chipyard._ +import chipyard.harness._ class WithDefaultPeripherals extends Config((site, here, up) => { case PeripheryUARTKey => List(UARTParams(address = BigInt(0x64000000L))) @@ -30,7 +30,7 @@ class WithSystemModifications extends Config((site, here, up) => { case DTSTimebase => BigInt((1e6).toLong) case BootROMLocated(x) => up(BootROMLocated(x), site).map { p => // invoke makefile for sdboot - val freqMHz = (site(DefaultClockFrequencyKey) * 1e6).toLong + val freqMHz = (site(SystemBusKey).dtsFrequency.get / (1000 * 1000)).toLong val make = s"make -C fpga/src/main/resources/vcu118/sdboot PBUS_CLK=${freqMHz} bin" require (make.! == 0, "Failed to build bootrom") p.copy(hang = 0x10000, contentFileName = s"./fpga/src/main/resources/vcu118/sdboot/build/sdboot.bin") @@ -41,8 +41,14 @@ class WithSystemModifications extends Config((site, here, up) => { // DOC include start: AbstractVCU118 and Rocket class WithVCU118Tweaks extends Config( - // harness binders + // clocking new chipyard.harness.WithAllClocksFromHarnessClockInstantiator ++ + new chipyard.clocking.WithPassthroughClockGenerator ++ + new chipyard.config.WithMemoryBusFrequency(100) ++ + new chipyard.config.WithSystemBusFrequency(100) ++ + new chipyard.config.WithPeripheryBusFrequency(100) ++ + new WithFPGAFrequency(100) ++ // default 100MHz freq + // harness binders new WithUART ++ new WithSPISDCard ++ new WithDDRMem ++ @@ -55,8 +61,7 @@ class WithVCU118Tweaks extends Config( new WithSystemModifications ++ // setup busses, use sdboot bootrom, setup ext. mem. size new chipyard.config.WithNoDebug ++ // remove debug module new freechips.rocketchip.subsystem.WithoutTLMonitors ++ - new freechips.rocketchip.subsystem.WithNMemoryChannels(1) ++ - new WithFPGAFrequency(100) // default 100MHz freq + new freechips.rocketchip.subsystem.WithNMemoryChannels(1) ) class RocketVCU118Config extends Config( diff --git a/fpga/src/main/scala/vcu118/HarnessBinders.scala b/fpga/src/main/scala/vcu118/HarnessBinders.scala index 50fbfeb4..f17b654f 100644 --- a/fpga/src/main/scala/vcu118/HarnessBinders.scala +++ b/fpga/src/main/scala/vcu118/HarnessBinders.scala @@ -9,12 +9,12 @@ import freechips.rocketchip.tilelink.{TLBundle} import sifive.blocks.devices.uart.{HasPeripheryUARTModuleImp, UARTPortIO} import sifive.blocks.devices.spi.{HasPeripherySPI, SPIPortIO} -import chipyard.{CanHaveMasterTLMemPort} -import chipyard.harness.{HasHarnessSignalReferences, OverrideHarnessBinder} +import chipyard._ +import chipyard.harness._ /*** UART ***/ class WithUART extends OverrideHarnessBinder({ - (system: HasPeripheryUARTModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[UARTPortIO]) => { + (system: HasPeripheryUARTModuleImp, th: BaseModule with HasHarnessInstantiators, ports: Seq[UARTPortIO]) => { th match { case vcu118th: VCU118FPGATestHarnessImp => { vcu118th.vcu118Outer.io_uart_bb.bundle <> ports.head } } @@ -23,7 +23,7 @@ class WithUART extends OverrideHarnessBinder({ /*** SPI ***/ class WithSPISDCard extends OverrideHarnessBinder({ - (system: HasPeripherySPI, th: BaseModule with HasHarnessSignalReferences, ports: Seq[SPIPortIO]) => { + (system: HasPeripherySPI, th: BaseModule with HasHarnessInstantiators, ports: Seq[SPIPortIO]) => { th match { case vcu118th: VCU118FPGATestHarnessImp => { vcu118th.vcu118Outer.io_spi_bb.bundle <> ports.head } } @@ -32,7 +32,7 @@ class WithSPISDCard extends OverrideHarnessBinder({ /*** Experimental DDR ***/ class WithDDRMem extends OverrideHarnessBinder({ - (system: CanHaveMasterTLMemPort, th: BaseModule with HasHarnessSignalReferences, ports: Seq[HeterogeneousBag[TLBundle]]) => { + (system: CanHaveMasterTLMemPort, th: BaseModule with HasHarnessInstantiators, ports: Seq[HeterogeneousBag[TLBundle]]) => { th match { case vcu118th: VCU118FPGATestHarnessImp => { require(ports.size == 1) diff --git a/fpga/src/main/scala/vcu118/TestHarness.scala b/fpga/src/main/scala/vcu118/TestHarness.scala index 5ca3d4a0..b2032596 100644 --- a/fpga/src/main/scala/vcu118/TestHarness.scala +++ b/fpga/src/main/scala/vcu118/TestHarness.scala @@ -5,8 +5,9 @@ import chisel3.experimental.{IO} import freechips.rocketchip.diplomacy.{LazyModule, LazyRawModuleImp, BundleBridgeSource} import org.chipsalliance.cde.config.{Parameters} -import freechips.rocketchip.tilelink.{TLClientNode} -import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters} +import freechips.rocketchip.tilelink._ +import freechips.rocketchip.diplomacy.{IdRange, TransferSizes} +import freechips.rocketchip.subsystem.{SystemBusKey} import sifive.fpgashells.shell.xilinx._ import sifive.fpgashells.ip.xilinx.{IBUF, PowerOnResetFPGAOnly} @@ -38,8 +39,6 @@ class VCU118FPGATestHarness(override implicit val p: Parameters) extends VCU118S val sys_clock2 = Overlay(ClockInputOverlayKey, new SysClock2VCU118ShellPlacer(this, ClockInputShellInput())) val ddr2 = Overlay(DDROverlayKey, new DDR2VCU118ShellPlacer(this, DDRShellInput())) - val topDesign = LazyModule(p(BuildTop)(dp)).suggestName("chiptop") - // DOC include start: ClockOverlay // place all clocks in the shell require(dp(ClockInputOverlayKey).size >= 1) @@ -52,8 +51,9 @@ class VCU118FPGATestHarness(override implicit val p: Parameters) extends VCU118S harnessSysPLL := sysClkNode // create and connect to the dutClock - println(s"VCU118 FPGA Base Clock Freq: ${dp(DefaultClockFrequencyKey)} MHz") - val dutClock = ClockSinkNode(freqMHz = dp(DefaultClockFrequencyKey)) + val dutFreqMHz = (dp(SystemBusKey).dtsFrequency.get / (1000 * 1000)).toInt + val dutClock = ClockSinkNode(freqMHz = dutFreqMHz) + println(s"VCU118 FPGA Base Clock Freq: ${dutFreqMHz} MHz") val dutWrangler = LazyModule(new ResetWrangler) val dutGroup = ClockGroup() dutClock := dutWrangler.node := dutGroup := harnessSysPLL @@ -80,19 +80,18 @@ class VCU118FPGATestHarness(override implicit val p: Parameters) extends VCU118S val ddrNode = dp(DDROverlayKey).head.place(DDRDesignInput(dp(ExtTLMem).get.master.base, dutWrangler.node, harnessSysPLL)).overlayOutput.ddr // connect 1 mem. channel to the FPGA DDR - val inParams = topDesign match { case td: ChipTop => - td.lazySystem match { case lsys: CanHaveMasterTLMemPort => - lsys.memTLNode.edges.in(0) - } - } - val ddrClient = TLClientNode(Seq(inParams.master)) + val ddrClient = TLClientNode(Seq(TLMasterPortParameters.v1(Seq(TLMasterParameters.v1( + name = "chip_ddr", + sourceId = IdRange(0, 64) + ))))) ddrNode := ddrClient // module implementation override lazy val module = new VCU118FPGATestHarnessImp(this) } -class VCU118FPGATestHarnessImp(_outer: VCU118FPGATestHarness) extends LazyRawModuleImp(_outer) with HasHarnessSignalReferences { +class VCU118FPGATestHarnessImp(_outer: VCU118FPGATestHarness) extends LazyRawModuleImp(_outer) with HasHarnessInstantiators { + require(p(MultiChipNChips) == 0) val vcu118Outer = _outer @@ -119,25 +118,12 @@ class VCU118FPGATestHarnessImp(_outer: VCU118FPGATestHarness) extends LazyRawMod val hReset = Wire(Reset()) hReset := _outer.dutClock.in.head._1.reset - val buildtopClock = _outer.dutClock.in.head._1.clock - val buildtopReset = WireInit(hReset) - val dutReset = hReset.asAsyncReset - val success = false.B + def implicitClock = _outer.dutClock.in.head._1.clock + def implicitReset = hReset + def success = { require(false, "Unused"); false.B } - childClock := buildtopClock - childReset := buildtopReset + childClock := implicitClock + childReset := implicitReset - // harness binders are non-lazy - _outer.topDesign match { case d: HasIOBinders => - ApplyHarnessBinders(this, d.lazySystem, d.portMap) - } - - // check the top-level reference clock is equal to the default - // non-exhaustive since you need all ChipTop clocks to equal the default - require(getRefClockFreq == p(DefaultClockFrequencyKey)) - - val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters())) - implicitHarnessClockBundle.clock := buildtopClock - implicitHarnessClockBundle.reset := buildtopReset - harnessClockInstantiator.instantiateHarnessClocks(implicitHarnessClockBundle) + instantiateChipTops() } diff --git a/fpga/src/main/scala/vcu118/bringup/HarnessBinders.scala b/fpga/src/main/scala/vcu118/bringup/HarnessBinders.scala index 7008092a..97d62ae2 100644 --- a/fpga/src/main/scala/vcu118/bringup/HarnessBinders.scala +++ b/fpga/src/main/scala/vcu118/bringup/HarnessBinders.scala @@ -13,11 +13,11 @@ import sifive.blocks.devices.gpio.{HasPeripheryGPIOModuleImp, GPIOPortIO} import testchipip.{HasPeripheryTSIHostWidget, TSIHostWidgetIO} -import chipyard.harness.{ComposeHarnessBinder, OverrideHarnessBinder, HasHarnessSignalReferences} +import chipyard.harness._ /*** UART ***/ class WithBringupUART extends ComposeHarnessBinder({ - (system: HasPeripheryUARTModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[UARTPortIO]) => { + (system: HasPeripheryUARTModuleImp, th: BaseModule with HasHarnessInstantiators, ports: Seq[UARTPortIO]) => { th match { case vcu118th: BringupVCU118FPGATestHarnessImp => { require(ports.size == 2) @@ -28,7 +28,7 @@ class WithBringupUART extends ComposeHarnessBinder({ /*** I2C ***/ class WithBringupI2C extends OverrideHarnessBinder({ - (system: HasPeripheryI2CModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[I2CPort]) => { + (system: HasPeripheryI2CModuleImp, th: BaseModule with HasHarnessInstantiators, ports: Seq[I2CPort]) => { th match { case vcu118th: BringupVCU118FPGATestHarnessImp => { require(ports.size == 1) @@ -39,7 +39,7 @@ class WithBringupI2C extends OverrideHarnessBinder({ /*** GPIO ***/ class WithBringupGPIO extends OverrideHarnessBinder({ - (system: HasPeripheryGPIOModuleImp, th: BaseModule with HasHarnessSignalReferences, ports: Seq[GPIOPortIO]) => { + (system: HasPeripheryGPIOModuleImp, th: BaseModule with HasHarnessInstantiators, ports: Seq[GPIOPortIO]) => { th match { case vcu118th: BringupVCU118FPGATestHarnessImp => { (vcu118th.bringupOuter.io_gpio_bb zip ports).map { case (bb_io, dut_io) => bb_io.bundle <> dut_io @@ -50,7 +50,7 @@ class WithBringupGPIO extends OverrideHarnessBinder({ /*** TSI Host Widget ***/ class WithBringupTSIHost extends OverrideHarnessBinder({ - (system: HasPeripheryTSIHostWidget, th: BaseModule with HasHarnessSignalReferences, ports: Seq[Data]) => { + (system: HasPeripheryTSIHostWidget, th: BaseModule with HasHarnessInstantiators, ports: Seq[Data]) => { th match { case vcu118th: BringupVCU118FPGATestHarnessImp => { require(ports.size == 2) // 1st goes to the TL mem, 2nd goes to the serial link diff --git a/fpga/src/main/scala/vcu118/bringup/TestHarness.scala b/fpga/src/main/scala/vcu118/bringup/TestHarness.scala index c311d84f..12398d8f 100644 --- a/fpga/src/main/scala/vcu118/bringup/TestHarness.scala +++ b/fpga/src/main/scala/vcu118/bringup/TestHarness.scala @@ -1,5 +1,4 @@ package chipyard.fpga.vcu118.bringup - import chisel3._ import freechips.rocketchip.diplomacy._ @@ -22,6 +21,7 @@ import testchipip.{HasPeripheryTSIHostWidget, PeripheryTSIHostKey, TSIHostWidget import chipyard.fpga.vcu118.{VCU118FPGATestHarness, VCU118FPGATestHarnessImp, DDR2VCU118ShellPlacer, SysClock2VCU118ShellPlacer} import chipyard.{ChipTop} +import chipyard.harness._ class BringupVCU118FPGATestHarness(override implicit val p: Parameters) extends VCU118FPGATestHarness { @@ -78,12 +78,10 @@ class BringupVCU118FPGATestHarness(override implicit val p: Parameters) extends dp(TSIHostOverlayKey).head.place(TSIHostDesignInput(dp(PeripheryTSIHostKey).head.offchipSerialIfWidth, io_tsi_serial_bb)) // connect 1 mem. channel to the FPGA DDR - val inTsiParams = topDesign match { case td: ChipTop => - td.lazySystem match { case lsys: HasPeripheryTSIHostWidget => - lsys.tsiMemTLNodes.head.edges.in(0) - } - } - val tsiDdrClient = TLClientNode(Seq(inTsiParams.master)) + val tsiDdrClient = TLClientNode(Seq(TLMasterPortParameters.v1(Seq(TLMasterParameters.v1( + name = "chip_ddr", + sourceId = IdRange(0, 64) + ))))) (ddr2Node := TLFragmenter(8,64,holdFirstDeny=true) := TLCacheCork() diff --git a/generators/chipyard/src/main/scala/clocking/ClockBinders.scala b/generators/chipyard/src/main/scala/clocking/ClockBinders.scala index 5a53051e..30a5ab10 100644 --- a/generators/chipyard/src/main/scala/clocking/ClockBinders.scala +++ b/generators/chipyard/src/main/scala/clocking/ClockBinders.scala @@ -111,6 +111,7 @@ class WithPassthroughClockGenerator extends OverrideLazyIOBinder({ val (bundle, edge) = clockGroupAggNode.out(0) val clock_ios = (bundle.member.data zip edge.sink.members).map { case (b, m) => + require(m.take.isDefined, s"Clock ${m.name.get} has no requested frequency") val freq = m.take.get.freqMHz val clock_io = IO(Input(new ClockWithFreq(freq))).suggestName(s"clock_${m.name.get}") b.clock := clock_io.clock diff --git a/generators/chipyard/src/main/scala/clocking/ClockGroupCombiner.scala b/generators/chipyard/src/main/scala/clocking/ClockGroupCombiner.scala index c8bad8c4..ff6c52e9 100644 --- a/generators/chipyard/src/main/scala/clocking/ClockGroupCombiner.scala +++ b/generators/chipyard/src/main/scala/clocking/ClockGroupCombiner.scala @@ -23,10 +23,9 @@ object ClockGroupCombiner { case object ClockGroupCombinerKey extends Field[Seq[(String, ClockSinkParameters => Boolean)]](Nil) // All clock groups with a name containing any substring in names will be combined into a single clock group -class WithClockGroupsCombinedByName(grouped_name: String, names: String*) extends Config((site, here, up) => { - case ClockGroupCombinerKey => { - val combiner: ClockSinkParameters => Boolean = { m => names.map(n => m.name.get.contains(n)).reduce(_||_) } - up(ClockGroupCombinerKey) ++ Seq((grouped_name, combiner)) +class WithClockGroupsCombinedByName(groups: (String, Seq[String])*) extends Config((site, here, up) => { + case ClockGroupCombinerKey => groups.map { case (grouped_name, matched_names) => + (grouped_name, (m: ClockSinkParameters) => matched_names.map(n => m.name.get.contains(n)).reduce(_||_)) } }) @@ -49,9 +48,14 @@ class ClockGroupCombiner(implicit p: Parameters, v: ValName) extends LazyModule val name = combiners(i)._1 i = i + 1 require(g.size >= 1) - require(g.forall(_.take.get == g.head.take.get)) - (grouped ++ Seq(ClockSinkParameters(take = g.head.take, name = Some(name))), r) + val takes = g.map(_.take).flatten + require(takes.distinct.size <= 1, + s"Clock group $name has non-homogeneous requested ClockParameters $takes") + require(takes.size > 0, + s"Clock group $name has no inheritable frequencies") + (grouped ++ Seq(ClockSinkParameters(take = takes.headOption, name = Some(name))), r) } + ClockGroupSinkParameters( name = u.name, members = grouped ++ rest diff --git a/generators/chipyard/src/main/scala/clocking/ClockGroupNamePrefixer.scala b/generators/chipyard/src/main/scala/clocking/ClockGroupNamePrefixer.scala index 39cb379b..08d54acf 100644 --- a/generators/chipyard/src/main/scala/clocking/ClockGroupNamePrefixer.scala +++ b/generators/chipyard/src/main/scala/clocking/ClockGroupNamePrefixer.scala @@ -60,23 +60,23 @@ object ClockGroupNamePrefixer { * The default if all functions return None. */ object ClockGroupFrequencySpecifier { - def apply( - assigners: Seq[(String) => Option[Double]], - defaultFreq: Double)( - implicit p: Parameters, valName: ValName): ClockGroupAdapterNode = { + def apply(assigners: Seq[(String) => Option[Double]])( + implicit p: Parameters, valName: ValName): ClockGroupAdapterNode = { - def lookupFrequencyForName(clock: ClockSinkParameters): ClockSinkParameters = { - require(clock.name.nonEmpty, "All clocks in clock group must have an assigned name") - val clockFreq = assigners.foldLeft(defaultFreq)( - (currentFreq, candidateFunc) => candidateFunc(clock.name.get).getOrElse(currentFreq)) - - clock.copy(take = clock.take match { - case Some(cp) => - println(s"Clock ${clock.name.get}: using diplomatically specified frequency of ${cp.freqMHz}.") - Some(cp) - case None => Some(ClockParameters(clockFreq)) - }) - } + def lookupFrequencyForName(clock: ClockSinkParameters): ClockSinkParameters = clock.copy(take = clock.take match { + case Some(cp) => + println(s"Clock ${clock.name.get}: using diplomatically specified frequency of ${cp.freqMHz}.") + Some(cp) + case None => { + val freqs = assigners.map { f => f(clock.name.get) }.flatten + if (freqs.size > 0) { + println(s"Clock ${clock.name.get}: using specified frequency of ${freqs.last}") + Some(ClockParameters(freqs.last)) + } else { + None + } + } + }) LazyModule(new ClockGroupParameterModifier(sinkFn = { s => s.copy(members = s.members.map(lookupFrequencyForName)) })).node } diff --git a/generators/chipyard/src/main/scala/clocking/HasChipyardPRCI.scala b/generators/chipyard/src/main/scala/clocking/HasChipyardPRCI.scala index 1522648a..6a2c82ca 100644 --- a/generators/chipyard/src/main/scala/clocking/HasChipyardPRCI.scala +++ b/generators/chipyard/src/main/scala/clocking/HasChipyardPRCI.scala @@ -15,7 +15,6 @@ import freechips.rocketchip.tile._ import freechips.rocketchip.prci._ import testchipip.{TLTileResetCtrl} -import chipyard.harness.{DefaultClockFrequencyKey} case class ChipyardPRCIControlParams( slaveWhere: TLBusWrapperLocation = CBUS, @@ -70,7 +69,7 @@ trait HasChipyardPRCI { this: BaseSubsystem with InstantiatesTiles => // 5. Add reset control registers to the tiles (if desired) // The final clock group here contains physically distinct clock domains, which some PRCI node in a // diplomatic IOBinder should drive - val frequencySpecifier = ClockGroupFrequencySpecifier(p(ClockFrequencyAssignersKey), p(DefaultClockFrequencyKey)) + val frequencySpecifier = ClockGroupFrequencySpecifier(p(ClockFrequencyAssignersKey)) val clockGroupCombiner = ClockGroupCombiner() val resetSynchronizer = ClockGroupResetSynchronizer() val tileClockGater = if (prciParams.enableTileClockGating) { prci_ctrl_domain { diff --git a/generators/chipyard/src/main/scala/config/AbstractConfig.scala b/generators/chipyard/src/main/scala/config/AbstractConfig.scala index 4b179fd0..065d49cb 100644 --- a/generators/chipyard/src/main/scala/config/AbstractConfig.scala +++ b/generators/chipyard/src/main/scala/config/AbstractConfig.scala @@ -44,6 +44,9 @@ class AbstractConfig extends Config( // By default, punch out IOs to the Harness new chipyard.clocking.WithPassthroughClockGenerator ++ + new chipyard.clocking.WithClockGroupsCombinedByName(("uncore", Seq("sbus", "mbus", "pbus", "fbus", "cbus", "implicit"))) ++ + new chipyard.config.WithPeripheryBusFrequency(500.0) ++ // Default 500 MHz pbus + new chipyard.config.WithMemoryBusFrequency(500.0) ++ // Default 500 MHz mbus new testchipip.WithCustomBootPin ++ // add a custom-boot-pin to support pin-driven boot address new testchipip.WithBootAddrReg ++ // add a boot-addr-reg for configurable boot address @@ -55,9 +58,6 @@ class AbstractConfig extends Config( new chipyard.config.WithL2TLBs(1024) ++ // use L2 TLBs new chipyard.config.WithNoSubsystemDrivenClocks ++ // drive the subsystem diplomatic clocks from ChipTop instead of using implicit clocks new chipyard.config.WithInheritBusFrequencyAssignments ++ // Unspecified clocks within a bus will receive the bus frequency if set - new chipyard.config.WithPeripheryBusFrequencyAsDefault ++ // Unspecified frequencies with match the pbus frequency (which is always set) - new chipyard.config.WithMemoryBusFrequency(500.0) ++ // Default 500 MHz mbus - new chipyard.config.WithPeripheryBusFrequency(500.0) ++ // Default 500 MHz pbus new freechips.rocketchip.subsystem.WithNMemoryChannels(2) ++ // Default 2 memory channels new freechips.rocketchip.subsystem.WithClockGateModel ++ // add default EICG_wrapper clock gate model new freechips.rocketchip.subsystem.WithJtagDTM ++ // set the debug module to expose a JTAG port diff --git a/generators/chipyard/src/main/scala/config/ChipConfigs.scala b/generators/chipyard/src/main/scala/config/ChipConfigs.scala index e51ac525..c2daf32c 100644 --- a/generators/chipyard/src/main/scala/config/ChipConfigs.scala +++ b/generators/chipyard/src/main/scala/config/ChipConfigs.scala @@ -32,7 +32,7 @@ class ChipLikeQuadRocketConfig extends Config( new chipyard.clocking.WithPLLSelectorDividerClockGenerator ++ // Use a PLL-based clock selector/divider generator structure // Create the uncore clock group - new chipyard.clocking.WithClockGroupsCombinedByName("uncore", "implicit", "sbus", "mbus", "cbus", "system_bus", "fbus", "pbus") ++ + new chipyard.clocking.WithClockGroupsCombinedByName(("uncore", Seq("implicit", "sbus", "mbus", "cbus", "system_bus", "fbus", "pbus"))) ++ new chipyard.config.AbstractConfig) diff --git a/generators/chipyard/src/main/scala/config/RocketConfigs.scala b/generators/chipyard/src/main/scala/config/RocketConfigs.scala index 7018b1f2..f1596143 100644 --- a/generators/chipyard/src/main/scala/config/RocketConfigs.scala +++ b/generators/chipyard/src/main/scala/config/RocketConfigs.scala @@ -25,7 +25,7 @@ class TinyRocketConfig extends Config( class UARTTSIRocketConfig extends Config( new chipyard.harness.WithUARTSerial ++ new chipyard.config.WithNoUART ++ - new chipyard.config.WithMemoryBusFrequency(10) ++ + new chipyard.config.WithMemoryBusFrequency(10) ++ new chipyard.config.WithPeripheryBusFrequency(10) ++ new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // single rocket-core new chipyard.config.AbstractConfig) @@ -90,11 +90,13 @@ class MulticlockRocketConfig extends Config( new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // Frequency specifications new chipyard.config.WithTileFrequency(1600.0) ++ // Matches the maximum frequency of U540 - new chipyard.config.WithSystemBusFrequency(800.0) ++ // Ditto + new chipyard.clocking.WithClockGroupsCombinedByName(("uncore" , Seq("sbus", "cbus", "implicit")), + ("periphery", Seq("pbus", "fbus"))) ++ + new chipyard.config.WithSystemBusFrequency(800.0) ++ // Matches the maximum frequency of U540 new chipyard.config.WithMemoryBusFrequency(1000.0) ++ // 2x the U540 freq (appropriate for a 128b Mbus) - new chipyard.config.WithPeripheryBusFrequency(100) ++ // Retains the default pbus frequency - new chipyard.config.WithSystemBusFrequencyAsDefault ++ // All unspecified clock frequencies, notably the implicit clock, will use the sbus freq (800 MHz) + new chipyard.config.WithPeripheryBusFrequency(100) ++ // Slow periphery bus // Crossing specifications + new chipyard.config.WithFbusToSbusCrossingType(AsynchronousCrossing()) ++ // Add Async crossing between FBUS and SBUS new chipyard.config.WithCbusToPbusCrossingType(AsynchronousCrossing()) ++ // Add Async crossing between PBUS and CBUS new chipyard.config.WithSbusToMbusCrossingType(AsynchronousCrossing()) ++ // Add Async crossings between backside of L2 and MBUS new testchipip.WithAsynchronousSerialSlaveCrossing ++ // Add Async crossing between serial and MBUS. Its master-side is tied to the FBUS @@ -102,7 +104,6 @@ class MulticlockRocketConfig extends Config( // DOC include start: MulticlockAXIOverSerialConfig class MulticlockAXIOverSerialConfig extends Config( - new chipyard.config.WithSystemBusFrequencyAsDefault ++ new chipyard.config.WithSystemBusFrequency(250) ++ new chipyard.config.WithPeripheryBusFrequency(250) ++ new chipyard.config.WithMemoryBusFrequency(250) ++ diff --git a/generators/chipyard/src/main/scala/config/TracegenConfigs.scala b/generators/chipyard/src/main/scala/config/TracegenConfigs.scala index 3c2b9a0c..3818f551 100644 --- a/generators/chipyard/src/main/scala/config/TracegenConfigs.scala +++ b/generators/chipyard/src/main/scala/config/TracegenConfigs.scala @@ -13,7 +13,6 @@ class AbstractTraceGenConfig extends Config( new chipyard.clocking.WithPassthroughClockGenerator ++ new chipyard.config.WithTracegenSystem ++ new chipyard.config.WithNoSubsystemDrivenClocks ++ - new chipyard.config.WithPeripheryBusFrequencyAsDefault ++ new chipyard.config.WithMemoryBusFrequency(100.0) ++ new chipyard.config.WithPeripheryBusFrequency(100.0) ++ new freechips.rocketchip.subsystem.WithCoherentBusTopology ++ diff --git a/generators/chipyard/src/main/scala/config/fragments/ClockingFragments.scala b/generators/chipyard/src/main/scala/config/fragments/ClockingFragments.scala index 82e1e16b..1f7bb943 100644 --- a/generators/chipyard/src/main/scala/config/fragments/ClockingFragments.scala +++ b/generators/chipyard/src/main/scala/config/fragments/ClockingFragments.scala @@ -13,7 +13,6 @@ import freechips.rocketchip.tilelink.{HasTLBusParams} import chipyard._ import chipyard.clocking._ -import chipyard.harness.{DefaultClockFrequencyKey} // The default RocketChip BaseSubsystem drives its diplomatic clock graph // with the implicit clocks of Subsystem. Don't do that, instead we extend @@ -37,14 +36,6 @@ class WithTileFrequency(fMHz: Double, hartId: Option[Int] = None) extends ClockN }, fMHz) -class WithPeripheryBusFrequencyAsDefault extends Config((site, here, up) => { - case DefaultClockFrequencyKey => (site(PeripheryBusKey).dtsFrequency.get.toDouble / (1000 * 1000)) -}) - -class WithSystemBusFrequencyAsDefault extends Config((site, here, up) => { - case DefaultClockFrequencyKey => (site(SystemBusKey).dtsFrequency.get.toDouble / (1000 * 1000)) -}) - class BusFrequencyAssignment[T <: HasTLBusParams](re: Regex, key: Field[T]) extends Config((site, here, up) => { case ClockFrequencyAssignersKey => up(ClockFrequencyAssignersKey, site) ++ Seq((cName: String) => site(key).dtsFrequency.flatMap { f => diff --git a/generators/chipyard/src/main/scala/example/FlatTestHarness.scala b/generators/chipyard/src/main/scala/example/FlatTestHarness.scala index 55b414cf..80a0088b 100644 --- a/generators/chipyard/src/main/scala/example/FlatTestHarness.scala +++ b/generators/chipyard/src/main/scala/example/FlatTestHarness.scala @@ -46,15 +46,12 @@ class FlatTestHarness(implicit val p: Parameters) extends Module { val memFreq = axiDomainParams.getMemFrequency(lazyDut.system) withClockAndReset(clock, reset) { - val memOverSerialTLClockBundle = Wire(new ClockBundle(ClockBundleParameters())) - memOverSerialTLClockBundle.clock := clock - memOverSerialTLClockBundle.reset := reset val serial_bits = dut.serial_tl_pad.bits dut.serial_tl_pad.clock := clock val harnessMultiClockAXIRAM = TSIHarness.connectMultiClockAXIRAM( lazyDut.system.serdesser.get, serial_bits, - memOverSerialTLClockBundle, + clock, reset) io.success := SimTSI.connect(Some(harnessMultiClockAXIRAM.module.io.tsi), clock, reset) diff --git a/generators/chipyard/src/main/scala/harness/HarnessBinders.scala b/generators/chipyard/src/main/scala/harness/HarnessBinders.scala index d78318f8..42738f87 100644 --- a/generators/chipyard/src/main/scala/harness/HarnessBinders.scala +++ b/generators/chipyard/src/main/scala/harness/HarnessBinders.scala @@ -30,12 +30,12 @@ import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvon import scala.reflect.{ClassTag} -case object HarnessBinders extends Field[Map[String, (Any, HasHarnessSignalReferences, Seq[Data]) => Unit]]( - Map[String, (Any, HasHarnessSignalReferences, Seq[Data]) => Unit]().withDefaultValue((t: Any, th: HasHarnessSignalReferences, d: Seq[Data]) => ()) +case object HarnessBinders extends Field[Map[String, (Any, HasHarnessInstantiators, Seq[Data]) => Unit]]( + Map[String, (Any, HasHarnessInstantiators, Seq[Data]) => Unit]().withDefaultValue((t: Any, th: HasHarnessInstantiators, d: Seq[Data]) => ()) ) object ApplyHarnessBinders { - def apply(th: HasHarnessSignalReferences, sys: LazyModule, portMap: Map[String, Seq[Data]])(implicit p: Parameters): Unit = { + def apply(th: HasHarnessInstantiators, sys: LazyModule, portMap: Map[String, Seq[Data]])(implicit p: Parameters): Unit = { val pm = portMap.withDefaultValue(Nil) p(HarnessBinders).foreach { case (s, f) => f(sys, th, pm(s)) @@ -45,9 +45,9 @@ object ApplyHarnessBinders { } // The ClassTags here are necessary to overcome issues arising from type erasure -class HarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](composer: ((T, S, Seq[U]) => Unit) => (T, S, Seq[U]) => Unit)(implicit systemTag: ClassTag[T], harnessTag: ClassTag[S], portTag: ClassTag[U]) extends Config((site, here, up) => { +class HarnessBinder[T, S <: HasHarnessInstantiators, U <: Data](composer: ((T, S, Seq[U]) => Unit) => (T, S, Seq[U]) => Unit)(implicit systemTag: ClassTag[T], harnessTag: ClassTag[S], portTag: ClassTag[U]) extends Config((site, here, up) => { case HarnessBinders => up(HarnessBinders, site) + (systemTag.runtimeClass.toString -> - ((t: Any, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + ((t: Any, th: HasHarnessInstantiators, ports: Seq[Data]) => { val pts = ports.collect({case p: U => p}) require (pts.length == ports.length, s"Port type mismatch between IOBinder and HarnessBinder: ${portTag}") val upfn = up(HarnessBinders, site)(systemTag.runtimeClass.toString) @@ -63,11 +63,11 @@ class HarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](composer: ((T ) }) -class OverrideHarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](fn: => (T, S, Seq[U]) => Unit) +class OverrideHarnessBinder[T, S <: HasHarnessInstantiators, U <: Data](fn: => (T, S, Seq[U]) => Unit) (implicit tag: ClassTag[T], thtag: ClassTag[S], ptag: ClassTag[U]) extends HarnessBinder[T, S, U]((upfn: (T, S, Seq[U]) => Unit) => fn) -class ComposeHarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](fn: => (T, S, Seq[U]) => Unit) +class ComposeHarnessBinder[T, S <: HasHarnessInstantiators, U <: Data](fn: => (T, S, Seq[U]) => Unit) (implicit tag: ClassTag[T], thtag: ClassTag[S], ptag: ClassTag[U]) extends HarnessBinder[T, S, U]((upfn: (T, S, Seq[U]) => Unit) => (t, th, p) => { upfn(t, th, p) @@ -76,72 +76,66 @@ class ComposeHarnessBinder[T, S <: HasHarnessSignalReferences, U <: Data](fn: => class WithGPIOTiedOff extends OverrideHarnessBinder({ - (system: HasPeripheryGPIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[Analog]) => { + (system: HasPeripheryGPIOModuleImp, th: HasHarnessInstantiators, ports: Seq[Analog]) => { ports.foreach { _ <> AnalogConst(0) } } }) // DOC include start: WithUARTAdapter class WithUARTAdapter extends OverrideHarnessBinder({ - (system: HasPeripheryUARTModuleImp, th: HasHarnessSignalReferences, ports: Seq[UARTPortIO]) => { + (system: HasPeripheryUARTModuleImp, th: HasHarnessInstantiators, ports: Seq[UARTPortIO]) => { UARTAdapter.connect(ports)(system.p) } }) // DOC include end: WithUARTAdapter class WithSimSPIFlashModel(rdOnly: Boolean = true) extends OverrideHarnessBinder({ - (system: HasPeripherySPIFlashModuleImp, th: HasHarnessSignalReferences, ports: Seq[SPIChipIO]) => { - SimSPIFlashModel.connect(ports, th.buildtopReset, rdOnly)(system.p) + (system: HasPeripherySPIFlashModuleImp, th: HasHarnessInstantiators, ports: Seq[SPIChipIO]) => { + SimSPIFlashModel.connect(ports, th.harnessBinderReset, rdOnly)(system.p) } }) class WithSimBlockDevice extends OverrideHarnessBinder({ - (system: CanHavePeripheryBlockDevice, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => { + (system: CanHavePeripheryBlockDevice, th: HasHarnessInstantiators, ports: Seq[ClockedIO[BlockDeviceIO]]) => { implicit val p: Parameters = GetSystemParameters(system) - ports.map { b => SimBlockDevice.connect(b.clock, th.buildtopReset.asBool, Some(b.bits)) } + ports.map { b => SimBlockDevice.connect(b.clock, th.harnessBinderReset.asBool, Some(b.bits)) } } }) class WithBlockDeviceModel extends OverrideHarnessBinder({ - (system: CanHavePeripheryBlockDevice, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => { + (system: CanHavePeripheryBlockDevice, th: HasHarnessInstantiators, ports: Seq[ClockedIO[BlockDeviceIO]]) => { implicit val p: Parameters = GetSystemParameters(system) - ports.map { b => withClockAndReset(b.clock, th.buildtopReset) { BlockDeviceModel.connect(Some(b.bits)) } } + ports.map { b => BlockDeviceModel.connect(Some(b.bits)) } } }) class WithLoopbackNIC extends OverrideHarnessBinder({ - (system: CanHavePeripheryIceNIC, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => { + (system: CanHavePeripheryIceNIC, th: HasHarnessInstantiators, ports: Seq[ClockedIO[NICIOvonly]]) => { implicit val p: Parameters = GetSystemParameters(system) - ports.map { n => - withClockAndReset(n.clock, th.buildtopReset) { - NicLoopback.connect(Some(n.bits), p(NICKey)) - } - } + ports.map { n => NicLoopback.connect(Some(n.bits), p(NICKey)) } } }) class WithSimNetwork extends OverrideHarnessBinder({ - (system: CanHavePeripheryIceNIC, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => { + (system: CanHavePeripheryIceNIC, th: BaseModule with HasHarnessInstantiators, ports: Seq[ClockedIO[NICIOvonly]]) => { implicit val p: Parameters = GetSystemParameters(system) - ports.map { n => SimNetwork.connect(Some(n.bits), n.clock, th.buildtopReset.asBool) } + ports.map { n => SimNetwork.connect(Some(n.bits), n.clock, th.harnessBinderReset.asBool) } } }) class WithSimAXIMem extends OverrideHarnessBinder({ - (system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => { + (system: CanHaveMasterAXI4MemPort, th: HasHarnessInstantiators, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => { val p: Parameters = chipyard.iobinders.GetSystemParameters(system) (ports zip system.memAXI4Node.edges.in).map { case (port, edge) => val mem = LazyModule(new SimAXIMem(edge, size=p(ExtMem).get.master.size)(p)) - withClockAndReset(port.clock, port.reset) { - Module(mem.module).suggestName("mem") - } + Module(mem.module).suggestName("mem") mem.io_axi4.head <> port.bits } } }) class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({ - (system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { + (system: CanHavePeripheryTLSerial, th: HasHarnessInstantiators, ports: Seq[ClockedIO[SerialIO]]) => { implicit val p = chipyard.iobinders.GetSystemParameters(system) p(SerialTLKey).map({ sVal => @@ -153,29 +147,27 @@ class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({ ports.map({ port => // DOC include start: HarnessClockInstantiatorEx - withClockAndReset(th.buildtopClock, th.buildtopReset) { - val memOverSerialTLClockBundle = th.harnessClockInstantiator.requestClockBundle("mem_over_serial_tl_clock", memFreq) - val serial_bits = port.bits - port.clock := th.buildtopClock - val harnessMultiClockAXIRAM = TSIHarness.connectMultiClockAXIRAM( - system.serdesser.get, - serial_bits, - memOverSerialTLClockBundle, - th.buildtopReset) -// DOC include end: HarnessClockInstantiatorEx - val success = SimTSI.connect(Some(harnessMultiClockAXIRAM.module.io.tsi), th.buildtopClock, th.buildtopReset.asBool) - when (success) { th.success := true.B } + val memOverSerialTLClock = th.harnessClockInstantiator.requestClockHz("mem_over_serial_tl_clock", memFreq) + val serial_bits = port.bits + port.clock := th.harnessBinderClock + val harnessMultiClockAXIRAM = TSIHarness.connectMultiClockAXIRAM( + system.serdesser.get, + serial_bits, + memOverSerialTLClock, + th.harnessBinderReset) + // DOC include end: HarnessClockInstantiatorEx + val success = SimTSI.connect(Some(harnessMultiClockAXIRAM.module.io.tsi), th.harnessBinderClock, th.harnessBinderReset.asBool) + when (success) { th.success := true.B } - // connect SimDRAM from the AXI port coming from the harness multi clock axi ram - (harnessMultiClockAXIRAM.mem_axi4 zip harnessMultiClockAXIRAM.memNode.edges.in).map { case (axi_port, edge) => - val memSize = sVal.memParams.size - val memBase = sVal.memParams.base - val lineSize = p(CacheBlockBytes) - val mem = Module(new SimDRAM(memSize, lineSize, BigInt(memFreq.toLong), memBase, edge.bundle)).suggestName("simdram") - mem.io.axi <> axi_port.bits - mem.io.clock := axi_port.clock - mem.io.reset := axi_port.reset - } + // connect SimDRAM from the AXI port coming from the harness multi clock axi ram + (harnessMultiClockAXIRAM.mem_axi4 zip harnessMultiClockAXIRAM.memNode.edges.in).map { case (axi_port, edge) => + val memSize = sVal.memParams.size + val memBase = sVal.memParams.base + val lineSize = p(CacheBlockBytes) + val mem = Module(new SimDRAM(memSize, lineSize, BigInt(memFreq.toLong), memBase, edge.bundle)).suggestName("simdram") + mem.io.axi <> axi_port.bits + mem.io.clock := axi_port.clock + mem.io.reset := axi_port.reset } }) }) @@ -183,7 +175,7 @@ class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({ }) class WithBlackBoxSimMem(additionalLatency: Int = 0) extends OverrideHarnessBinder({ - (system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => { + (system: CanHaveMasterAXI4MemPort, th: HasHarnessInstantiators, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => { val p: Parameters = chipyard.iobinders.GetSystemParameters(system) (ports zip system.memAXI4Node.edges.in).map { case (port, edge) => // TODO FIX: This currently makes each SimDRAM contain the entire memory space @@ -218,7 +210,7 @@ class WithBlackBoxSimMem(additionalLatency: Int = 0) extends OverrideHarnessBind }) class WithSimAXIMMIO extends OverrideHarnessBinder({ - (system: CanHaveMasterAXI4MMIOPort, th: HasHarnessSignalReferences, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => { + (system: CanHaveMasterAXI4MMIOPort, th: HasHarnessInstantiators, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => { val p: Parameters = chipyard.iobinders.GetSystemParameters(system) (ports zip system.mmioAXI4Node.edges.in).map { case (port, edge) => val mmio_mem = LazyModule(new SimAXIMem(edge, size = p(ExtBus).get.size)(p)) @@ -231,13 +223,13 @@ class WithSimAXIMMIO extends OverrideHarnessBinder({ }) class WithTieOffInterrupts extends OverrideHarnessBinder({ - (system: HasExtInterruptsModuleImp, th: HasHarnessSignalReferences, ports: Seq[UInt]) => { + (system: HasExtInterruptsModuleImp, th: HasHarnessInstantiators, ports: Seq[UInt]) => { ports.foreach { _ := 0.U } } }) class WithTieOffL2FBusAXI extends OverrideHarnessBinder({ - (system: CanHaveSlaveAXI4Port, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[AXI4Bundle]]) => { + (system: CanHaveSlaveAXI4Port, th: HasHarnessInstantiators, ports: Seq[ClockedIO[AXI4Bundle]]) => { ports.foreach({ p => p.bits := DontCare p.bits.aw.valid := false.B @@ -250,13 +242,13 @@ class WithTieOffL2FBusAXI extends OverrideHarnessBinder({ }) class WithSimDebug extends OverrideHarnessBinder({ - (system: HasPeripheryDebug, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + (system: HasPeripheryDebug, th: HasHarnessInstantiators, ports: Seq[Data]) => { implicit val p: Parameters = GetSystemParameters(system) ports.map { case d: ClockedDMIIO => val dtm_success = WireInit(false.B) when (dtm_success) { th.success := true.B } - val dtm = Module(new TestchipSimDTM).connect(th.buildtopClock, th.buildtopReset.asBool, d, dtm_success) + val dtm = Module(new TestchipSimDTM).connect(th.harnessBinderClock, th.harnessBinderReset.asBool, d, dtm_success) case j: JTAGChipIO => val dtm_success = WireInit(false.B) when (dtm_success) { th.success := true.B } @@ -267,13 +259,13 @@ class WithSimDebug extends OverrideHarnessBinder({ j.TMS := jtag_wire.TMS j.TDI := jtag_wire.TDI val jtag = Module(new SimJTAG(tickDelay=3)) - jtag.connect(jtag_wire, th.buildtopClock, th.buildtopReset.asBool, ~(th.buildtopReset.asBool), dtm_success) + jtag.connect(jtag_wire, th.harnessBinderClock, th.harnessBinderReset.asBool, ~(th.harnessBinderReset.asBool), dtm_success) } } }) class WithTiedOffDebug extends OverrideHarnessBinder({ - (system: HasPeripheryDebug, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + (system: HasPeripheryDebug, th: HasHarnessInstantiators, ports: Seq[Data]) => { ports.map { case j: JTAGChipIO => j.TCK := true.B.asClock @@ -300,7 +292,7 @@ class WithTiedOffDebug extends OverrideHarnessBinder({ class WithSerialTLTiedOff extends OverrideHarnessBinder({ - (system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { + (system: CanHavePeripheryTLSerial, th: HasHarnessInstantiators, ports: Seq[ClockedIO[SerialIO]]) => { implicit val p = chipyard.iobinders.GetSystemParameters(system) ports.map({ port => val bits = port.bits @@ -313,56 +305,52 @@ class WithSerialTLTiedOff extends OverrideHarnessBinder({ }) class WithSimTSIOverSerialTL extends OverrideHarnessBinder({ - (system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { + (system: CanHavePeripheryTLSerial, th: HasHarnessInstantiators, ports: Seq[ClockedIO[SerialIO]]) => { implicit val p = chipyard.iobinders.GetSystemParameters(system) ports.map({ port => val bits = port.bits - port.clock := th.buildtopClock - withClockAndReset(th.buildtopClock, th.buildtopReset) { - val ram = TSIHarness.connectRAM(system.serdesser.get, bits, th.buildtopReset) - val success = SimTSI.connect(Some(ram.module.io.tsi), th.buildtopClock, th.buildtopReset.asBool) - when (success) { th.success := true.B } - } + port.clock := th.harnessBinderClock + val ram = TSIHarness.connectRAM(system.serdesser.get, bits, th.harnessBinderReset) + val success = SimTSI.connect(Some(ram.module.io.tsi), th.harnessBinderClock, th.harnessBinderReset.asBool) + when (success) { th.success := true.B } }) } }) class WithUARTSerial extends OverrideHarnessBinder({ - (system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { + (system: CanHavePeripheryTLSerial, th: HasHarnessInstantiators, ports: Seq[ClockedIO[SerialIO]]) => { implicit val p = chipyard.iobinders.GetSystemParameters(system) ports.map({ port => val freq = p(PeripheryBusKey).dtsFrequency.get val bits = port.bits - port.clock := th.buildtopClock - withClockAndReset(th.buildtopClock, th.buildtopReset) { - val ram = TSIHarness.connectRAM(system.serdesser.get, bits, th.buildtopReset) - val uart_to_serial = Module(new UARTToSerial(freq, UARTParams(0))) - val serial_width_adapter = Module(new SerialWidthAdapter( - 8, TSI.WIDTH)) - ram.module.io.tsi.flipConnect(serial_width_adapter.io.wide) - UARTAdapter.connect(Seq(uart_to_serial.io.uart), uart_to_serial.div) - serial_width_adapter.io.narrow.flipConnect(uart_to_serial.io.serial) - th.success := false.B - } + port.clock := th.harnessBinderClock + val ram = TSIHarness.connectRAM(system.serdesser.get, bits, th.harnessBinderReset) + val uart_to_serial = Module(new UARTToSerial(freq, UARTParams(0))) + val serial_width_adapter = Module(new SerialWidthAdapter( + 8, TSI.WIDTH)) + ram.module.io.tsi.flipConnect(serial_width_adapter.io.wide) + UARTAdapter.connect(Seq(uart_to_serial.io.uart), uart_to_serial.div) + serial_width_adapter.io.narrow.flipConnect(uart_to_serial.io.serial) + th.success := false.B }) } }) class WithTraceGenSuccess extends OverrideHarnessBinder({ - (system: TraceGenSystemModuleImp, th: HasHarnessSignalReferences, ports: Seq[Bool]) => { + (system: TraceGenSystemModuleImp, th: HasHarnessInstantiators, ports: Seq[Bool]) => { ports.map { p => when (p) { th.success := true.B } } } }) class WithSimDromajoBridge extends ComposeHarnessBinder({ - (system: CanHaveTraceIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[TraceOutputTop]) => { + (system: CanHaveTraceIOModuleImp, th: HasHarnessInstantiators, ports: Seq[TraceOutputTop]) => { ports.map { p => p.traces.map(tileTrace => SimDromajoBridge(tileTrace)(system.p)) } } }) class WithCospike extends ComposeHarnessBinder({ - (system: CanHaveTraceIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[TraceOutputTop]) => { + (system: CanHaveTraceIOModuleImp, th: HasHarnessInstantiators, ports: Seq[TraceOutputTop]) => { implicit val p = chipyard.iobinders.GetSystemParameters(system) val chipyardSystem = system.asInstanceOf[ChipyardSystemModule[_]].outer.asInstanceOf[ChipyardSystem] val tiles = chipyardSystem.tiles @@ -381,7 +369,7 @@ class WithCospike extends ComposeHarnessBinder({ class WithCustomBootPinPlusArg extends OverrideHarnessBinder({ - (system: CanHavePeripheryCustomBootPin, th: HasHarnessSignalReferences, ports: Seq[Bool]) => { + (system: CanHavePeripheryCustomBootPin, th: HasHarnessInstantiators, ports: Seq[Bool]) => { val pin = PlusArg("custom_boot_pin", width=1) ports.foreach(_ := pin) } @@ -389,14 +377,14 @@ class WithCustomBootPinPlusArg extends OverrideHarnessBinder({ class WithClockAndResetFromHarness extends OverrideHarnessBinder({ - (system: HasChipyardPRCI, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + (system: HasChipyardPRCI, th: HasHarnessInstantiators, ports: Seq[Data]) => { implicit val p = GetSystemParameters(system) ports.map ({ case c: ClockWithFreq => { - val clock = th.harnessClockInstantiator.requestClockBundle(s"clock_${c.freqMHz}MHz", c.freqMHz * (1000 * 1000)) - c.clock := clock.clock + val clock = th.harnessClockInstantiator.requestClockMHz(s"clock_${c.freqMHz}MHz", c.freqMHz) + c.clock := clock } - case r: AsyncReset => r := th.buildtopReset.asAsyncReset + case r: AsyncReset => r := th.harnessBinderReset.asAsyncReset }) } }) diff --git a/generators/chipyard/src/main/scala/harness/HarnessClocks.scala b/generators/chipyard/src/main/scala/harness/HarnessClocks.scala index 4fb7ea9e..8d1c8756 100644 --- a/generators/chipyard/src/main/scala/harness/HarnessClocks.scala +++ b/generators/chipyard/src/main/scala/harness/HarnessClocks.scala @@ -17,24 +17,26 @@ import chipyard.clocking.{SimplePllConfiguration, ClockDividerN} // HarnessClockInstantiators are classes which generate clocks that drive // TestHarness simulation models and any Clock inputs to the ChipTop trait HarnessClockInstantiator { - val _clockMap: LinkedHashMap[String, (Double, ClockBundle)] = LinkedHashMap.empty + val clockMap: LinkedHashMap[String, (Double, Clock)] = LinkedHashMap.empty - // request a clock bundle at a particular frequency - def requestClockBundle(name: String, freqRequested: Double): ClockBundle = { - if (_clockMap.contains(name)) { - require(freqRequested == _clockMap(name)._1, - s"Request clock freq = $freqRequested != previously requested ${_clockMap(name)._2} for requested clock $name") - _clockMap(name)._2 + // request a clock at a particular frequency + def requestClockHz(name: String, freqHzRequested: Double): Clock = { + if (clockMap.contains(name)) { + require(freqHzRequested == clockMap(name)._1, + s"Request clock freq = $freqHzRequested != previously requested ${clockMap(name)._2} for requested clock $name") + clockMap(name)._2 } else { - val clockBundle = Wire(new ClockBundle(ClockBundleParameters())) - _clockMap(name) = (freqRequested, clockBundle) - clockBundle + val clock = Wire(Clock()) + clockMap(name) = (freqHzRequested, clock) + clock } } - + def requestClockMHz(name: String, freqMHzRequested: Double): Clock = { + requestClockHz(name, freqMHzRequested * (1000 * 1000)) + } // refClock is the clock generated by TestDriver that is // passed to the TestHarness as its implicit clock - def instantiateHarnessClocks(refClock: ClockBundle): Unit + def instantiateHarnessClocks(refClock: Clock): Unit } class ClockSourceAtFreqMHz(val freqMHz: Double) extends BlackBox(Map( @@ -63,19 +65,14 @@ class ClockSourceAtFreqMHz(val freqMHz: Double) extends BlackBox(Map( // This ClockInstantiator cannot be synthesized, run in Verilator, or run in FireSim // It is useful for VCS/Xcelium-driven RTL simulations class AbsoluteFreqHarnessClockInstantiator extends HarnessClockInstantiator { - def instantiateHarnessClocks(refClock: ClockBundle): Unit = { - val sinks = _clockMap.map({ case (name, (freq, bundle)) => - ClockSinkParameters(take=Some(ClockParameters(freqMHz=freq / (1000 * 1000))), name=Some(name)) - }).toSeq - + def instantiateHarnessClocks(refClock: Clock): Unit = { // connect wires to clock source - for (sinkParams <- sinks) { - val source = Module(new ClockSourceAtFreqMHz(sinkParams.take.get.freqMHz)) + for ((name, (freqHz, clock)) <- clockMap) { + val source = Module(new ClockSourceAtFreqMHz(freqHz / (1000 * 1000))) source.io.power := true.B source.io.gate := false.B - _clockMap(sinkParams.name.get)._2.clock := source.io.clk - _clockMap(sinkParams.name.get)._2.reset := refClock.reset + clock := source.io.clk } } } @@ -85,12 +82,11 @@ class WithAbsoluteFreqHarnessClockInstantiator extends Config((site, here, up) = }) class AllClocksFromHarnessClockInstantiator extends HarnessClockInstantiator { - def instantiateHarnessClocks(refClock: ClockBundle): Unit = { - val freqs = _clockMap.map(_._2._1) + def instantiateHarnessClocks(refClock: Clock): Unit = { + val freqs = clockMap.map(_._2._1) freqs.tail.foreach(t => require(t == freqs.head, s"Mismatching clocks $t != ${freqs.head}")) - for ((_, (_, bundle)) <- _clockMap) { - bundle.clock := refClock.clock - bundle.reset := refClock.reset + for ((name, (freq, clock)) <- clockMap) { + clock := refClock } } } diff --git a/generators/chipyard/src/main/scala/harness/HasHarnessInstantiators.scala b/generators/chipyard/src/main/scala/harness/HasHarnessInstantiators.scala new file mode 100644 index 00000000..05323fdd --- /dev/null +++ b/generators/chipyard/src/main/scala/harness/HasHarnessInstantiators.scala @@ -0,0 +1,95 @@ +package chipyard.harness + +import chisel3._ + +import scala.collection.mutable.{ArrayBuffer, LinkedHashMap} +import freechips.rocketchip.diplomacy.{LazyModule} +import org.chipsalliance.cde.config.{Field, Parameters, Config} +import freechips.rocketchip.util.{ResetCatchAndSync} +import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters, ClockSinkParameters, ClockParameters} +import freechips.rocketchip.stage.phases.TargetDirKey + +import chipyard.harness.{ApplyHarnessBinders, HarnessBinders} +import chipyard.iobinders.HasIOBinders +import chipyard.clocking.{SimplePllConfiguration, ClockDividerN} +import chipyard.{ChipTop} + +// ------------------------------- +// Chipyard Test Harness +// ------------------------------- + +case object MultiChipNChips extends Field[Int](0) // 0 means ignore MultiChipParams +case class MultiChipParameters(chipId: Int) extends Field[Parameters] +case object BuildTop extends Field[Parameters => LazyModule]((p: Parameters) => new ChipTop()(p)) +case object HarnessClockInstantiatorKey extends Field[() => HarnessClockInstantiator]() +case object HarnessBinderClockFrequencyKey extends Field[Double](100.0) // MHz +case object MultiChipIdx extends Field[Int](0) + +class WithMultiChip(id: Int, p: Parameters) extends Config((site, here, up) => { + case MultiChipParameters(`id`) => p + case MultiChipNChips => up(MultiChipNChips) max (id + 1) +}) + +class WithHomogeneousMultiChip(n: Int, p: Parameters, idStart: Int = 0) extends Config((site, here, up) => { + case MultiChipParameters(id) => if (id >= idStart && id < idStart + n) p else up(MultiChipParameters(id)) + case MultiChipNChips => up(MultiChipNChips) max (idStart + n) +}) + +class WithHarnessBinderClockFreqMHz(freqMHz: Double) extends Config((site, here, up) => { + case HarnessBinderClockFrequencyKey => freqMHz +}) + +// A TestHarness mixing this in will +// - use the HarnessClockInstantiator clock provide +trait HasHarnessInstantiators { + implicit val p: Parameters + // clock/reset of the chiptop reference clock (can be different than the implicit harness clock/reset) + private val harnessBinderClockFreq: Double = p(HarnessBinderClockFrequencyKey) + def getHarnessBinderClockFreqHz: Double = harnessBinderClockFreq * 1000000 + def getHarnessBinderClockFreqMHz: Double = harnessBinderClockFreq + + // buildtopClock takes the refClockFreq, and drives the harnessbinders + val harnessBinderClock = Wire(Clock()) + val harnessBinderReset = Wire(Reset()) + + // classes which inherit this trait should provide the below definitions + def implicitClock: Clock + def implicitReset: Reset + def success: Bool + + // This can be accessed to get new clocks from the harness + val harnessClockInstantiator = p(HarnessClockInstantiatorKey)() + + private val chipParameters = if (p(MultiChipNChips) == 0) { + Seq(p) + } else { + (0 until p(MultiChipNChips)).map { i => p(MultiChipParameters(i)).alterPartial { + case TargetDirKey => p(TargetDirKey) // hacky fix + case MultiChipIdx => i + }} + } + + // This shold be called last to build the ChipTops + def instantiateChipTops(): Seq[LazyModule] = { + val lazyDuts = chipParameters.zipWithIndex.map { case (q,i) => + LazyModule(q(BuildTop)(q)).suggestName(s"chiptop$i") + } + val duts = lazyDuts.map(l => Module(l.module)) + + withClockAndReset (harnessBinderClock, harnessBinderReset) { + lazyDuts.zipWithIndex.foreach { + case (d: HasIOBinders, i: Int) => ApplyHarnessBinders(this, d.lazySystem, d.portMap)(chipParameters(i)) + case _ => + } + } + + val harnessBinderClk = harnessClockInstantiator.requestClockMHz("harnessbinder_clock", getHarnessBinderClockFreqMHz) + println(s"Harness binder clock is $harnessBinderClockFreq") + harnessBinderClock := harnessBinderClk + harnessBinderReset := implicitReset + + harnessClockInstantiator.instantiateHarnessClocks(implicitClock) + + lazyDuts + } +} diff --git a/generators/chipyard/src/main/scala/harness/TestHarness.scala b/generators/chipyard/src/main/scala/harness/TestHarness.scala index cb8cfe47..c42cbf41 100644 --- a/generators/chipyard/src/main/scala/harness/TestHarness.scala +++ b/generators/chipyard/src/main/scala/harness/TestHarness.scala @@ -17,48 +17,15 @@ import chipyard.{ChipTop} // Chipyard Test Harness // ------------------------------- -case object BuildTop extends Field[Parameters => LazyModule]((p: Parameters) => new ChipTop()(p)) -case object DefaultClockFrequencyKey extends Field[Double](100.0) // MHz -case object HarnessClockInstantiatorKey extends Field[() => HarnessClockInstantiator]() - -trait HasHarnessSignalReferences { - implicit val p: Parameters - val harnessClockInstantiator = p(HarnessClockInstantiatorKey)() - // clock/reset of the chiptop reference clock (can be different than the implicit harness clock/reset) - var refClockFreq: Double = p(DefaultClockFrequencyKey) - def setRefClockFreq(freqMHz: Double) = { refClockFreq = freqMHz } - def getRefClockFreq: Double = refClockFreq - def buildtopClock: Clock - def buildtopReset: Reset - def success: Bool -} - -class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSignalReferences { +class TestHarness(implicit val p: Parameters) extends Module with HasHarnessInstantiators { val io = IO(new Bundle { val success = Output(Bool()) }) + val success = WireInit(false.B) + io.success := success - val buildtopClock = Wire(Clock()) - val buildtopReset = Wire(Reset()) + def implicitClock = clock + def implicitReset = reset - val lazyDut = LazyModule(p(BuildTop)(p)).suggestName("chiptop") - val dut = Module(lazyDut.module) - - io.success := false.B - - val success = io.success - - lazyDut match { case d: HasIOBinders => - ApplyHarnessBinders(this, d.lazySystem, d.portMap) - } - - val refClkBundle = harnessClockInstantiator.requestClockBundle("buildtop_reference_clock", getRefClockFreq * (1000 * 1000)) - - buildtopClock := refClkBundle.clock - buildtopReset := WireInit(refClkBundle.reset) - - val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters())) - implicitHarnessClockBundle.clock := clock - implicitHarnessClockBundle.reset := reset - harnessClockInstantiator.instantiateHarnessClocks(implicitHarnessClockBundle) + instantiateChipTops() } diff --git a/generators/firechip/src/main/scala/BridgeBinders.scala b/generators/firechip/src/main/scala/BridgeBinders.scala index 579c2d50..e3f9e2d6 100644 --- a/generators/firechip/src/main/scala/BridgeBinders.scala +++ b/generators/firechip/src/main/scala/BridgeBinders.scala @@ -4,6 +4,7 @@ package firesim.firesim import chisel3._ import chisel3.experimental.annotate +import chisel3.experimental.{DataMirror, Direction} import chisel3.util.experimental.BoringUtils import org.chipsalliance.cde.config.{Field, Config, Parameters} @@ -30,11 +31,12 @@ import cva6.CVA6Tile import boom.common.{BoomTile} import barstools.iocell.chisel._ import chipyard.iobinders.{IOBinders, OverrideIOBinder, ComposeIOBinder, GetSystemParameters, IOCellKey} +import chipyard._ import chipyard.harness._ object MainMemoryConsts { val regionNamePrefix = "MainMemory" - def globalName = s"${regionNamePrefix}_${NodeIdx()}" + def globalName()(implicit p: Parameters) = s"${regionNamePrefix}_${p(MultiChipIdx)}" } trait Unsupported { @@ -72,11 +74,9 @@ class WithTSIBridgeAndHarnessRAMOverSerialTL extends OverrideHarnessBinder({ ports.map { port => implicit val p = GetSystemParameters(system) val bits = port.bits - port.clock := th.buildtopClock - val ram = withClockAndReset(th.buildtopClock, th.buildtopReset) { - TSIHarness.connectRAM(system.serdesser.get, bits, th.buildtopReset) - } - TSIBridge(th.buildtopClock, ram.module.io.tsi, p(ExtMem).map(_ => MainMemoryConsts.globalName), th.buildtopReset.asBool) + port.clock := th.harnessBinderClock + val ram = TSIHarness.connectRAM(system.serdesser.get, bits, th.harnessBinderReset) + TSIBridge(th.harnessBinderClock, ram.module.io.tsi, p(ExtMem).map(_ => MainMemoryConsts.globalName), th.harnessBinderReset.asBool) } Nil } @@ -97,13 +97,13 @@ class WithUARTBridge extends OverrideHarnessBinder({ val pbusClockNode = system.outer.asInstanceOf[HasTileLinkLocations].locateTLBusWrapper(PBUS).fixedClockNode val pbusClock = pbusClockNode.in.head._1.clock BoringUtils.bore(pbusClock, Seq(uartSyncClock)) - ports.map { p => UARTBridge(uartSyncClock, p, th.buildtopReset.asBool)(system.p) }; Nil + ports.map { p => UARTBridge(uartSyncClock, p, th.harnessBinderReset.asBool)(system.p) }; Nil }) class WithBlockDeviceBridge extends OverrideHarnessBinder({ (system: CanHavePeripheryBlockDevice, th: FireSim, ports: Seq[ClockedIO[BlockDeviceIO]]) => { implicit val p: Parameters = GetSystemParameters(system) - ports.map { b => BlockDevBridge(b.clock, b.bits, th.buildtopReset.asBool) } + ports.map { b => BlockDevBridge(b.clock, b.bits, th.harnessBinderReset.asBool) } Nil } }) @@ -120,21 +120,16 @@ class WithAXIOverSerialTLCombinedBridges extends OverrideHarnessBinder({ val memFreq = axiDomainParams.getMemFrequency(system.asInstanceOf[HasTileLinkLocations]) ports.map({ port => - val axiClock = p(ClockBridgeInstantiatorKey).requestClock("mem_over_serial_tl_clock", memFreq) - val axiClockBundle = Wire(new ClockBundle(ClockBundleParameters())) - axiClockBundle.clock := axiClock - axiClockBundle.reset := ResetCatchAndSync(axiClock, th.buildtopReset.asBool) + val axiClock = th.harnessClockInstantiator.requestClockHz("mem_over_serial_tl_clock", memFreq) val serial_bits = port.bits - port.clock := th.buildtopClock - val harnessMultiClockAXIRAM = withClockAndReset(th.buildtopClock, th.buildtopReset) { - TSIHarness.connectMultiClockAXIRAM( - system.serdesser.get, - serial_bits, - axiClockBundle, - th.buildtopReset) - } - TSIBridge(th.buildtopClock, harnessMultiClockAXIRAM.module.io.tsi, Some(MainMemoryConsts.globalName), th.buildtopReset.asBool) + port.clock := th.harnessBinderClock + val harnessMultiClockAXIRAM = TSIHarness.connectMultiClockAXIRAM( + system.serdesser.get, + serial_bits, + axiClock, + ResetCatchAndSync(axiClock, th.harnessBinderReset.asBool)) + TSIBridge(th.harnessBinderClock, harnessMultiClockAXIRAM.module.io.tsi, Some(MainMemoryConsts.globalName), th.harnessBinderReset.asBool) // connect SimAxiMem (harnessMultiClockAXIRAM.mem_axi4 zip harnessMultiClockAXIRAM.memNode.edges.in).map { case (axi4, edge) => @@ -192,7 +187,7 @@ class WithDromajoBridge extends ComposeHarnessBinder({ class WithTraceGenBridge extends OverrideHarnessBinder({ (system: TraceGenSystemModuleImp, th: FireSim, ports: Seq[Bool]) => - ports.map { p => GroundTestBridge(th.buildtopClock, p)(system.p) }; Nil + ports.map { p => GroundTestBridge(th.harnessBinderClock, p)(system.p) }; Nil }) class WithFireSimMultiCycleRegfile extends ComposeIOBinder({ diff --git a/generators/firechip/src/main/scala/FireSim.scala b/generators/firechip/src/main/scala/FireSim.scala index a62059e3..d43b9a59 100644 --- a/generators/firechip/src/main/scala/FireSim.scala +++ b/generators/firechip/src/main/scala/FireSim.scala @@ -20,258 +20,67 @@ import chipyard.harness._ import chipyard.iobinders._ import chipyard.clocking._ -// Determines the number of times to instantiate the DUT in the harness. -// Subsumes legacy supernode support -case object NumNodes extends Field[Int](1) - -class WithNumNodes(n: Int) extends Config((pname, site, here) => { - case NumNodes => n -}) - -// Hacky: Set before each node is generated. Ideally we'd give IO binders -// accesses to the the Harness's parameters instance. We could then alter that. -object NodeIdx { - private var idx = 0 - def increment(): Unit = {idx = idx + 1 } - def apply(): Int = idx -} - - -/** - * Specifies DUT clocks for the rational clock bridge - * - * @param allClocks Seq. of RationalClocks that want a clock - * - * @param baseClockName Name of domain that the allClocks is rational to - * - * @param baseFreqRequested Freq. for the reference domain in Hz - */ -case class BuildTopClockParameters(allClocks: Seq[RationalClock], baseClockName: String, baseFreqRequested: Double) - /** * Under FireSim's current multiclock implementation there can be only a * single clock bridge. This requires, therefore, that it be instantiated in * the harness and reused across all supernode instances. This class attempts to * memoize its instantiation such that it can be referenced from within a ClockScheme function. */ -class ClockBridgeInstantiator { - private val _harnessClockMap: LinkedHashMap[String, (Double, Clock)] = LinkedHashMap.empty +class FireSimClockBridgeInstantiator extends HarnessClockInstantiator { + // connect all clock wires specified to the RationalClockBridge + def instantiateHarnessClocks(refClock: Clock): Unit = { + val sinks = clockMap.map({ case (name, (freq, bundle)) => + ClockSinkParameters(take=Some(ClockParameters(freqMHz=freq / (1000 * 1000))), name=Some(name)) + }).toSeq - // Assumes that the supernode implementation results in duplicated clocks - // (i.e. only 1 set of clocks is generated for all BuildTop designs) - private var _buildTopClockParams: Option[BuildTopClockParameters] = None - private val _buildTopClockMap: LinkedHashMap[String, (RationalClock, Clock)] = LinkedHashMap.empty - private var _buildTopClockRecord: Option[RecordMap[Clock]] = None + val pllConfig = new SimplePllConfiguration("firesimRationalClockBridge", sinks) + pllConfig.emitSummaries() - /** - * Request a clock at a particular frequency - * - * @param name An identifier for the associated clock domain - * - * @param freqRequested Freq. for the domain in Hz - */ - def requestClock(name: String, freqRequested: Double): Clock = { - val clkWire = Wire(new Clock) - _harnessClockMap(name) = (freqRequested, clkWire) - clkWire - } - - /** - * Get a RecordMap of clocks for a set of input RationalClocks. Used to drive - * the design elaborated by buildtop - * - * @param clockMapParameters Defines the set of required clocks - */ - def requestClockRecordMap(clockMapParameters: BuildTopClockParameters): RecordMap[Clock] = { - if (_buildTopClockParams.isDefined) { - require(_buildTopClockParams.get == clockMapParameters, "Must request same set of clocks on repeated invocations.") - } else { - val clockRecord = Wire(RecordMap(clockMapParameters.allClocks.map { c => (c.name, Clock()) }:_*)) - // Build up the mutable structures describing the clocks for the dut - _buildTopClockParams = Some(clockMapParameters) - _buildTopClockRecord = Some(clockRecord) - - for (clock <- clockMapParameters.allClocks) { - val clockWire = Wire(new Clock) - _buildTopClockMap(clock.name) = (clock, clockWire) - clockRecord(clock.name).get := clockWire + var instantiatedClocks = LinkedHashMap[Int, (Clock, Seq[String])]() + // connect wires to clock source + for ((name, (freq, clock)) <- clockMap) { + val freqMHz = (freq / (1000 * 1000)).toInt + if (!instantiatedClocks.contains(freqMHz)) { + val clock = Wire(Clock()) + instantiatedClocks(freqMHz) = (clock, Seq(name)) + } else { + instantiatedClocks(freqMHz) = (instantiatedClocks(freqMHz)._1, instantiatedClocks(freqMHz)._2 :+ name) } + clock := instantiatedClocks(freqMHz)._1 } - _buildTopClockRecord.get - } - - /** - * Connect all clocks requested to ClockBridge - */ - def instantiateFireSimClockBridge: Unit = { - require(_buildTopClockParams.isDefined, "Must have rational clocks to assign to") - val BuildTopClockParameters(allClocks, refRatClockName, refRatClockFreq) = _buildTopClockParams.get - require(_buildTopClockMap.exists(_._1 == refRatClockName), - s"Provided base-clock name for rational clocks, ${refRatClockName}, doesn't match a name within specified rational clocks." + - "Available clocks:\n " + _buildTopClockMap.map(_._1).mkString("\n ")) - - // Simplify the RationalClocks ratio's - val refRatClock = _buildTopClockMap.find(_._1 == refRatClockName).get._2._1 - val simpleRatClocks = _buildTopClockMap.map { t => - val ratClock = t._2._1 - ratClock.copy( - multiplier = ratClock.multiplier * refRatClock.divisor, - divisor = ratClock.divisor * refRatClock.multiplier).simplify - } - - // Determine all the clock dividers (harness + rational clocks) - // Note: Requires that the BuildTop reference frequency is requested with proper freq. - val refRatSinkParams = ClockSinkParameters(take=Some(ClockParameters(freqMHz=refRatClockFreq / (1000 * 1000))),name=Some(refRatClockName)) - val harSinkParams = _harnessClockMap.map { case (name, (freq, bundle)) => - ClockSinkParameters(take=Some(ClockParameters(freqMHz=freq / (1000 * 1000))),name=Some(name)) + val ratClocks = instantiatedClocks.map { case (freqMHz, (clock, names)) => + (RationalClock(names.mkString(","), 1, pllConfig.referenceFreqMHz.toInt / freqMHz), clock) }.toSeq - val allSinkParams = harSinkParams :+ refRatSinkParams - - // Use PLL config to determine overall div's - val pllConfig = new SimplePllConfiguration("firesimOverallClockBridge", allSinkParams) - pllConfig.emitSummaries - - // Adjust all BuildTop RationalClocks with the div determined by the PLL - val refRatDiv = pllConfig.sinkDividerMap(refRatSinkParams) - val adjRefRatClocks = simpleRatClocks.map { clock => - clock.copy(divisor = clock.divisor * refRatDiv).simplify - } - - // Convert harness clocks to RationalClocks - val harRatClocks = harSinkParams.map { case ClockSinkParameters(_, _, _, _, clkParamsOpt, nameOpt) => - RationalClock(nameOpt.get, 1, pllConfig.referenceFreqMHz.toInt / clkParamsOpt.get.freqMHz.toInt) - } - - val allAdjRatClks = adjRefRatClocks ++ harRatClocks - - // Removes clocks that have the same frequency before instantiating the - // clock bridge to avoid unnecessary BUFGCE use. - val allDistinctRatClocks = allAdjRatClks.foldLeft(Seq(RationalClock(pllConfig.referenceSinkParams.name.get, 1, 1))) { - case (list, candidate) => if (list.exists { clock => clock.equalFrequency(candidate) }) list else list :+ candidate - } - - val clockBridge = Module(new RationalClockBridge(allDistinctRatClocks)) - val cbVecTuples = allDistinctRatClocks.zip(clockBridge.io.clocks) - - // Connect all clocks (harness + BuildTop clocks) - for (clock <- allAdjRatClks) { - val (_, cbClockField) = cbVecTuples.find(_._1.equalFrequency(clock)).get - _buildTopClockMap.get(clock.name).map { case (_, clk) => clk := cbClockField } - _harnessClockMap.get(clock.name).map { case (_, clk) => clk := cbClockField } + val clockBridge = Module(new RationalClockBridge(ratClocks.map(_._1))) + (clockBridge.io.clocks zip ratClocks).foreach { case (clk, rat) => + rat._2 := clk } } } -case object ClockBridgeInstantiatorKey extends Field[ClockBridgeInstantiator](new ClockBridgeInstantiator) -case object FireSimBaseClockNameKey extends Field[String]("implicit_clock") - -class ClocksWithSinkParams(val params: Seq[ClockSinkParameters]) extends Bundle { - val clocks = Vec(params.size, Clock()) -} - -class WithFireSimSimpleClocks extends OverrideLazyIOBinder({ - (system: HasChipyardPRCI) => { - implicit val p = GetSystemParameters(system) - // Figure out what provides this in the chipyard scheme - implicit val valName = ValName("FireSimClocking") - - val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters(name = Some("implicit_clock")))) - system.connectImplicitClockSinkNode(implicitClockSinkNode) - InModuleBody { - val implicit_clock = implicitClockSinkNode.in.head._1.clock - val implicit_reset = implicitClockSinkNode.in.head._1.reset - system.asInstanceOf[BaseSubsystem].module match { case l: LazyModuleImp => { - l.clock := implicit_clock - l.reset := implicit_reset - }} - } - - val inputClockSource = ClockGroupSourceNode(Seq(ClockGroupSourceParameters())) - system.allClockGroupsNode := inputClockSource - - InModuleBody { - val (clockGroupBundle, clockGroupEdge) = inputClockSource.out.head - val reset_io = IO(Input(AsyncReset())).suggestName("async_reset") - - val input_clocks = IO(Input(new ClocksWithSinkParams(clockGroupEdge.sink.members))) - .suggestName("clocks") - - (clockGroupBundle.member.data zip input_clocks.clocks).foreach { case (clockBundle, inputClock) => - clockBundle.clock := inputClock - clockBundle.reset := reset_io - } - - (Seq(reset_io, input_clocks), Nil) - } - } -}) - -class WithFireSimHarnessClockBinder extends OverrideHarnessBinder({ - (system: HasChipyardPRCI, th: FireSim, ports: Seq[Data]) => { - implicit val p = th.p - ports.map ({ - case c: ClocksWithSinkParams => { - val pllConfig = new SimplePllConfiguration("firesimBuildTopClockGenerator", c.params) - pllConfig.emitSummaries - th.setRefClockFreq(pllConfig.referenceFreqMHz) - val rationalClockSpecs = for ((sinkP, division) <- pllConfig.sinkDividerMap) yield { - RationalClock(sinkP.name.get, 1, division) - } - val input_clocks: RecordMap[Clock] = p(ClockBridgeInstantiatorKey).requestClockRecordMap( - BuildTopClockParameters( - rationalClockSpecs.toSeq, - p(FireSimBaseClockNameKey), - pllConfig.referenceFreqMHz * (1000 * 1000))) - (c.clocks zip c.params) map ({ case (clock, param) => - clock := input_clocks(param.name.get).get - }) - } - case r: Reset => r := th.buildtopReset.asAsyncReset - }) - } -}) - -class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSignalReferences { +class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessInstantiators { + require(harnessClockInstantiator.isInstanceOf[FireSimClockBridgeInstantiator]) freechips.rocketchip.util.property.cover.setPropLib(new midas.passes.FireSimPropertyLibrary()) - val buildtopClock = Wire(Clock()) - val buildtopReset = WireInit(false.B) // The peek-poke bridge must still be instantiated even though it's // functionally unused. This will be removed in a future PR. val dummy = WireInit(false.B) - val peekPokeBridge = PeekPokeBridge(buildtopClock, dummy) + val peekPokeBridge = PeekPokeBridge(harnessBinderClock, dummy) val resetBridge = Module(new ResetPulseBridge(ResetPulseBridgeParameters())) // In effect, the bridge counts the length of the reset in terms of this clock. - resetBridge.io.clock := buildtopClock - buildtopReset := resetBridge.io.reset - // Ensures FireSim-synthesized assertions and instrumentation is disabled - // while buildtopReset is asserted. This ensures assertions do not fire at - // time zero in the event their local reset is delayed (typically because it - // has been pipelined) - midas.targetutils.GlobalResetCondition(buildtopReset) + resetBridge.io.clock := harnessBinderClock - def dutReset = { require(false, "dutReset should not be used in Firesim"); false.B } + def implicitClock = false.B.asClock // unused + def implicitReset = resetBridge.io.reset def success = { require(false, "success should not be used in Firesim"); false.B } - // Instantiate multiple instances of the DUT to implement supernode - for (i <- 0 until p(NumNodes)) { - // It's not a RC bump without some hacks... - // Copy the AsyncClockGroupsKey to generate a fresh node on each - // instantiation of the dut, otherwise the initial instance will be - // reused across each node - import freechips.rocketchip.subsystem.AsyncClockGroupsKey - val lazyModule = LazyModule(p(BuildTop)(p)) - val module = Module(lazyModule.module) + instantiateChipTops() - lazyModule match { case d: HasIOBinders => - ApplyHarnessBinders(this, d.lazySystem, d.portMap) - } - NodeIdx.increment() - } - - buildtopClock := p(ClockBridgeInstantiatorKey).requestClock("buildtop_reference_clock", getRefClockFreq * (1000 * 1000)) - - p(ClockBridgeInstantiatorKey).instantiateFireSimClockBridge + // Ensures FireSim-synthesized assertions and instrumentation is disabled + // while resetBridge.io.reset is asserted. This ensures assertions do not fire at + // time zero in the event their local reset is delayed (typically because it + // has been pipelined) + midas.targetutils.GlobalResetCondition(resetBridge.io.reset) } diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index 621a152c..b450360a 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -18,6 +18,7 @@ import sifive.blocks.devices.uart.{PeripheryUARTKey, UARTParams} import scala.math.{min, max} import chipyard.clocking.{ChipyardPRCIControlKey} +import chipyard.harness.{HarnessClockInstantiatorKey} import icenet._ import firesim.bridges._ @@ -43,6 +44,11 @@ class WithoutClockGating extends Config((site, here, up) => { case ChipyardPRCIControlKey => up(ChipyardPRCIControlKey, site).copy(enableTileClockGating = false) }) +// Use the firesim clock bridge instantiator. this is required +class WithFireSimHarnessClockBridgeInstantiator extends Config((site, here, up) => { + case HarnessClockInstantiatorKey => () => new FireSimClockBridgeInstantiator +}) + // Testing configurations // This enables printfs used in testing class WithScalaTestFeatures extends Config((site, here, up) => { @@ -63,9 +69,10 @@ class WithNVDLASmall extends nvidia.blocks.dla.WithNVDLA("small") // Minimal set of FireSim-related design tweaks - notably discludes FASED, TraceIO, and the BlockDevice class WithMinimalFireSimDesignTweaks extends Config( - // Required*: Uses FireSim ClockBridge and PeekPokeBridge to drive the system with a single clock/reset - new WithFireSimHarnessClockBinder ++ - new WithFireSimSimpleClocks ++ + // Required*: Punch all clocks to FireSim's harness clock instantiator + new WithFireSimHarnessClockBridgeInstantiator ++ + new chipyard.harness.WithClockAndResetFromHarness ++ + new chipyard.clocking.WithPassthroughClockGenerator ++ // Required*: When using FireSim-as-top to provide a correct path to the target bootrom source new WithBootROM ++ // Required: Existing FAME-1 transform cannot handle black-box clock gates @@ -116,19 +123,11 @@ class WithFireSimConfigTweaks extends Config( // Using some other frequency will require runnings the FASED runtime configuration generator // to generate faithful DDR3 timing values. new chipyard.config.WithSystemBusFrequency(1000.0) ++ - new chipyard.config.WithSystemBusFrequencyAsDefault ++ // All unspecified clock frequencies, notably the implicit clock, will use the sbus freq (1000 MHz) - // Explicitly set PBUS + MBUS to 1000 MHz, since they will be driven to 100 MHz by default because of assignments in the Chisel new chipyard.config.WithPeripheryBusFrequency(1000.0) ++ new chipyard.config.WithMemoryBusFrequency(1000.0) ++ new WithFireSimDesignTweaks ) -// Tweak more representative of testchip configs -class WithFireSimTestChipConfigTweaks extends Config( - new chipyard.config.WithTestChipBusFreqs ++ - new WithFireSimDesignTweaks -) - // Tweaks to use minimal design tweaks // Need to use initramfs to use linux (no block device) class WithMinimalFireSimHighPerfConfigTweaks extends Config( @@ -267,9 +266,10 @@ class FireSimLeanGemminiPrintfRocketConfig extends Config( // Supernode Configurations, base off chipyard's RocketConfig //********************************************************************************** class SupernodeFireSimRocketConfig extends Config( - new WithNumNodes(4) ++ - new freechips.rocketchip.subsystem.WithExtMemSize((1 << 30) * 8L) ++ // 8 GB - new FireSimRocketConfig) + new WithFireSimHarnessClockBridgeInstantiator ++ + new chipyard.harness.WithHomogeneousMultiChip(n=4, new Config( + new freechips.rocketchip.subsystem.WithExtMemSize((1 << 30) * 8L) ++ // 8GB DRAM per node + new FireSimRocketConfig))) //********************************************************************************** //* CVA6 Configurations diff --git a/generators/testchipip b/generators/testchipip index ebf61569..e95e8074 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit ebf61569c5a65ff46ac3ee77fcc3a8404441ab9d +Subproject commit e95e807464f232d33606e0458856f657fdf7e485