From 79eccceadd8478d9ea38236468b559e6248e3626 Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Sat, 27 Feb 2021 22:55:25 +0000 Subject: [PATCH 01/30] Small comments to Clocks.scala --- generators/chipyard/src/main/scala/Clocks.scala | 3 +++ 1 file changed, 3 insertions(+) diff --git a/generators/chipyard/src/main/scala/Clocks.scala b/generators/chipyard/src/main/scala/Clocks.scala index 9ca6a801..0ba31abb 100644 --- a/generators/chipyard/src/main/scala/Clocks.scala +++ b/generators/chipyard/src/main/scala/Clocks.scala @@ -75,15 +75,18 @@ object ClockingSchemeGenerators { } val aggregator = LazyModule(new ClockGroupAggregator("allClocks")).node + // provides the implicit clock to the system (chiptop.implicitClockSinkNode := ClockGroup() := aggregator) + // provides the system clock (ex. the bus clocks) (systemAsyncClockGroup :*= resetSetter :*= ClockGroupNamePrefixer() :*= aggregator) val referenceClockSource = ClockSourceNode(Seq(ClockSourceParameters())) + // provides all the divided clocks (from the top-level clock) (aggregator := ClockGroupFrequencySpecifier(p(ClockFrequencyAssignersKey), p(DefaultClockFrequencyKey)) := ClockGroupResetSynchronizer() From a3e22c78de66131c07e528db7aef2614a803f492 Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Sun, 28 Feb 2021 22:27:18 +0000 Subject: [PATCH 02/30] First attempt at getting Offchip AXI port --- .../src/main/scala/ConfigFragments.scala | 18 +++++- .../src/main/scala/HarnessBinders.scala | 23 ++++++++ .../chipyard/src/main/scala/IOBinders.scala | 30 +++++++++- .../main/scala/config/AbstractConfig.scala | 43 +++++++++++++++ .../src/main/scala/config/RocketConfigs.scala | 52 +++++++++++++++++- .../src/main/scala/BridgeBinders.scala | 28 ++++++++++ .../src/main/scala/TargetConfigs.scala | 55 +++++++++++++++++++ generators/testchipip | 2 +- 8 files changed, 247 insertions(+), 4 deletions(-) diff --git a/generators/chipyard/src/main/scala/ConfigFragments.scala b/generators/chipyard/src/main/scala/ConfigFragments.scala index 667e5148..f2d77a5f 100644 --- a/generators/chipyard/src/main/scala/ConfigFragments.scala +++ b/generators/chipyard/src/main/scala/ConfigFragments.scala @@ -193,7 +193,23 @@ class WithTLBackingMemory extends Config((site, here, up) => { case ExtTLMem => up(ExtMem, site) // enable TL backing memory }) -class WithTileFrequency(fMHz: Double) extends ClockNameContainsAssignment("core", fMHz) +class WithOffchipBackingMemory extends Config((site, here, up) => { + case ExtMem => None + case SerialTLKey => Some(SerialTLParams( + memParams = { + val memPortParams = up(ExtMem, site).get + + require(memPortParams.nMemoryChannels == 1) + + memPortParams.master + }, + width = 4, + isMemoryDevice = true + )) +}) + +class WithTileFrequency(fMHz: Double) extends ClockNameContainsAssignment("tile", fMHz) +class WithSpecificTileFrequency(hartId: Int, fMHz: Double) extends chipyard.ClockNameContainsAssignment(s"tile_$hartId", fMHz) class WithPeripheryBusFrequencyAsDefault extends Config((site, here, up) => { case DefaultClockFrequencyKey => (site(PeripheryBusKey).dtsFrequency.get / (1000 * 1000)).toDouble diff --git a/generators/chipyard/src/main/scala/HarnessBinders.scala b/generators/chipyard/src/main/scala/HarnessBinders.scala index 643b2065..95382f6e 100644 --- a/generators/chipyard/src/main/scala/HarnessBinders.scala +++ b/generators/chipyard/src/main/scala/HarnessBinders.scala @@ -139,6 +139,29 @@ class WithSimAXIMem extends OverrideHarnessBinder({ } }) +class WithOffchipNetwork(offchipFreqMHz: Double = 1000) extends OverrideHarnessBinder({ + (system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedAndResetIO[ClockedIO[SerialIO]]]) => { + implicit val p = chipyard.iobinders.GetSystemParameters(system) + + ports.map({ port => + val offchipNetwork = SerialAdapter.connectOffChipNetwork(system.serdesser.get, port, th.harnessReset) + val success = SerialAdapter.connectSimSerial(offchipNetwork.module.io.tsi_ser, port.bits.clock, th.harnessReset.asBool) + when (success) { th.success := true.B } + + // connect SimAxiMem + (offchipNetwork.mem_axi4 zip offchipNetwork.memAXI4Node.edges.in).map { case (off_port, edge) => + val memSize = p(SerialTLKey).get.memParams.size + val lineSize = p(CacheBlockBytes) + val mem = Module(new SimDRAM(memSize, lineSize, offchipFreqMHz.toInt*1000000, edge.bundle)).suggestName("simdram") + mem.io.axi <> off_port + // use the clk from the ClockAndResetIO + mem.io.clock := port.clock + mem.io.reset := port.reset + } + }) + } +}) + class WithBlackBoxSimMem(additionalLatency: Int = 0) extends OverrideHarnessBinder({ (system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => { val p: Parameters = chipyard.iobinders.GetSystemParameters(system) diff --git a/generators/chipyard/src/main/scala/IOBinders.scala b/generators/chipyard/src/main/scala/IOBinders.scala index ab6ccdf8..eff75ae2 100644 --- a/generators/chipyard/src/main/scala/IOBinders.scala +++ b/generators/chipyard/src/main/scala/IOBinders.scala @@ -11,7 +11,7 @@ import freechips.rocketchip.subsystem._ import freechips.rocketchip.system.{SimAXIMem} import freechips.rocketchip.amba.axi4.{AXI4Bundle, AXI4SlaveNode, AXI4MasterNode, AXI4EdgeParameters} import freechips.rocketchip.util._ -import freechips.rocketchip.prci.{ClockSinkNode, ClockSinkParameters} +import freechips.rocketchip.prci.{ClockSinkNode, ClockSinkParameters, ClockParameters, ClockGroup} import freechips.rocketchip.groundtest.{GroundTestSubsystemModuleImp, GroundTestSubsystem} import sifive.blocks.devices.gpio._ @@ -260,6 +260,34 @@ class WithSerialTLIOCells extends OverrideIOBinder({ }).getOrElse((Nil, Nil)) }) +class WithSerialTLAndOffchipClockPunchthrough(offchipFreqMHz: Double = 1000) extends OverrideLazyIOBinder({ + (system: CanHavePeripheryTLSerial) => { + implicit val p: Parameters = GetSystemParameters(system) + + val serial_clked_tl = system.serial_tl + val sys = system.asInstanceOf[BaseSubsystem] + + val externalDRAMClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters(take = Some(ClockParameters(freqMHz = offchipFreqMHz))))) + (externalDRAMClockSinkNode + := ClockGroup()(p, ValName("OffchipClocking")) + := sys.asyncClockGroupsNode) + def clockBundle = externalDRAMClockSinkNode.in.head._1 + + InModuleBody { + // 1st clock+reset is for offchip, 2nd clock (attached to serial io is the serial clock) + val port: Option[ClockedAndResetIO[ClockedIO[SerialIO]]] = serial_clked_tl.map({ s_io => + val p = IO(new ClockedAndResetIO(DataMirror.internal.chiselTypeClone[ClockedIO[SerialIO]](s_io))).suggestName(s"serial_tl_offchip_clk") + p.bits <> s_io + p.clock := clockBundle.clock + p.reset := clockBundle.reset + p + }) + + // return the ports and no IO cells + (Seq(port.get), Nil) + } + } +}) class WithAXI4MemPunchthrough extends OverrideLazyIOBinder({ (system: CanHaveMasterAXI4MemPort) => { diff --git a/generators/chipyard/src/main/scala/config/AbstractConfig.scala b/generators/chipyard/src/main/scala/config/AbstractConfig.scala index a70ae4df..043bd45e 100644 --- a/generators/chipyard/src/main/scala/config/AbstractConfig.scala +++ b/generators/chipyard/src/main/scala/config/AbstractConfig.scala @@ -55,3 +55,46 @@ class AbstractConfig extends Config( new chipyard.WithMulticlockCoherentBusTopology ++ // hierarchical buses including mbus+l2 new freechips.rocketchip.system.BaseConfig) // "base" rocketchip system +class AbstractOffChipConfig extends Config( + // The HarnessBinders control generation of hardware in the TestHarness + new chipyard.harness.WithUARTAdapter ++ // add UART adapter to display UART on stdout, if uart is present + new chipyard.harness.WithOffchipNetwork ++ // add SimDRAM DRAM model for axi4 backing memory over the SerDes link, if axi4 mem is enabled + new chipyard.harness.WithSimDebug ++ // add SimJTAG or SimDTM adapters if debug module is enabled + new chipyard.harness.WithGPIOTiedOff ++ // tie-off chiptop GPIOs, if GPIOs are present + new chipyard.harness.WithSimSPIFlashModel ++ // add simulated SPI flash memory, if SPI is enabled + new chipyard.harness.WithSimAXIMMIO ++ // add SimAXIMem for axi4 mmio port, if enabled + new chipyard.harness.WithTieOffInterrupts ++ // tie-off interrupt ports, if present + new chipyard.harness.WithTieOffL2FBusAXI ++ // tie-off external AXI4 master, if present + + // The IOBinders instantiate ChipTop IOs to match desired digital IOs + // IOCells are generated for "Chip-like" IOs, while simulation-only IOs are directly punched through + new chipyard.iobinders.WithAXI4MemPunchthrough ++ + new chipyard.iobinders.WithAXI4MMIOPunchthrough ++ + new chipyard.iobinders.WithL2FBusAXI4Punchthrough ++ + new chipyard.iobinders.WithBlockDeviceIOPunchthrough ++ + new chipyard.iobinders.WithNICIOPunchthrough ++ + new chipyard.iobinders.WithSerialTLAndOffchipClockPunchthrough ++ + new chipyard.iobinders.WithDebugIOCells ++ + new chipyard.iobinders.WithUARTIOCells ++ + new chipyard.iobinders.WithGPIOCells ++ + new chipyard.iobinders.WithUARTIOCells ++ + new chipyard.iobinders.WithSPIIOCells ++ + new chipyard.iobinders.WithTraceIOPunchthrough ++ + new chipyard.iobinders.WithExtInterruptIOCells ++ + + new chipyard.config.WithOffchipBackingMemory ++ + new chipyard.config.WithBootROM ++ // use default bootrom + new chipyard.config.WithUART ++ // add a UART + 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(100.0) ++ // Default 100 MHz mbus + new chipyard.config.WithPeripheryBusFrequency(100.0) ++ // Default 100 MHz pbus + new freechips.rocketchip.subsystem.WithJtagDTM ++ // set the debug module to expose a JTAG port + new freechips.rocketchip.subsystem.WithNoMMIOPort ++ // no top-level MMIO master port (overrides default set in rocketchip) + new freechips.rocketchip.subsystem.WithNoSlavePort ++ // no top-level MMIO slave port (overrides default set in rocketchip) + new freechips.rocketchip.subsystem.WithInclusiveCache ++ // use Sifive L2 cache + new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++ // no external interrupts + new chipyard.WithMulticlockCoherentBusTopology ++ // hierarchical buses including mbus+l2 + new freechips.rocketchip.system.BaseConfig) // "base" rocketchip system diff --git a/generators/chipyard/src/main/scala/config/RocketConfigs.scala b/generators/chipyard/src/main/scala/config/RocketConfigs.scala index 7c4de6f5..2e6eb40f 100644 --- a/generators/chipyard/src/main/scala/config/RocketConfigs.scala +++ b/generators/chipyard/src/main/scala/config/RocketConfigs.scala @@ -1,7 +1,8 @@ package chipyard import freechips.rocketchip.config.{Config} -import freechips.rocketchip.diplomacy.{AsynchronousCrossing} +import freechips.rocketchip.diplomacy.{AsynchronousCrossing, RationalCrossing} +import freechips.rocketchip.util.{SlowToFast} // -------------- // Rocket Configs @@ -212,3 +213,52 @@ class LBWIFRocketConfig extends Config( new freechips.rocketchip.subsystem.WithNoMemPort ++ // remove AXI4 backing memory new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) + +// DEBUG: To check if UART works (with everything default but serdes slow and ramp up to 1GHz) +class DebugOffchipConfig extends Config( + new testchipip.WithSerialTLWidth(32) ++ + new testchipip.WithAsynchronousSerialSlaveCrossing ++ // SerDes <-async-> mbus. Remember SerDes master tied to fbus + new chipyard.config.WithFbusToSbusCrossingType(RationalCrossing(SlowToFast)) ++ // fbus slow -> sbus fast + new chipyard.config.WithFrontBusFrequency(3200 / 4) ++ // controls SerDes freq. + + new chipyard.config.WithPeripheryBusFrequencyAsDefault ++ // everything default to 3.2GHz + new chipyard.config.WithPeripheryBusFrequency(3200) ++ + new chipyard.config.WithMemoryBusFrequency(3200) ++ + + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // add 1 rocket cores + new chipyard.config.AbstractOffChipConfig) // new offchip network where AXI is in harness + +// have pbus=3.2GHz,/1, but others are different (fbus=/4, other=/2) +class DebugOffchip2Config extends Config( + new chipyard.config.WithCbusToPbusCrossingType(RationalCrossing(SlowToFast)) ++ + new chipyard.config.WithFbusToSbusCrossingType(RationalCrossing(SlowToFast)) ++ + + new chipyard.config.WithSystemBusFrequencyAsDefault ++ + new chipyard.config.WithSystemBusFrequency(3200 / 2) ++ + + new chipyard.config.WithFrontBusFrequency(3200 / 4) ++ + new chipyard.config.WithPeripheryBusFrequency(3200) ++ + new chipyard.config.WithMemoryBusFrequency(3200) ++ + + new chipyard.config.WithFbusToSbusCrossingType(RationalCrossing(SlowToFast)) ++ // fbus slow -> sbus fast + new testchipip.WithAsynchronousSerialSlaveCrossing ++ // Add Async crossing between serial and MBUS. Its master-side is tied to the FBUS + + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // add 1 rocket cores + new chipyard.config.AbstractOffChipConfig) + +// fbus=/2, other=/1 +class DebugOffchip3Config extends Config( + new chipyard.config.WithFbusToSbusCrossingType(RationalCrossing(SlowToFast)) ++ + + new chipyard.config.WithSystemBusFrequencyAsDefault ++ + new chipyard.config.WithSystemBusFrequency(4000) ++ + new chipyard.config.WithPeripheryBusFrequency(4000) ++ + new chipyard.config.WithMemoryBusFrequency(4000) ++ + + new chipyard.config.WithFrontBusFrequency(4000 / 2) ++ + + new chipyard.config.WithFbusToSbusCrossingType(RationalCrossing(SlowToFast)) ++ // fbus slow -> sbus fast + new testchipip.WithAsynchronousSerialSlaveCrossing ++ // Add Async crossing between serial and MBUS. Its master-side is tied to the FBUS + + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // add 1 rocket cores + new chipyard.config.AbstractOffChipConfig) diff --git a/generators/firechip/src/main/scala/BridgeBinders.scala b/generators/firechip/src/main/scala/BridgeBinders.scala index bdbb7d44..34a18f85 100644 --- a/generators/firechip/src/main/scala/BridgeBinders.scala +++ b/generators/firechip/src/main/scala/BridgeBinders.scala @@ -103,6 +103,34 @@ class WithBlockDeviceBridge extends OverrideHarnessBinder({ } }) +class WithOffchipNetworkSerialAXIBridge extends OverrideHarnessBinder({ + (system: CanHavePeripheryTLSerial, th: FireSim, ports: Seq[ClockedAndResetIO[ClockedIO[SerialIO]]]) => { + implicit val p = GetSystemParameters(system) + + ports.map({ port => + val offchipNetwork = SerialAdapter.connectOffChipNetwork(system.serdesser.get, port, th.harnessReset) + SerialBridge(port.bits.clock, offchipNetwork.module.io.tsi_ser, p(ExtMem).map(_ => MainMemoryConsts.globalName)) + + // connect SimAxiMem + (offchipNetwork.mem_axi4 zip offchipNetwork.memAXI4Node.edges.in).map { case (axi4, edge) => + val nastiKey = NastiParameters(axi4.r.bits.data.getWidth, + axi4.ar.bits.addr.getWidth, + axi4.ar.bits.id.getWidth) + system match { + case s: BaseSubsystem => FASEDBridge(port.clock, axi4, port.reset.asBool, + CompleteConfig(p(firesim.configs.MemModelKey), + nastiKey, + Some(AXI4EdgeSummary(edge)), + Some(MainMemoryConsts.globalName))) + case _ => throw new Exception("Attempting to attach FASED Bridge to misconfigured design") + } + } + }) + + Nil + } +}) + class WithFASEDBridge extends OverrideHarnessBinder({ (system: CanHaveMasterAXI4MemPort, th: FireSim, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => { implicit val p: Parameters = GetSystemParameters(system) diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index 92cd02c3..619137fd 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -215,3 +215,58 @@ class FireSim16LargeBoomConfig extends Config( new WithFireSimConfigTweaks ++ new boom.common.WithNLargeBooms(16) ++ new chipyard.config.AbstractConfig) + +class WithOffchipAXINoClksSetup(pbusFreqMHz: BigInt = 3200) extends Config( + // normal bridges + new offchip bridge + new WithNICBridge ++ + new WithUARTBridge ++ + new WithBlockDeviceBridge ++ + new WithOffchipNetworkSerialAXIBridge ++ // NEW BRIDGE COMBINING SERIAL/AXI + new WithFireSimMultiCycleRegfile ++ + new WithFireSimFAME5 ++ + //new WithTracerVBridge ++ + new WithFireSimIOCellModels ++ + + // new tweaks + // Required: Bake in the default FASED memory model + new WithDefaultMemModel ++ + // Required*: Uses FireSim ClockBridge and PeekPokeBridge to drive the system with a single clock/reset + new WithFireSimSimpleClocks ++ + // 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 + new WithoutClockGating ++ + // Required*: Removes thousands of assertions that would be synthesized (* pending PriorityMux bugfix) + new WithoutTLMonitors ++ + // Optional: Adds IO to attach tracerV bridges + //new chipyard.config.WithTraceIO ++ + // Optional: Request 16 GiB of target-DRAM by default (can safely request up to 32 GiB on F1) + new freechips.rocketchip.subsystem.WithExtMemSize((1 << 30) * 16L) ++ + // Optional: Removing this will require using an initramfs under linux + new testchipip.WithBlockDevice ++ + // Required*: Scale default baud rate with periphery bus frequency + // Rough math... + // NEW: + // pbus @ 500MHz.... baud @ 576000 = 115200 * 5 (somehow the default was 100M) + // OLD: pbus @ 3200MHz, HW baud @ 3686400L AKA 115200 * 32 + // OLD: Linux @ 115200, SBI @ 115200 + // scale down to 100MHz before multipling up + new chipyard.config.WithUART((pbusFreqMHz / 100) * BigInt(115200L)) ++ + // Required: Do not support debug module w. JTAG until FIRRTL stops emitting @(posedge ~clock) + new chipyard.config.WithNoDebug +) + +class FireSimDebugOffchipConfig extends Config( + new WithOffchipAXINoClksSetup(3200) ++ + new chipyard.DebugOffchipConfig +) + +class FireSimDebugOffchip2Config extends Config( + new WithOffchipAXINoClksSetup(3200) ++ + new chipyard.DebugOffchip2Config +) + +class FireSimDebugOffchip3Config extends Config( + new WithOffchipAXINoClksSetup(4000) ++ + new chipyard.DebugOffchip3Config +) diff --git a/generators/testchipip b/generators/testchipip index f2705592..abc5be8e 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit f27055929a2d4c091bfe10c3b64761e281844a2b +Subproject commit abc5be8ef1dc9bb5614ef81fbb021b51a21679dd From 1d287bede5fc4012b1ce8120fd00ffab98d8348e Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Wed, 3 Mar 2021 02:43:38 +0000 Subject: [PATCH 03/30] Enlarge serial width | Bugfix loadmem disable | Add TracerV --- .../chipyard/src/main/scala/config/RocketConfigs.scala | 2 +- generators/firechip/src/main/scala/BridgeBinders.scala | 3 ++- generators/firechip/src/main/scala/TargetConfigs.scala | 10 +++++++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/generators/chipyard/src/main/scala/config/RocketConfigs.scala b/generators/chipyard/src/main/scala/config/RocketConfigs.scala index 2e6eb40f..4d93f8e9 100644 --- a/generators/chipyard/src/main/scala/config/RocketConfigs.scala +++ b/generators/chipyard/src/main/scala/config/RocketConfigs.scala @@ -216,7 +216,7 @@ class LBWIFRocketConfig extends Config( // DEBUG: To check if UART works (with everything default but serdes slow and ramp up to 1GHz) class DebugOffchipConfig extends Config( - new testchipip.WithSerialTLWidth(32) ++ + new testchipip.WithSerialTLWidth(64) ++ new testchipip.WithAsynchronousSerialSlaveCrossing ++ // SerDes <-async-> mbus. Remember SerDes master tied to fbus new chipyard.config.WithFbusToSbusCrossingType(RationalCrossing(SlowToFast)) ++ // fbus slow -> sbus fast new chipyard.config.WithFrontBusFrequency(3200 / 4) ++ // controls SerDes freq. diff --git a/generators/firechip/src/main/scala/BridgeBinders.scala b/generators/firechip/src/main/scala/BridgeBinders.scala index 34a18f85..6f74b770 100644 --- a/generators/firechip/src/main/scala/BridgeBinders.scala +++ b/generators/firechip/src/main/scala/BridgeBinders.scala @@ -109,7 +109,8 @@ class WithOffchipNetworkSerialAXIBridge extends OverrideHarnessBinder({ ports.map({ port => val offchipNetwork = SerialAdapter.connectOffChipNetwork(system.serdesser.get, port, th.harnessReset) - SerialBridge(port.bits.clock, offchipNetwork.module.io.tsi_ser, p(ExtMem).map(_ => MainMemoryConsts.globalName)) + SerialBridge(port.bits.clock, offchipNetwork.module.io.tsi_ser, p(SerialTLKey).map(v => MainMemoryConsts.globalName)) + p(SerialTLKey).map(v => require(v.isMemoryDevice)) // connect SimAxiMem (offchipNetwork.mem_axi4 zip offchipNetwork.memAXI4Node.edges.in).map { case (axi4, edge) => diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index 619137fd..de9e9cf7 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -251,22 +251,30 @@ class WithOffchipAXINoClksSetup(pbusFreqMHz: BigInt = 3200) extends Config( // OLD: pbus @ 3200MHz, HW baud @ 3686400L AKA 115200 * 32 // OLD: Linux @ 115200, SBI @ 115200 // scale down to 100MHz before multipling up - new chipyard.config.WithUART((pbusFreqMHz / 100) * BigInt(115200L)) ++ + //new chipyard.config.WithUART((pbusFreqMHz / 100) * BigInt(115200L)) ++ + new chipyard.config.WithUART(BigInt(3686400L)) ++ // Required: Do not support debug module w. JTAG until FIRRTL stops emitting @(posedge ~clock) new chipyard.config.WithNoDebug ) +class WithTracerV extends Config( + new WithTracerVBridge ++ + new chipyard.config.WithTraceIO) + class FireSimDebugOffchipConfig extends Config( + new WithTracerV ++ new WithOffchipAXINoClksSetup(3200) ++ new chipyard.DebugOffchipConfig ) class FireSimDebugOffchip2Config extends Config( + new WithTracerV ++ new WithOffchipAXINoClksSetup(3200) ++ new chipyard.DebugOffchip2Config ) class FireSimDebugOffchip3Config extends Config( + new WithTracerV ++ new WithOffchipAXINoClksSetup(4000) ++ new chipyard.DebugOffchip3Config ) From f850df7a9f1e9ecd5d5d4f8fa694c9c9d36cb0c4 Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Tue, 2 Mar 2021 22:58:05 -0800 Subject: [PATCH 04/30] General renaming / cleanup --- .../src/main/scala/ConfigFragments.scala | 9 +- .../src/main/scala/HarnessBinders.scala | 37 ++++--- .../chipyard/src/main/scala/IOBinders.scala | 34 +++--- .../main/scala/config/AbstractConfig.scala | 44 -------- .../src/main/scala/config/RocketConfigs.scala | 75 +++++++------ .../src/main/scala/BridgeBinders.scala | 42 ++++---- .../src/main/scala/TargetConfigs.scala | 101 ++++++------------ generators/testchipip | 2 +- 8 files changed, 140 insertions(+), 204 deletions(-) diff --git a/generators/chipyard/src/main/scala/ConfigFragments.scala b/generators/chipyard/src/main/scala/ConfigFragments.scala index f2d77a5f..8f9ab029 100644 --- a/generators/chipyard/src/main/scala/ConfigFragments.scala +++ b/generators/chipyard/src/main/scala/ConfigFragments.scala @@ -193,19 +193,16 @@ class WithTLBackingMemory extends Config((site, here, up) => { case ExtTLMem => up(ExtMem, site) // enable TL backing memory }) -class WithOffchipBackingMemory extends Config((site, here, up) => { +class WithSerialTLBackingMemory extends Config((site, here, up) => { case ExtMem => None - case SerialTLKey => Some(SerialTLParams( + case SerialTLKey => up(SerialTLKey, site).map { k => k.copy( memParams = { val memPortParams = up(ExtMem, site).get - require(memPortParams.nMemoryChannels == 1) - memPortParams.master }, - width = 4, isMemoryDevice = true - )) + )} }) class WithTileFrequency(fMHz: Double) extends ClockNameContainsAssignment("tile", fMHz) diff --git a/generators/chipyard/src/main/scala/HarnessBinders.scala b/generators/chipyard/src/main/scala/HarnessBinders.scala index 95382f6e..54110ebe 100644 --- a/generators/chipyard/src/main/scala/HarnessBinders.scala +++ b/generators/chipyard/src/main/scala/HarnessBinders.scala @@ -139,25 +139,30 @@ class WithSimAXIMem extends OverrideHarnessBinder({ } }) -class WithOffchipNetwork(offchipFreqMHz: Double = 1000) extends OverrideHarnessBinder({ - (system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedAndResetIO[ClockedIO[SerialIO]]]) => { +class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({ + (system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[SerialAndPassthroughClockResetIO]) => { implicit val p = chipyard.iobinders.GetSystemParameters(system) - ports.map({ port => - val offchipNetwork = SerialAdapter.connectOffChipNetwork(system.serdesser.get, port, th.harnessReset) - val success = SerialAdapter.connectSimSerial(offchipNetwork.module.io.tsi_ser, port.bits.clock, th.harnessReset.asBool) - when (success) { th.success := true.B } + p(SerialTLKey).map({ sVal => + require(sVal.axiDomainClockFreqMHz.isDefined) + val freqRequested = sVal.axiDomainClockFreqMHz.get - // connect SimAxiMem - (offchipNetwork.mem_axi4 zip offchipNetwork.memAXI4Node.edges.in).map { case (off_port, edge) => - val memSize = p(SerialTLKey).get.memParams.size - val lineSize = p(CacheBlockBytes) - val mem = Module(new SimDRAM(memSize, lineSize, offchipFreqMHz.toInt*1000000, edge.bundle)).suggestName("simdram") - mem.io.axi <> off_port - // use the clk from the ClockAndResetIO - mem.io.clock := port.clock - mem.io.reset := port.reset - } + ports.map({ port => + val harnessMultiClockAXIRAM = SerialAdapter.connectHarnessMultiClockAXIRAM(system.serdesser.get, port, th.harnessReset) + val success = SerialAdapter.connectSimSerial(harnessMultiClockAXIRAM.module.io.tsi_ser, port.clocked_serial.clock, th.harnessReset.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.memAXI4Node.edges.in).map { case (axi_port, edge) => + val memSize = sVal.memParams.size + val lineSize = p(CacheBlockBytes) + val mem = Module(new SimDRAM(memSize, lineSize, (freqRequested.toInt)*1000000, edge.bundle)).suggestName("simdram") + mem.io.axi <> axi_port + // use the clk from the ClockAndResetIO + mem.io.clock := port.passthrough_clock_reset.clock + mem.io.reset := port.passthrough_clock_reset.reset + } + }) }) } }) diff --git a/generators/chipyard/src/main/scala/IOBinders.scala b/generators/chipyard/src/main/scala/IOBinders.scala index eff75ae2..26189ec5 100644 --- a/generators/chipyard/src/main/scala/IOBinders.scala +++ b/generators/chipyard/src/main/scala/IOBinders.scala @@ -260,33 +260,35 @@ class WithSerialTLIOCells extends OverrideIOBinder({ }).getOrElse((Nil, Nil)) }) -class WithSerialTLAndOffchipClockPunchthrough(offchipFreqMHz: Double = 1000) extends OverrideLazyIOBinder({ - (system: CanHavePeripheryTLSerial) => { +class WithSerialTLAndPassthroughClockPunchthrough extends OverrideLazyIOBinder({ + (system: CanHavePeripheryTLSerial) => system.serial_tl.map({ s => implicit val p: Parameters = GetSystemParameters(system) - val serial_clked_tl = system.serial_tl val sys = system.asInstanceOf[BaseSubsystem] - val externalDRAMClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters(take = Some(ClockParameters(freqMHz = offchipFreqMHz))))) - (externalDRAMClockSinkNode - := ClockGroup()(p, ValName("OffchipClocking")) + require(p(SerialTLKey).isDefined) + val sVal = p(SerialTLKey).get + + require(sVal.axiDomainClockFreqMHz.isDefined) + val freqRequested = sVal.axiDomainClockFreqMHz.get + + // request clock to pass along + val externalAXIDomainClkSinkNode = ClockSinkNode(Seq(ClockSinkParameters(take = Some(ClockParameters(freqMHz = freqRequested))))) + (externalAXIDomainClkSinkNode + := ClockGroup()(p, ValName("axi_mem_clock_domain")) := sys.asyncClockGroupsNode) - def clockBundle = externalDRAMClockSinkNode.in.head._1 + def clockBundle = externalAXIDomainClkSinkNode.in.head._1 InModuleBody { // 1st clock+reset is for offchip, 2nd clock (attached to serial io is the serial clock) - val port: Option[ClockedAndResetIO[ClockedIO[SerialIO]]] = serial_clked_tl.map({ s_io => - val p = IO(new ClockedAndResetIO(DataMirror.internal.chiselTypeClone[ClockedIO[SerialIO]](s_io))).suggestName(s"serial_tl_offchip_clk") - p.bits <> s_io - p.clock := clockBundle.clock - p.reset := clockBundle.reset - p - }) + val port = IO(new SerialAndPassthroughClockResetIO(sVal.width)).suggestName(s"serial_tl_passthrough_clk") + port.clocked_serial <> s + port.passthrough_clock_reset <> clockBundle // return the ports and no IO cells - (Seq(port.get), Nil) + (Seq(port), Nil) } - } + }).getOrElse(InModuleBody{(Nil, Nil)}).asInstanceOf[ModuleValue[IOBinderTuple]] }) class WithAXI4MemPunchthrough extends OverrideLazyIOBinder({ diff --git a/generators/chipyard/src/main/scala/config/AbstractConfig.scala b/generators/chipyard/src/main/scala/config/AbstractConfig.scala index 043bd45e..da84bd05 100644 --- a/generators/chipyard/src/main/scala/config/AbstractConfig.scala +++ b/generators/chipyard/src/main/scala/config/AbstractConfig.scala @@ -54,47 +54,3 @@ class AbstractConfig extends Config( new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++ // no external interrupts new chipyard.WithMulticlockCoherentBusTopology ++ // hierarchical buses including mbus+l2 new freechips.rocketchip.system.BaseConfig) // "base" rocketchip system - -class AbstractOffChipConfig extends Config( - // The HarnessBinders control generation of hardware in the TestHarness - new chipyard.harness.WithUARTAdapter ++ // add UART adapter to display UART on stdout, if uart is present - new chipyard.harness.WithOffchipNetwork ++ // add SimDRAM DRAM model for axi4 backing memory over the SerDes link, if axi4 mem is enabled - new chipyard.harness.WithSimDebug ++ // add SimJTAG or SimDTM adapters if debug module is enabled - new chipyard.harness.WithGPIOTiedOff ++ // tie-off chiptop GPIOs, if GPIOs are present - new chipyard.harness.WithSimSPIFlashModel ++ // add simulated SPI flash memory, if SPI is enabled - new chipyard.harness.WithSimAXIMMIO ++ // add SimAXIMem for axi4 mmio port, if enabled - new chipyard.harness.WithTieOffInterrupts ++ // tie-off interrupt ports, if present - new chipyard.harness.WithTieOffL2FBusAXI ++ // tie-off external AXI4 master, if present - - // The IOBinders instantiate ChipTop IOs to match desired digital IOs - // IOCells are generated for "Chip-like" IOs, while simulation-only IOs are directly punched through - new chipyard.iobinders.WithAXI4MemPunchthrough ++ - new chipyard.iobinders.WithAXI4MMIOPunchthrough ++ - new chipyard.iobinders.WithL2FBusAXI4Punchthrough ++ - new chipyard.iobinders.WithBlockDeviceIOPunchthrough ++ - new chipyard.iobinders.WithNICIOPunchthrough ++ - new chipyard.iobinders.WithSerialTLAndOffchipClockPunchthrough ++ - new chipyard.iobinders.WithDebugIOCells ++ - new chipyard.iobinders.WithUARTIOCells ++ - new chipyard.iobinders.WithGPIOCells ++ - new chipyard.iobinders.WithUARTIOCells ++ - new chipyard.iobinders.WithSPIIOCells ++ - new chipyard.iobinders.WithTraceIOPunchthrough ++ - new chipyard.iobinders.WithExtInterruptIOCells ++ - - new chipyard.config.WithOffchipBackingMemory ++ - new chipyard.config.WithBootROM ++ // use default bootrom - new chipyard.config.WithUART ++ // add a UART - 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(100.0) ++ // Default 100 MHz mbus - new chipyard.config.WithPeripheryBusFrequency(100.0) ++ // Default 100 MHz pbus - new freechips.rocketchip.subsystem.WithJtagDTM ++ // set the debug module to expose a JTAG port - new freechips.rocketchip.subsystem.WithNoMMIOPort ++ // no top-level MMIO master port (overrides default set in rocketchip) - new freechips.rocketchip.subsystem.WithNoSlavePort ++ // no top-level MMIO slave port (overrides default set in rocketchip) - new freechips.rocketchip.subsystem.WithInclusiveCache ++ // use Sifive L2 cache - new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++ // no external interrupts - new chipyard.WithMulticlockCoherentBusTopology ++ // hierarchical buses including mbus+l2 - new freechips.rocketchip.system.BaseConfig) // "base" rocketchip system diff --git a/generators/chipyard/src/main/scala/config/RocketConfigs.scala b/generators/chipyard/src/main/scala/config/RocketConfigs.scala index 4d93f8e9..11bf9c4f 100644 --- a/generators/chipyard/src/main/scala/config/RocketConfigs.scala +++ b/generators/chipyard/src/main/scala/config/RocketConfigs.scala @@ -214,37 +214,37 @@ class LBWIFRocketConfig extends Config( new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) -// DEBUG: To check if UART works (with everything default but serdes slow and ramp up to 1GHz) -class DebugOffchipConfig extends Config( - new testchipip.WithSerialTLWidth(64) ++ - new testchipip.WithAsynchronousSerialSlaveCrossing ++ // SerDes <-async-> mbus. Remember SerDes master tied to fbus - new chipyard.config.WithFbusToSbusCrossingType(RationalCrossing(SlowToFast)) ++ // fbus slow -> sbus fast - new chipyard.config.WithFrontBusFrequency(3200 / 4) ++ // controls SerDes freq. - - new chipyard.config.WithPeripheryBusFrequencyAsDefault ++ // everything default to 3.2GHz - new chipyard.config.WithPeripheryBusFrequency(3200) ++ - new chipyard.config.WithMemoryBusFrequency(3200) ++ - - new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // add 1 rocket cores - new chipyard.config.AbstractOffChipConfig) // new offchip network where AXI is in harness - -// have pbus=3.2GHz,/1, but others are different (fbus=/4, other=/2) -class DebugOffchip2Config extends Config( - new chipyard.config.WithCbusToPbusCrossingType(RationalCrossing(SlowToFast)) ++ - new chipyard.config.WithFbusToSbusCrossingType(RationalCrossing(SlowToFast)) ++ - - new chipyard.config.WithSystemBusFrequencyAsDefault ++ - new chipyard.config.WithSystemBusFrequency(3200 / 2) ++ - - new chipyard.config.WithFrontBusFrequency(3200 / 4) ++ - new chipyard.config.WithPeripheryBusFrequency(3200) ++ - new chipyard.config.WithMemoryBusFrequency(3200) ++ - - new chipyard.config.WithFbusToSbusCrossingType(RationalCrossing(SlowToFast)) ++ // fbus slow -> sbus fast - new testchipip.WithAsynchronousSerialSlaveCrossing ++ // Add Async crossing between serial and MBUS. Its master-side is tied to the FBUS - - new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // add 1 rocket cores - new chipyard.config.AbstractOffChipConfig) +//// DEBUG: To check if UART works (with everything default but serdes slow and ramp up to 1GHz) +//class DebugOffchipConfig extends Config( +// new testchipip.WithSerialTLWidth(64) ++ +// new testchipip.WithAsynchronousSerialSlaveCrossing ++ // SerDes <-async-> mbus. Remember SerDes master tied to fbus +// new chipyard.config.WithFbusToSbusCrossingType(RationalCrossing(SlowToFast)) ++ // fbus slow -> sbus fast +// new chipyard.config.WithFrontBusFrequency(3200 / 4) ++ // controls SerDes freq. +// +// new chipyard.config.WithPeripheryBusFrequencyAsDefault ++ // everything default to 3.2GHz +// new chipyard.config.WithPeripheryBusFrequency(3200) ++ +// new chipyard.config.WithMemoryBusFrequency(3200) ++ +// +// new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // add 1 rocket cores +// new chipyard.config.AbstractOffChipConfig) // new offchip network where AXI is in harness +// +//// have pbus=3.2GHz,/1, but others are different (fbus=/4, other=/2) +//class DebugOffchip2Config extends Config( +// new chipyard.config.WithCbusToPbusCrossingType(RationalCrossing(SlowToFast)) ++ +// new chipyard.config.WithFbusToSbusCrossingType(RationalCrossing(SlowToFast)) ++ +// +// new chipyard.config.WithSystemBusFrequencyAsDefault ++ +// new chipyard.config.WithSystemBusFrequency(3200 / 2) ++ +// +// new chipyard.config.WithFrontBusFrequency(3200 / 4) ++ +// new chipyard.config.WithPeripheryBusFrequency(3200) ++ +// new chipyard.config.WithMemoryBusFrequency(3200) ++ +// +// new chipyard.config.WithFbusToSbusCrossingType(RationalCrossing(SlowToFast)) ++ // fbus slow -> sbus fast +// new testchipip.WithAsynchronousSerialSlaveCrossing ++ // Add Async crossing between serial and MBUS. Its master-side is tied to the FBUS +// +// new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // add 1 rocket cores +// new chipyard.config.AbstractOffChipConfig) // fbus=/2, other=/1 class DebugOffchip3Config extends Config( @@ -257,8 +257,13 @@ class DebugOffchip3Config extends Config( new chipyard.config.WithFrontBusFrequency(4000 / 2) ++ - new chipyard.config.WithFbusToSbusCrossingType(RationalCrossing(SlowToFast)) ++ // fbus slow -> sbus fast - new testchipip.WithAsynchronousSerialSlaveCrossing ++ // Add Async crossing between serial and MBUS. Its master-side is tied to the FBUS + new chipyard.config.WithFbusToSbusCrossingType(RationalCrossing(SlowToFast)) ++ + new testchipip.WithAsynchronousSerialSlaveCrossing ++ - new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // add 1 rocket cores - new chipyard.config.AbstractOffChipConfig) + new chipyard.harness.WithSimAXIMemOverSerialTL ++ // add SimDRAM DRAM model for axi4 backing memory over the SerDes link, if axi4 mem is enabled + new chipyard.iobinders.WithSerialTLAndPassthroughClockPunchthrough ++ // add new clock for axi domain over serdes and passthrough ios + //new testchipip.WithAXIDomainFreq(1000.0) ++ // set offchip axi domain clock freq (match FireSim DRAM) + new chipyard.config.WithSerialTLBackingMemory ++ // remove axi4 mem port in favor of SerialTL memory + + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new chipyard.config.AbstractConfig) diff --git a/generators/firechip/src/main/scala/BridgeBinders.scala b/generators/firechip/src/main/scala/BridgeBinders.scala index 6f74b770..eb48cc47 100644 --- a/generators/firechip/src/main/scala/BridgeBinders.scala +++ b/generators/firechip/src/main/scala/BridgeBinders.scala @@ -103,29 +103,33 @@ class WithBlockDeviceBridge extends OverrideHarnessBinder({ } }) -class WithOffchipNetworkSerialAXIBridge extends OverrideHarnessBinder({ - (system: CanHavePeripheryTLSerial, th: FireSim, ports: Seq[ClockedAndResetIO[ClockedIO[SerialIO]]]) => { +class WithAXIOverSerialTLCombinedBridges extends OverrideHarnessBinder({ + (system: CanHavePeripheryTLSerial, th: FireSim, ports: Seq[SerialAndPassthroughClockResetIO]]]) => { implicit val p = GetSystemParameters(system) - ports.map({ port => - val offchipNetwork = SerialAdapter.connectOffChipNetwork(system.serdesser.get, port, th.harnessReset) - SerialBridge(port.bits.clock, offchipNetwork.module.io.tsi_ser, p(SerialTLKey).map(v => MainMemoryConsts.globalName)) - p(SerialTLKey).map(v => require(v.isMemoryDevice)) + p(SerialTLKey).map({ sVal => + // require having memory over the serdes link + require(sVal.isMemoryDevice) - // connect SimAxiMem - (offchipNetwork.mem_axi4 zip offchipNetwork.memAXI4Node.edges.in).map { case (axi4, edge) => - val nastiKey = NastiParameters(axi4.r.bits.data.getWidth, - axi4.ar.bits.addr.getWidth, - axi4.ar.bits.id.getWidth) - system match { - case s: BaseSubsystem => FASEDBridge(port.clock, axi4, port.reset.asBool, - CompleteConfig(p(firesim.configs.MemModelKey), - nastiKey, - Some(AXI4EdgeSummary(edge)), - Some(MainMemoryConsts.globalName))) - case _ => throw new Exception("Attempting to attach FASED Bridge to misconfigured design") + ports.map({ port => + val offchipNetwork = SerialAdapter.connectHarnessMultiClockAXIRAM(system.serdesser.get, port, th.harnessReset) + SerialBridge(port.clocked_serial.clock, offchipNetwork.module.io.tsi_ser, MainMemoryConsts.globalName) + + // connect SimAxiMem + (offchipNetwork.mem_axi4 zip offchipNetwork.memAXI4Node.edges.in).map { case (axi4, edge) => + val nastiKey = NastiParameters(axi4.r.bits.data.getWidth, + axi4.ar.bits.addr.getWidth, + axi4.ar.bits.id.getWidth) + system match { + case s: BaseSubsystem => FASEDBridge(port.passthrough_clock_reset.clock, axi4, port.passthrough_clock_reset.reset.asBool, + CompleteConfig(p(firesim.configs.MemModelKey), + nastiKey, + Some(AXI4EdgeSummary(edge)), + Some(MainMemoryConsts.globalName))) + case _ => throw new Exception("Attempting to attach FASED Bridge to misconfigured design") + } } - } + }) }) Nil diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index de9e9cf7..51f18227 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -59,26 +59,13 @@ class WithNIC extends icenet.WithIceNIC(inBufFlits = 8192, ctrlQueueDepth = 64) class WithNVDLALarge extends nvidia.blocks.dla.WithNVDLA("large") class WithNVDLASmall extends nvidia.blocks.dla.WithNVDLA("small") - -// Tweaks that are generally applied to all firesim configs -class WithFireSimConfigTweaks extends Config( +class WithFireSimConfigTweaksWithoutClocking extends Config( // Required: Bake in the default FASED memory model new WithDefaultMemModel ++ // Required*: Uses FireSim ClockBridge and PeekPokeBridge to drive the system with a single clock/reset new WithFireSimSimpleClocks ++ // Required*: When using FireSim-as-top to provide a correct path to the target bootrom source new WithBootROM ++ - // Optional*: Removing this will require adjusting the UART baud rate and - // potential target-software changes to properly capture UART output - new chipyard.config.WithPeripheryBusFrequency(3200.0) ++ - // Optional: These three configs put the DRAM memory system in it's own clock domian. - // Removing the first config will result in the FASED timing model running - // at the pbus freq (above, 3.2 GHz), which is outside the range of valid DDR3 speedgrades. - // 1 GHz matches the FASED default, using some other frequency will require - // runnings the FASED runtime configuration generator to generate faithful DDR3 timing values. - new chipyard.config.WithMemoryBusFrequency(1000.0) ++ - new chipyard.config.WithAsynchrousMemoryBusCrossing ++ - new testchipip.WithAsynchronousSerialSlaveCrossing ++ // Required: Existing FAME-1 transform cannot handle black-box clock gates new WithoutClockGating ++ // Required*: Removes thousands of assertions that would be synthesized (* pending PriorityMux bugfix) @@ -99,6 +86,23 @@ class WithFireSimConfigTweaks extends Config( new chipyard.config.WithNoDebug ) +// Tweaks that are generally applied to all firesim configs +class WithFireSimConfigTweaks extends Config( + // Optional*: Removing this will require adjusting the UART baud rate and + // potential target-software changes to properly capture UART output + new chipyard.config.WithPeripheryBusFrequency(3200.0) ++ + // Optional: These three configs put the DRAM memory system in it's own clock domian. + // Removing the first config will result in the FASED timing model running + // at the pbus freq (above, 3.2 GHz), which is outside the range of valid DDR3 speedgrades. + // 1 GHz matches the FASED default, using some other frequency will require + // runnings the FASED runtime configuration generator to generate faithful DDR3 timing values. + new chipyard.config.WithMemoryBusFrequency(1000.0) ++ + new chipyard.config.WithAsynchrousMemoryBusCrossing ++ + new testchipip.WithAsynchronousSerialSlaveCrossing ++ + // Tweaks that are independent from multi-clock + new WithFireSimConfigTweaksWithoutClocking +) + /******************************************************************************* * Full TARGET_CONFIG configurations. These set parameters of the target being * simulated. @@ -216,65 +220,28 @@ class FireSim16LargeBoomConfig extends Config( new boom.common.WithNLargeBooms(16) ++ new chipyard.config.AbstractConfig) +class WithAXIOverSerialTLCombinedBridges extends OverrideHarnessBinder({ class WithOffchipAXINoClksSetup(pbusFreqMHz: BigInt = 3200) extends Config( - // normal bridges + new offchip bridge - new WithNICBridge ++ - new WithUARTBridge ++ - new WithBlockDeviceBridge ++ - new WithOffchipNetworkSerialAXIBridge ++ // NEW BRIDGE COMBINING SERIAL/AXI - new WithFireSimMultiCycleRegfile ++ - new WithFireSimFAME5 ++ - //new WithTracerVBridge ++ - new WithFireSimIOCellModels ++ - - // new tweaks - // Required: Bake in the default FASED memory model - new WithDefaultMemModel ++ - // Required*: Uses FireSim ClockBridge and PeekPokeBridge to drive the system with a single clock/reset - new WithFireSimSimpleClocks ++ - // 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 - new WithoutClockGating ++ - // Required*: Removes thousands of assertions that would be synthesized (* pending PriorityMux bugfix) - new WithoutTLMonitors ++ - // Optional: Adds IO to attach tracerV bridges - //new chipyard.config.WithTraceIO ++ - // Optional: Request 16 GiB of target-DRAM by default (can safely request up to 32 GiB on F1) - new freechips.rocketchip.subsystem.WithExtMemSize((1 << 30) * 16L) ++ - // Optional: Removing this will require using an initramfs under linux - new testchipip.WithBlockDevice ++ - // Required*: Scale default baud rate with periphery bus frequency - // Rough math... - // NEW: - // pbus @ 500MHz.... baud @ 576000 = 115200 * 5 (somehow the default was 100M) - // OLD: pbus @ 3200MHz, HW baud @ 3686400L AKA 115200 * 32 - // OLD: Linux @ 115200, SBI @ 115200 - // scale down to 100MHz before multipling up //new chipyard.config.WithUART((pbusFreqMHz / 100) * BigInt(115200L)) ++ new chipyard.config.WithUART(BigInt(3686400L)) ++ - // Required: Do not support debug module w. JTAG until FIRRTL stops emitting @(posedge ~clock) - new chipyard.config.WithNoDebug ) -class WithTracerV extends Config( - new WithTracerVBridge ++ - new chipyard.config.WithTraceIO) - -class FireSimDebugOffchipConfig extends Config( - new WithTracerV ++ - new WithOffchipAXINoClksSetup(3200) ++ - new chipyard.DebugOffchipConfig -) - -class FireSimDebugOffchip2Config extends Config( - new WithTracerV ++ - new WithOffchipAXINoClksSetup(3200) ++ - new chipyard.DebugOffchip2Config -) +//class FireSimDebugOffchipConfig extends Config( +// new WithTracerV ++ +// new WithOffchipAXINoClksSetup(3200) ++ +// new chipyard.DebugOffchipConfig +//) +// +//class FireSimDebugOffchip2Config extends Config( +// new WithTracerV ++ +// new WithOffchipAXINoClksSetup(3200) ++ +// new chipyard.DebugOffchip2Config +//) class FireSimDebugOffchip3Config extends Config( - new WithTracerV ++ - new WithOffchipAXINoClksSetup(4000) ++ + new WithAXIOverSerialTLCombinedBridges ++ // use combined bridge to connect to axi mem over serial + new WithDefaultFireSimBridges ++ + new WithDefaultMemModel ++ + new WithFireSimConfigTweaksWithoutClocking ++ // don't inherit firesim clocking new chipyard.DebugOffchip3Config ) diff --git a/generators/testchipip b/generators/testchipip index abc5be8e..b66dd655 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit abc5be8ef1dc9bb5614ef81fbb021b51a21679dd +Subproject commit b66dd655a3605ff0b3327b133513e27b590d926e From c52fce79ae2348b515e54600cfd602976a513437 Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Wed, 3 Mar 2021 07:25:49 +0000 Subject: [PATCH 05/30] Fix FireChip compilation | Remove extra DefaultSerialTL in bridges --- .../src/main/scala/BridgeBinders.scala | 6 ++--- .../src/main/scala/TargetConfigs.scala | 22 ++++++++++--------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/generators/firechip/src/main/scala/BridgeBinders.scala b/generators/firechip/src/main/scala/BridgeBinders.scala index eb48cc47..b6b3caf9 100644 --- a/generators/firechip/src/main/scala/BridgeBinders.scala +++ b/generators/firechip/src/main/scala/BridgeBinders.scala @@ -98,13 +98,13 @@ class WithUARTBridge extends OverrideHarnessBinder({ 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.harnessReset.toBool) } + ports.map { b => BlockDevBridge(b.clock, b.bits, th.harnessReset.asBool) } Nil } }) class WithAXIOverSerialTLCombinedBridges extends OverrideHarnessBinder({ - (system: CanHavePeripheryTLSerial, th: FireSim, ports: Seq[SerialAndPassthroughClockResetIO]]]) => { + (system: CanHavePeripheryTLSerial, th: FireSim, ports: Seq[SerialAndPassthroughClockResetIO]) => { implicit val p = GetSystemParameters(system) p(SerialTLKey).map({ sVal => @@ -113,7 +113,7 @@ class WithAXIOverSerialTLCombinedBridges extends OverrideHarnessBinder({ ports.map({ port => val offchipNetwork = SerialAdapter.connectHarnessMultiClockAXIRAM(system.serdesser.get, port, th.harnessReset) - SerialBridge(port.clocked_serial.clock, offchipNetwork.module.io.tsi_ser, MainMemoryConsts.globalName) + SerialBridge(port.clocked_serial.clock, offchipNetwork.module.io.tsi_ser, Some(MainMemoryConsts.globalName)) // connect SimAxiMem (offchipNetwork.mem_axi4 zip offchipNetwork.memAXI4Node.edges.in).map { case (axi4, edge) => diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index 51f18227..58c28de1 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -74,10 +74,6 @@ class WithFireSimConfigTweaksWithoutClocking extends Config( new chipyard.config.WithTraceIO ++ // Optional: Request 16 GiB of target-DRAM by default (can safely request up to 32 GiB on F1) new freechips.rocketchip.subsystem.WithExtMemSize((1 << 30) * 16L) ++ - // Required: Adds IO to attach SerialBridge. The SerialBridges is responsible - // for signalling simulation termination under simulation success. This fragment can - // be removed if you supply an auxiliary bridge that signals simulation termination - new testchipip.WithDefaultSerialTL ++ // Optional: Removing this will require using an initramfs under linux new testchipip.WithBlockDevice ++ // Required*: Scale default baud rate with periphery bus frequency @@ -220,24 +216,30 @@ class FireSim16LargeBoomConfig extends Config( new boom.common.WithNLargeBooms(16) ++ new chipyard.config.AbstractConfig) -class WithAXIOverSerialTLCombinedBridges extends OverrideHarnessBinder({ -class WithOffchipAXINoClksSetup(pbusFreqMHz: BigInt = 3200) extends Config( - //new chipyard.config.WithUART((pbusFreqMHz / 100) * BigInt(115200L)) ++ - new chipyard.config.WithUART(BigInt(3686400L)) ++ -) +// unsure if this needs to scale +//new chipyard.config.WithUART((pbusFreqMHz / 100) * BigInt(115200L)) ++ //class FireSimDebugOffchipConfig extends Config( // new WithTracerV ++ // new WithOffchipAXINoClksSetup(3200) ++ // new chipyard.DebugOffchipConfig //) -// + //class FireSimDebugOffchip2Config extends Config( // new WithTracerV ++ // new WithOffchipAXINoClksSetup(3200) ++ // new chipyard.DebugOffchip2Config //) +class FireSimDebugOffchip2Config extends Config( + new chipyard.config.WithUART((4000 / 100) * BigInt(115200L)) ++ + new WithAXIOverSerialTLCombinedBridges ++ // use combined bridge to connect to axi mem over serial + new WithDefaultFireSimBridges ++ + new WithDefaultMemModel ++ + new WithFireSimConfigTweaksWithoutClocking ++ // don't inherit firesim clocking + new chipyard.DebugOffchip3Config +) + class FireSimDebugOffchip3Config extends Config( new WithAXIOverSerialTLCombinedBridges ++ // use combined bridge to connect to axi mem over serial new WithDefaultFireSimBridges ++ From 3d962180be010dec6d845bb03f7fd5c5cde9d5b7 Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Wed, 3 Mar 2021 19:44:55 +0000 Subject: [PATCH 06/30] Cleanup | Fix BlockDevice clocking issues --- .../src/main/scala/config/RocketConfigs.scala | 39 ++----------------- .../src/main/scala/TargetConfigs.scala | 39 ++++--------------- generators/testchipip | 2 +- 3 files changed, 13 insertions(+), 67 deletions(-) diff --git a/generators/chipyard/src/main/scala/config/RocketConfigs.scala b/generators/chipyard/src/main/scala/config/RocketConfigs.scala index 11bf9c4f..612b7ae6 100644 --- a/generators/chipyard/src/main/scala/config/RocketConfigs.scala +++ b/generators/chipyard/src/main/scala/config/RocketConfigs.scala @@ -214,40 +214,7 @@ class LBWIFRocketConfig extends Config( new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) -//// DEBUG: To check if UART works (with everything default but serdes slow and ramp up to 1GHz) -//class DebugOffchipConfig extends Config( -// new testchipip.WithSerialTLWidth(64) ++ -// new testchipip.WithAsynchronousSerialSlaveCrossing ++ // SerDes <-async-> mbus. Remember SerDes master tied to fbus -// new chipyard.config.WithFbusToSbusCrossingType(RationalCrossing(SlowToFast)) ++ // fbus slow -> sbus fast -// new chipyard.config.WithFrontBusFrequency(3200 / 4) ++ // controls SerDes freq. -// -// new chipyard.config.WithPeripheryBusFrequencyAsDefault ++ // everything default to 3.2GHz -// new chipyard.config.WithPeripheryBusFrequency(3200) ++ -// new chipyard.config.WithMemoryBusFrequency(3200) ++ -// -// new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // add 1 rocket cores -// new chipyard.config.AbstractOffChipConfig) // new offchip network where AXI is in harness -// -//// have pbus=3.2GHz,/1, but others are different (fbus=/4, other=/2) -//class DebugOffchip2Config extends Config( -// new chipyard.config.WithCbusToPbusCrossingType(RationalCrossing(SlowToFast)) ++ -// new chipyard.config.WithFbusToSbusCrossingType(RationalCrossing(SlowToFast)) ++ -// -// new chipyard.config.WithSystemBusFrequencyAsDefault ++ -// new chipyard.config.WithSystemBusFrequency(3200 / 2) ++ -// -// new chipyard.config.WithFrontBusFrequency(3200 / 4) ++ -// new chipyard.config.WithPeripheryBusFrequency(3200) ++ -// new chipyard.config.WithMemoryBusFrequency(3200) ++ -// -// new chipyard.config.WithFbusToSbusCrossingType(RationalCrossing(SlowToFast)) ++ // fbus slow -> sbus fast -// new testchipip.WithAsynchronousSerialSlaveCrossing ++ // Add Async crossing between serial and MBUS. Its master-side is tied to the FBUS -// -// new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // add 1 rocket cores -// new chipyard.config.AbstractOffChipConfig) - -// fbus=/2, other=/1 -class DebugOffchip3Config extends Config( +class MulticlockAXIOverSerialConfig extends Config( new chipyard.config.WithFbusToSbusCrossingType(RationalCrossing(SlowToFast)) ++ new chipyard.config.WithSystemBusFrequencyAsDefault ++ @@ -262,8 +229,10 @@ class DebugOffchip3Config extends Config( new chipyard.harness.WithSimAXIMemOverSerialTL ++ // add SimDRAM DRAM model for axi4 backing memory over the SerDes link, if axi4 mem is enabled new chipyard.iobinders.WithSerialTLAndPassthroughClockPunchthrough ++ // add new clock for axi domain over serdes and passthrough ios - //new testchipip.WithAXIDomainFreq(1000.0) ++ // set offchip axi domain clock freq (match FireSim DRAM) new chipyard.config.WithSerialTLBackingMemory ++ // remove axi4 mem port in favor of SerialTL memory + new testchipip.WithBlockDeviceLocations( + freechips.rocketchip.subsystem.PBUS, + freechips.rocketchip.subsystem.PBUS) ++ // put block device fully on PBUS to avoid clock crossings new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index 58c28de1..a7626f32 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -204,6 +204,14 @@ class FireSimMulticlockRocketConfig extends Config( new freechips.rocketchip.subsystem.WithRationalRocketTiles ++ // Add rational crossings between RocketTile and uncore new FireSimRocketConfig) +class FireSimMulticlockAXIOverSerialConfig extends Config( + new WithAXIOverSerialTLCombinedBridges ++ // use combined bridge to connect to axi mem over serial + new WithDefaultFireSimBridges ++ + new WithDefaultMemModel ++ + new WithFireSimConfigTweaksWithoutClocking ++ // don't inherit firesim clocking + new chipyard.MulticlockAXIOverSerialConfig +) + //********************************************************************************** // System with 16 LargeBOOMs that can be simulated with Golden Gate optimizations // - Requires MTModels and MCRams mixins as prefixes to the platform config @@ -216,34 +224,3 @@ class FireSim16LargeBoomConfig extends Config( new boom.common.WithNLargeBooms(16) ++ new chipyard.config.AbstractConfig) -// unsure if this needs to scale -//new chipyard.config.WithUART((pbusFreqMHz / 100) * BigInt(115200L)) ++ - -//class FireSimDebugOffchipConfig extends Config( -// new WithTracerV ++ -// new WithOffchipAXINoClksSetup(3200) ++ -// new chipyard.DebugOffchipConfig -//) - -//class FireSimDebugOffchip2Config extends Config( -// new WithTracerV ++ -// new WithOffchipAXINoClksSetup(3200) ++ -// new chipyard.DebugOffchip2Config -//) - -class FireSimDebugOffchip2Config extends Config( - new chipyard.config.WithUART((4000 / 100) * BigInt(115200L)) ++ - new WithAXIOverSerialTLCombinedBridges ++ // use combined bridge to connect to axi mem over serial - new WithDefaultFireSimBridges ++ - new WithDefaultMemModel ++ - new WithFireSimConfigTweaksWithoutClocking ++ // don't inherit firesim clocking - new chipyard.DebugOffchip3Config -) - -class FireSimDebugOffchip3Config extends Config( - new WithAXIOverSerialTLCombinedBridges ++ // use combined bridge to connect to axi mem over serial - new WithDefaultFireSimBridges ++ - new WithDefaultMemModel ++ - new WithFireSimConfigTweaksWithoutClocking ++ // don't inherit firesim clocking - new chipyard.DebugOffchip3Config -) diff --git a/generators/testchipip b/generators/testchipip index b66dd655..531ffb70 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit b66dd655a3605ff0b3327b133513e27b590d926e +Subproject commit 531ffb7020ef012c5d9dd8642df515d2fbadd7a8 From 3d9cd61d1602f513b1ed4a52cc1ebad51f95e49d Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Wed, 3 Mar 2021 22:38:44 -0800 Subject: [PATCH 07/30] Slightly cleaner implementation --- .../src/main/scala/HarnessBinders.scala | 26 +++++++++----- .../chipyard/src/main/scala/IOBinders.scala | 36 ++++++++++++------- generators/testchipip | 2 +- 3 files changed, 43 insertions(+), 21 deletions(-) diff --git a/generators/chipyard/src/main/scala/HarnessBinders.scala b/generators/chipyard/src/main/scala/HarnessBinders.scala index 54110ebe..505cded7 100644 --- a/generators/chipyard/src/main/scala/HarnessBinders.scala +++ b/generators/chipyard/src/main/scala/HarnessBinders.scala @@ -144,8 +144,19 @@ class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({ implicit val p = chipyard.iobinders.GetSystemParameters(system) p(SerialTLKey).map({ sVal => - require(sVal.axiDomainClockFreqMHz.isDefined) - val freqRequested = sVal.axiDomainClockFreqMHz.get + // currently only the harness AXI port supports a passthrough clock + require(sVal.axiMemOverSerialTLParams.isDefined) + val axiDomainParams = sVal.axiMemOverSerialTLParams.get + + val memFreq = axiDomainParams.axiClockParams match { + case Some(clkParams) => { + BigInt(clkParams.clockFreqMHz.toInt)*1000000 + } + case None => { + // get freq. from what the master bus specifies + system.asInstanceOf[HasTileLinkLocations].locateTLBusWrapper(p(SerialTLAttachKey).masterWhere).dtsFrequency.get + } + } ports.map({ port => val harnessMultiClockAXIRAM = SerialAdapter.connectHarnessMultiClockAXIRAM(system.serdesser.get, port, th.harnessReset) @@ -153,14 +164,13 @@ class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({ 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.memAXI4Node.edges.in).map { case (axi_port, edge) => + (harnessMultiClockAXIRAM.mem_axi4 zip harnessMultiClockAXIRAM.memNode.edges.in).map { case (axi_port, edge) => val memSize = sVal.memParams.size val lineSize = p(CacheBlockBytes) - val mem = Module(new SimDRAM(memSize, lineSize, (freqRequested.toInt)*1000000, edge.bundle)).suggestName("simdram") - mem.io.axi <> axi_port - // use the clk from the ClockAndResetIO - mem.io.clock := port.passthrough_clock_reset.clock - mem.io.reset := port.passthrough_clock_reset.reset + val mem = Module(new SimDRAM(memSize, lineSize, memFreq, edge.bundle)).suggestName("simdram") + mem.io.axi <> axi_port.bits + mem.io.clock := axi_port.clock + mem.io.reset := axi_port.reset } }) }) diff --git a/generators/chipyard/src/main/scala/IOBinders.scala b/generators/chipyard/src/main/scala/IOBinders.scala index 26189ec5..5621382e 100644 --- a/generators/chipyard/src/main/scala/IOBinders.scala +++ b/generators/chipyard/src/main/scala/IOBinders.scala @@ -11,7 +11,7 @@ import freechips.rocketchip.subsystem._ import freechips.rocketchip.system.{SimAXIMem} import freechips.rocketchip.amba.axi4.{AXI4Bundle, AXI4SlaveNode, AXI4MasterNode, AXI4EdgeParameters} import freechips.rocketchip.util._ -import freechips.rocketchip.prci.{ClockSinkNode, ClockSinkParameters, ClockParameters, ClockGroup} +import freechips.rocketchip.prci.{ClockSinkNode, ClockSinkParameters, ClockParameters, ClockGroup, ClockBundle, ClockBundleParameters} import freechips.rocketchip.groundtest.{GroundTestSubsystemModuleImp, GroundTestSubsystem} import sifive.blocks.devices.gpio._ @@ -261,7 +261,7 @@ class WithSerialTLIOCells extends OverrideIOBinder({ }) class WithSerialTLAndPassthroughClockPunchthrough extends OverrideLazyIOBinder({ - (system: CanHavePeripheryTLSerial) => system.serial_tl.map({ s => + (system: CanHavePeripheryTLSerial) => system.serial_tl.map({ serial_io => implicit val p: Parameters = GetSystemParameters(system) val sys = system.asInstanceOf[BaseSubsystem] @@ -269,20 +269,32 @@ class WithSerialTLAndPassthroughClockPunchthrough extends OverrideLazyIOBinder({ require(p(SerialTLKey).isDefined) val sVal = p(SerialTLKey).get - require(sVal.axiDomainClockFreqMHz.isDefined) - val freqRequested = sVal.axiDomainClockFreqMHz.get + // currently only the harness AXI port supports a passthrough clock + require(sVal.axiMemOverSerialTLParams.isDefined) + val axiDomainParams = sVal.axiMemOverSerialTLParams.get - // request clock to pass along - val externalAXIDomainClkSinkNode = ClockSinkNode(Seq(ClockSinkParameters(take = Some(ClockParameters(freqMHz = freqRequested))))) - (externalAXIDomainClkSinkNode - := ClockGroup()(p, ValName("axi_mem_clock_domain")) - := sys.asyncClockGroupsNode) - def clockBundle = externalAXIDomainClkSinkNode.in.head._1 + val clockSinkNode = axiDomainParams.axiClockParams.map({ clkParams => + // request clock to pass along + val node = ClockSinkNode(Seq(ClockSinkParameters(take = Some(ClockParameters(freqMHz = clkParams.clockFreqMHz))))) + (node + := ClockGroup()(p, ValName("mem_over_serialtl_domain")) + := sys.asyncClockGroupsNode) + node + }) + + def clockBundle = clockSinkNode match { + case Some(node) => node.in.head._1 + case None => { + val dontCareClockBundle = new ClockBundle(ClockBundleParameters()) + dontCareClockBundle.clock := DontCare + dontCareClockBundle.reset := DontCare + dontCareClockBundle + } + } InModuleBody { - // 1st clock+reset is for offchip, 2nd clock (attached to serial io is the serial clock) val port = IO(new SerialAndPassthroughClockResetIO(sVal.width)).suggestName(s"serial_tl_passthrough_clk") - port.clocked_serial <> s + port.clocked_serial <> serial_io port.passthrough_clock_reset <> clockBundle // return the ports and no IO cells diff --git a/generators/testchipip b/generators/testchipip index 531ffb70..3de5c07d 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit 531ffb7020ef012c5d9dd8642df515d2fbadd7a8 +Subproject commit 3de5c07d054ec301499e75374f3ae2c2cea3930c From d2a6dd68226c07ace8c5670c8c48cb39d54c7171 Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Thu, 4 Mar 2021 23:31:49 -0800 Subject: [PATCH 08/30] Add support for harness pll --- .../chipyard/src/main/scala/ChipTop.scala | 2 +- .../chipyard/src/main/scala/Clocks.scala | 12 +++- .../chipyard/src/main/scala/TestHarness.scala | 60 +++++++++++++++++-- .../clocking/DividerOnlyClockGenerator.scala | 2 +- 4 files changed, 67 insertions(+), 9 deletions(-) diff --git a/generators/chipyard/src/main/scala/ChipTop.scala b/generators/chipyard/src/main/scala/ChipTop.scala index 61a043b6..205135a2 100644 --- a/generators/chipyard/src/main/scala/ChipTop.scala +++ b/generators/chipyard/src/main/scala/ChipTop.scala @@ -28,7 +28,7 @@ class ChipTop(implicit p: Parameters) extends LazyModule with BindingScope // The system module specified by BuildSystem lazy val lazySystem = LazyModule(p(BuildSystem)(p)).suggestName("system") - // The implicitClockSinkNode provides the implicit clock and reset for the System + // The implicitClockSinkNode provides the implicit clock and reset for the system (connected by clocking scheme) val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters(name = Some("implicit_clock")))) // Generate Clocks and Reset diff --git a/generators/chipyard/src/main/scala/Clocks.scala b/generators/chipyard/src/main/scala/Clocks.scala index 0ba31abb..65346ea6 100644 --- a/generators/chipyard/src/main/scala/Clocks.scala +++ b/generators/chipyard/src/main/scala/Clocks.scala @@ -47,6 +47,12 @@ case object ClockingSchemeKey extends Field[ChipTop => Unit](ClockingSchemeGener */ case object ClockFrequencyAssignersKey extends Field[Seq[(String) => Option[Double]]](Seq.empty) case object DefaultClockFrequencyKey extends Field[Double]() +case object ReferenceClockTrackerKey extends Field[ReferenceClockTracker](new ReferenceClockTracker) +class ReferenceClockTracker { + private var _refFreqMHz: Option[Double] = None + def set(freqMHz: Double): Unit = { _refFreqMHz = Some(freqMHz) } + def get: Option[Double] = { _refFreqMHz } +} class ClockNameMatchesAssignment(name: String, fMHz: Double) extends Config((site, here, up) => { case ClockFrequencyAssignersKey => up(ClockFrequencyAssignersKey, site) ++ @@ -86,20 +92,22 @@ object ClockingSchemeGenerators { :*= aggregator) val referenceClockSource = ClockSourceNode(Seq(ClockSourceParameters())) + val dividerOnlyClkGenerator = DividerOnlyClockGenerator() // provides all the divided clocks (from the top-level clock) (aggregator := ClockGroupFrequencySpecifier(p(ClockFrequencyAssignersKey), p(DefaultClockFrequencyKey)) := ClockGroupResetSynchronizer() - := DividerOnlyClockGenerator() + := dividerOnlyClkGenerator.node := referenceClockSource) - InModuleBody { val clock_wire = Wire(Input(Clock())) val reset_wire = GenerateReset(chiptop, clock_wire) val (clock_io, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, "clock") chiptop.iocells ++= clockIOCell + p(ReferenceClockTrackerKey).set(dividerOnlyClkGenerator.module.referenceFreq) + referenceClockSource.out.unzip._1.map { o => o.clock := clock_wire o.reset := reset_wire diff --git a/generators/chipyard/src/main/scala/TestHarness.scala b/generators/chipyard/src/main/scala/TestHarness.scala index c638c081..34e2b1ca 100644 --- a/generators/chipyard/src/main/scala/TestHarness.scala +++ b/generators/chipyard/src/main/scala/TestHarness.scala @@ -1,12 +1,16 @@ package chipyard import chisel3._ -import scala.collection.mutable.{ArrayBuffer} + +import scala.collection.mutable.{ArrayBuffer, HashMap} import freechips.rocketchip.diplomacy.{LazyModule} import freechips.rocketchip.config.{Field, Parameters} +import freechips.rocketchip.util.{ResetCatchAndSync} +import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters, ClockSinkParameters, ClockParameters} import chipyard.harness.{ApplyHarnessBinders, HarnessBinders} import chipyard.iobinders.HasIOBinders +import chipyard.clocking.{SimplePllConfiguration, ClockDividerN} // ------------------------------- // Chipyard Test Harness @@ -25,6 +29,46 @@ trait HasHarnessSignalReferences { def success: Bool } +class HarnessClockInstantiator { + private var _clockMap: HashMap[String, (Double, ClockBundle)] = HashMap.empty + + // request a clock bundle at a particular frequency + def getClockBundleWire(name: String, freqRequested: Double): ClockBundle = { + val clockBundle = Wire(new ClockBundle(ClockBundleParameters())) + _clockMap(name) = (freqRequested, clockBundle) + clockBundle + } + + // connect all clock wires specified to a divider only PLL + def instantiateHarnessDividerPLL(refClock: ClockBundle): Unit = { + val sinks = _clockMap.map({ case (name, (freq, bundle)) => + ClockSinkParameters(take=Some(ClockParameters(freqMHz=freq/1000000)),name=Some(name)) + }).toSeq + + val pllConfig = new SimplePllConfiguration("harnessDividerOnlyClockGenerator", sinks) + pllConfig.emitSummaries() + + val dividedClocks = HashMap[Int, Clock]() + def instantiateDivider(div: Int): Clock = { + val divider = Module(new ClockDividerN(div)) + divider.suggestName(s"ClockDivideBy${div}") + divider.io.clk_in := refClock.clock + dividedClocks(div) = divider.io.clk_out + divider.io.clk_out + } + + // connect wires to clock source + for (sinkParams <- sinks) { + val div = pllConfig.sinkDividerMap(sinkParams) + val divClock = dividedClocks.getOrElse(div, instantiateDivider(div)) + _clockMap(sinkParams.name.get)._2.clock := divClock + _clockMap(sinkParams.name.get)._2.reset := ResetCatchAndSync(divClock, refClock.reset.asBool) + } + } +} + +case object HarnessClockInstantiatorKey extends Field[HarnessClockInstantiator](new HarnessClockInstantiator) + class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSignalReferences { val io = IO(new Bundle { val success = Output(Bool()) @@ -34,17 +78,23 @@ class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSign val dut = Module(lazyDut.module) io.success := false.B - val harnessClock = clock - val harnessReset = WireInit(reset) + val (harnessClock, harnessReset, dutReset) = { + val freqMHz = p(ReferenceClockTrackerKey).get.getOrElse(100.0) // default to 100MHz + val bundle = p(HarnessClockInstantiatorKey).getClockBundleWire("implicit_harness_clock", freqMHz*1000000.0) + (bundle.clock, WireInit(bundle.reset), bundle.reset.asAsyncReset) + } val success = io.success - val dutReset = reset.asAsyncReset - lazyDut match { case d: HasTestHarnessFunctions => d.harnessFunctions.foreach(_(this)) } lazyDut match { case d: HasIOBinders => ApplyHarnessBinders(this, d.lazySystem, d.portMap) } + + val implicitHarnessClockBundle = Wire(new ClockBundle(ClockBundleParameters())) + implicitHarnessClockBundle.clock := clock + implicitHarnessClockBundle.reset := reset + p(HarnessClockInstantiatorKey).instantiateHarnessDividerPLL(implicitHarnessClockBundle) } diff --git a/generators/chipyard/src/main/scala/clocking/DividerOnlyClockGenerator.scala b/generators/chipyard/src/main/scala/clocking/DividerOnlyClockGenerator.scala index 2b666196..00cb6814 100644 --- a/generators/chipyard/src/main/scala/clocking/DividerOnlyClockGenerator.scala +++ b/generators/chipyard/src/main/scala/clocking/DividerOnlyClockGenerator.scala @@ -146,5 +146,5 @@ class DividerOnlyClockGenerator(pllName: String)(implicit p: Parameters, valName } object DividerOnlyClockGenerator { - def apply()(implicit p: Parameters, valName: ValName) = LazyModule(new DividerOnlyClockGenerator(valName.name)).node + def apply()(implicit p: Parameters, valName: ValName) = LazyModule(new DividerOnlyClockGenerator(valName.name)) } From 60a616e3202166731e2ad6036b1e4644cde5db04 Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Fri, 5 Mar 2021 00:08:02 -0800 Subject: [PATCH 09/30] 1st pass at connecting to harness PLL | Put UART adapter on harnessClock/Reset --- .../src/main/scala/HarnessBinders.scala | 28 +++++++----- .../chipyard/src/main/scala/IOBinders.scala | 45 +------------------ .../chipyard/src/main/scala/TestHarness.scala | 1 + .../src/main/scala/config/RocketConfigs.scala | 4 -- generators/testchipip | 2 +- 5 files changed, 19 insertions(+), 61 deletions(-) diff --git a/generators/chipyard/src/main/scala/HarnessBinders.scala b/generators/chipyard/src/main/scala/HarnessBinders.scala index 505cded7..39d469a6 100644 --- a/generators/chipyard/src/main/scala/HarnessBinders.scala +++ b/generators/chipyard/src/main/scala/HarnessBinders.scala @@ -21,7 +21,7 @@ import barstools.iocell.chisel._ import testchipip._ -import chipyard.HasHarnessSignalReferences +import chipyard.{HasHarnessSignalReferences, HarnessClockInstantiatorKey} import chipyard.iobinders.GetSystemParameters import tracegen.{TraceGenSystemModuleImp} @@ -83,7 +83,9 @@ class WithGPIOTiedOff extends OverrideHarnessBinder({ // DOC include start: WithUARTAdapter class WithUARTAdapter extends OverrideHarnessBinder({ (system: HasPeripheryUARTModuleImp, th: HasHarnessSignalReferences, ports: Seq[UARTPortIO]) => { - UARTAdapter.connect(ports)(system.p) + withClockAndReset(th.harnessClock, th.harnessReset) { + UARTAdapter.connect(ports)(system.p) + } } }) // DOC include end: WithUARTAdapter @@ -140,7 +142,7 @@ class WithSimAXIMem extends OverrideHarnessBinder({ }) class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({ - (system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[SerialAndPassthroughClockResetIO]) => { + (system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { implicit val p = chipyard.iobinders.GetSystemParameters(system) p(SerialTLKey).map({ sVal => @@ -148,26 +150,28 @@ class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({ require(sVal.axiMemOverSerialTLParams.isDefined) val axiDomainParams = sVal.axiMemOverSerialTLParams.get - val memFreq = axiDomainParams.axiClockParams match { - case Some(clkParams) => { - BigInt(clkParams.clockFreqMHz.toInt)*1000000 - } + val memFreq: Double = axiDomainParams.axiClockParams match { + case Some(clkParams) => clkParams.clockFreqMHz * 1000000 case None => { - // get freq. from what the master bus specifies - system.asInstanceOf[HasTileLinkLocations].locateTLBusWrapper(p(SerialTLAttachKey).masterWhere).dtsFrequency.get + // get freq. from what the master of the serial link specifies + system.asInstanceOf[HasTileLinkLocations].locateTLBusWrapper(p(SerialTLAttachKey).masterWhere).dtsFrequency.get.toDouble } } ports.map({ port => - val harnessMultiClockAXIRAM = SerialAdapter.connectHarnessMultiClockAXIRAM(system.serdesser.get, port, th.harnessReset) - val success = SerialAdapter.connectSimSerial(harnessMultiClockAXIRAM.module.io.tsi_ser, port.clocked_serial.clock, th.harnessReset.asBool) + val harnessMultiClockAXIRAM = SerialAdapter.connectHarnessMultiClockAXIRAM( + system.serdesser.get, + port, + p(HarnessClockInstantiatorKey).getClockBundleWire("mem_over_serial_tl_clock", memFreq), + th.harnessReset) + val success = SerialAdapter.connectSimSerial(harnessMultiClockAXIRAM.module.io.tsi_ser, port.clock, th.harnessReset.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 lineSize = p(CacheBlockBytes) - val mem = Module(new SimDRAM(memSize, lineSize, memFreq, edge.bundle)).suggestName("simdram") + val mem = Module(new SimDRAM(memSize, lineSize, BigInt(memFreq.toInt), edge.bundle)).suggestName("simdram") mem.io.axi <> axi_port.bits mem.io.clock := axi_port.clock mem.io.reset := axi_port.reset diff --git a/generators/chipyard/src/main/scala/IOBinders.scala b/generators/chipyard/src/main/scala/IOBinders.scala index 5621382e..c55d86e0 100644 --- a/generators/chipyard/src/main/scala/IOBinders.scala +++ b/generators/chipyard/src/main/scala/IOBinders.scala @@ -11,7 +11,7 @@ import freechips.rocketchip.subsystem._ import freechips.rocketchip.system.{SimAXIMem} import freechips.rocketchip.amba.axi4.{AXI4Bundle, AXI4SlaveNode, AXI4MasterNode, AXI4EdgeParameters} import freechips.rocketchip.util._ -import freechips.rocketchip.prci.{ClockSinkNode, ClockSinkParameters, ClockParameters, ClockGroup, ClockBundle, ClockBundleParameters} +import freechips.rocketchip.prci.{ClockSinkNode, ClockSinkParameters} import freechips.rocketchip.groundtest.{GroundTestSubsystemModuleImp, GroundTestSubsystem} import sifive.blocks.devices.gpio._ @@ -260,49 +260,6 @@ class WithSerialTLIOCells extends OverrideIOBinder({ }).getOrElse((Nil, Nil)) }) -class WithSerialTLAndPassthroughClockPunchthrough extends OverrideLazyIOBinder({ - (system: CanHavePeripheryTLSerial) => system.serial_tl.map({ serial_io => - implicit val p: Parameters = GetSystemParameters(system) - - val sys = system.asInstanceOf[BaseSubsystem] - - require(p(SerialTLKey).isDefined) - val sVal = p(SerialTLKey).get - - // currently only the harness AXI port supports a passthrough clock - require(sVal.axiMemOverSerialTLParams.isDefined) - val axiDomainParams = sVal.axiMemOverSerialTLParams.get - - val clockSinkNode = axiDomainParams.axiClockParams.map({ clkParams => - // request clock to pass along - val node = ClockSinkNode(Seq(ClockSinkParameters(take = Some(ClockParameters(freqMHz = clkParams.clockFreqMHz))))) - (node - := ClockGroup()(p, ValName("mem_over_serialtl_domain")) - := sys.asyncClockGroupsNode) - node - }) - - def clockBundle = clockSinkNode match { - case Some(node) => node.in.head._1 - case None => { - val dontCareClockBundle = new ClockBundle(ClockBundleParameters()) - dontCareClockBundle.clock := DontCare - dontCareClockBundle.reset := DontCare - dontCareClockBundle - } - } - - InModuleBody { - val port = IO(new SerialAndPassthroughClockResetIO(sVal.width)).suggestName(s"serial_tl_passthrough_clk") - port.clocked_serial <> serial_io - port.passthrough_clock_reset <> clockBundle - - // return the ports and no IO cells - (Seq(port), Nil) - } - }).getOrElse(InModuleBody{(Nil, Nil)}).asInstanceOf[ModuleValue[IOBinderTuple]] -}) - class WithAXI4MemPunchthrough extends OverrideLazyIOBinder({ (system: CanHaveMasterAXI4MemPort) => { implicit val p: Parameters = GetSystemParameters(system) diff --git a/generators/chipyard/src/main/scala/TestHarness.scala b/generators/chipyard/src/main/scala/TestHarness.scala index 34e2b1ca..981f7569 100644 --- a/generators/chipyard/src/main/scala/TestHarness.scala +++ b/generators/chipyard/src/main/scala/TestHarness.scala @@ -57,6 +57,7 @@ class HarnessClockInstantiator { divider.io.clk_out } + // TODO: on the implicit clock just create a passthrough (don't instantiate a divider + reset catch) // connect wires to clock source for (sinkParams <- sinks) { val div = pllConfig.sinkDividerMap(sinkParams) diff --git a/generators/chipyard/src/main/scala/config/RocketConfigs.scala b/generators/chipyard/src/main/scala/config/RocketConfigs.scala index 612b7ae6..7f7fe165 100644 --- a/generators/chipyard/src/main/scala/config/RocketConfigs.scala +++ b/generators/chipyard/src/main/scala/config/RocketConfigs.scala @@ -228,11 +228,7 @@ class MulticlockAXIOverSerialConfig extends Config( new testchipip.WithAsynchronousSerialSlaveCrossing ++ new chipyard.harness.WithSimAXIMemOverSerialTL ++ // add SimDRAM DRAM model for axi4 backing memory over the SerDes link, if axi4 mem is enabled - new chipyard.iobinders.WithSerialTLAndPassthroughClockPunchthrough ++ // add new clock for axi domain over serdes and passthrough ios new chipyard.config.WithSerialTLBackingMemory ++ // remove axi4 mem port in favor of SerialTL memory - new testchipip.WithBlockDeviceLocations( - freechips.rocketchip.subsystem.PBUS, - freechips.rocketchip.subsystem.PBUS) ++ // put block device fully on PBUS to avoid clock crossings new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) diff --git a/generators/testchipip b/generators/testchipip index 3de5c07d..927709c0 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit 3de5c07d054ec301499e75374f3ae2c2cea3930c +Subproject commit 927709c09e404c64108bb909f894e35c9a63396c From 2b7e359326a77980b5f61969d6bcf76523ef4727 Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Fri, 5 Mar 2021 12:25:59 -0800 Subject: [PATCH 10/30] Cleanup config + fragments | Remove reference clk div/rst catch in harness [ci skip] --- .../src/main/scala/ConfigFragments.scala | 9 ++++++-- .../src/main/scala/HarnessBinders.scala | 4 +--- .../chipyard/src/main/scala/TestHarness.scala | 14 +++++++---- .../src/main/scala/config/RocketConfigs.scala | 23 ++++++++++--------- 4 files changed, 30 insertions(+), 20 deletions(-) diff --git a/generators/chipyard/src/main/scala/ConfigFragments.scala b/generators/chipyard/src/main/scala/ConfigFragments.scala index 8f9ab029..10c5d7e3 100644 --- a/generators/chipyard/src/main/scala/ConfigFragments.scala +++ b/generators/chipyard/src/main/scala/ConfigFragments.scala @@ -205,8 +205,13 @@ class WithSerialTLBackingMemory extends Config((site, here, up) => { )} }) -class WithTileFrequency(fMHz: Double) extends ClockNameContainsAssignment("tile", fMHz) -class WithSpecificTileFrequency(hartId: Int, fMHz: Double) extends chipyard.ClockNameContainsAssignment(s"tile_$hartId", fMHz) +class WithTileFrequency(fMHz: Double, hartId: Option[Int] = None) extends ClockNameContainsAssignment({ + hartId match { + case Some(id) => s"tile_$id" + case None => "tile" + } + }, + fMHz) class WithPeripheryBusFrequencyAsDefault extends Config((site, here, up) => { case DefaultClockFrequencyKey => (site(PeripheryBusKey).dtsFrequency.get / (1000 * 1000)).toDouble diff --git a/generators/chipyard/src/main/scala/HarnessBinders.scala b/generators/chipyard/src/main/scala/HarnessBinders.scala index 39d469a6..bdff8995 100644 --- a/generators/chipyard/src/main/scala/HarnessBinders.scala +++ b/generators/chipyard/src/main/scala/HarnessBinders.scala @@ -83,9 +83,7 @@ class WithGPIOTiedOff extends OverrideHarnessBinder({ // DOC include start: WithUARTAdapter class WithUARTAdapter extends OverrideHarnessBinder({ (system: HasPeripheryUARTModuleImp, th: HasHarnessSignalReferences, ports: Seq[UARTPortIO]) => { - withClockAndReset(th.harnessClock, th.harnessReset) { - UARTAdapter.connect(ports)(system.p) - } + UARTAdapter.connect(ports)(system.p) } }) // DOC include end: WithUARTAdapter diff --git a/generators/chipyard/src/main/scala/TestHarness.scala b/generators/chipyard/src/main/scala/TestHarness.scala index 981f7569..c0c28088 100644 --- a/generators/chipyard/src/main/scala/TestHarness.scala +++ b/generators/chipyard/src/main/scala/TestHarness.scala @@ -57,13 +57,19 @@ class HarnessClockInstantiator { divider.io.clk_out } - // TODO: on the implicit clock just create a passthrough (don't instantiate a divider + reset catch) // connect wires to clock source for (sinkParams <- sinks) { - val div = pllConfig.sinkDividerMap(sinkParams) - val divClock = dividedClocks.getOrElse(div, instantiateDivider(div)) + // bypass the reference freq. (don't create a divider + reset sync) + val (divClock, divReset) = if (sinkParams.take.get.freqMHz != pllConfig.referenceFreqMHz) { + val div = pllConfig.sinkDividerMap(sinkParams) + val divClock = dividedClocks.getOrElse(div, instantiateDivider(div)) + (divClock, ResetCatchAndSync(divClock, refClock.reset.asBool)) + } else { + (refClock.clock, refClock.reset) + } + _clockMap(sinkParams.name.get)._2.clock := divClock - _clockMap(sinkParams.name.get)._2.reset := ResetCatchAndSync(divClock, refClock.reset.asBool) + _clockMap(sinkParams.name.get)._2.reset := divReset } } } diff --git a/generators/chipyard/src/main/scala/config/RocketConfigs.scala b/generators/chipyard/src/main/scala/config/RocketConfigs.scala index 7f7fe165..cbb8f06b 100644 --- a/generators/chipyard/src/main/scala/config/RocketConfigs.scala +++ b/generators/chipyard/src/main/scala/config/RocketConfigs.scala @@ -1,8 +1,7 @@ package chipyard import freechips.rocketchip.config.{Config} -import freechips.rocketchip.diplomacy.{AsynchronousCrossing, RationalCrossing} -import freechips.rocketchip.util.{SlowToFast} +import freechips.rocketchip.diplomacy.{AsynchronousCrossing} // -------------- // Rocket Configs @@ -215,20 +214,22 @@ class LBWIFRocketConfig extends Config( new chipyard.config.AbstractConfig) class MulticlockAXIOverSerialConfig extends Config( - new chipyard.config.WithFbusToSbusCrossingType(RationalCrossing(SlowToFast)) ++ - new chipyard.config.WithSystemBusFrequencyAsDefault ++ - new chipyard.config.WithSystemBusFrequency(4000) ++ - new chipyard.config.WithPeripheryBusFrequency(4000) ++ - new chipyard.config.WithMemoryBusFrequency(4000) ++ + new chipyard.config.WithSystemBusFrequency(500) ++ + new chipyard.config.WithPeripheryBusFrequency(500) ++ + new chipyard.config.WithMemoryBusFrequency(500) ++ + new chipyard.config.WithFrontBusFrequency(50) ++ + new chipyard.config.WithTileFrequency(1000, Some(1)) ++ + new chipyard.config.WithTileFrequency(250, Some(0)) ++ - new chipyard.config.WithFrontBusFrequency(4000 / 2) ++ - - new chipyard.config.WithFbusToSbusCrossingType(RationalCrossing(SlowToFast)) ++ + new chipyard.config.WithFbusToSbusCrossingType(AsynchronousCrossing()) ++ new testchipip.WithAsynchronousSerialSlaveCrossing ++ + new freechips.rocketchip.subsystem.WithAsynchronousRocketTiles( + AsynchronousCrossing().depth, + AsynchronousCrossing().sourceSync) ++ new chipyard.harness.WithSimAXIMemOverSerialTL ++ // add SimDRAM DRAM model for axi4 backing memory over the SerDes link, if axi4 mem is enabled new chipyard.config.WithSerialTLBackingMemory ++ // remove axi4 mem port in favor of SerialTL memory - new freechips.rocketchip.subsystem.WithNBigCores(1) ++ + new freechips.rocketchip.subsystem.WithNBigCores(2) ++ new chipyard.config.AbstractConfig) From 562d8e51165e310f7992112193116becb0c1da88 Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Fri, 5 Mar 2021 16:31:18 -0800 Subject: [PATCH 11/30] Distinguish between implicit clock/reset and reference harnessClock/Reset | Don't use parameter system to pass referenceFreq --- .../chipyard/src/main/scala/ChipTop.scala | 5 ++++- .../chipyard/src/main/scala/Clocks.scala | 9 ++------ .../chipyard/src/main/scala/TestHarness.scala | 21 ++++++++++++++----- .../src/main/scala/config/RocketConfigs.scala | 8 +++---- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/generators/chipyard/src/main/scala/ChipTop.scala b/generators/chipyard/src/main/scala/ChipTop.scala index 205135a2..e6cfa8cb 100644 --- a/generators/chipyard/src/main/scala/ChipTop.scala +++ b/generators/chipyard/src/main/scala/ChipTop.scala @@ -15,6 +15,9 @@ import barstools.iocell.chisel._ case object BuildSystem extends Field[Parameters => LazyModule]((p: Parameters) => new DigitalTop()(p)) +trait HasReferenceClockFreq { + var refClockFreqMHz: Option[Double] = None +} /** * The base class used for building chips. This constructor instantiates a module specified by the BuildSystem parameter, @@ -24,7 +27,7 @@ case object BuildSystem extends Field[Parameters => LazyModule]((p: Parameters) */ class ChipTop(implicit p: Parameters) extends LazyModule with BindingScope - with HasTestHarnessFunctions with HasIOBinders { + with HasTestHarnessFunctions with HasReferenceClockFreq with HasIOBinders { // The system module specified by BuildSystem lazy val lazySystem = LazyModule(p(BuildSystem)(p)).suggestName("system") diff --git a/generators/chipyard/src/main/scala/Clocks.scala b/generators/chipyard/src/main/scala/Clocks.scala index 65346ea6..00c07417 100644 --- a/generators/chipyard/src/main/scala/Clocks.scala +++ b/generators/chipyard/src/main/scala/Clocks.scala @@ -47,12 +47,6 @@ case object ClockingSchemeKey extends Field[ChipTop => Unit](ClockingSchemeGener */ case object ClockFrequencyAssignersKey extends Field[Seq[(String) => Option[Double]]](Seq.empty) case object DefaultClockFrequencyKey extends Field[Double]() -case object ReferenceClockTrackerKey extends Field[ReferenceClockTracker](new ReferenceClockTracker) -class ReferenceClockTracker { - private var _refFreqMHz: Option[Double] = None - def set(freqMHz: Double): Unit = { _refFreqMHz = Some(freqMHz) } - def get: Option[Double] = { _refFreqMHz } -} class ClockNameMatchesAssignment(name: String, fMHz: Double) extends Config((site, here, up) => { case ClockFrequencyAssignersKey => up(ClockFrequencyAssignersKey, site) ++ @@ -106,7 +100,8 @@ object ClockingSchemeGenerators { val (clock_io, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, "clock") chiptop.iocells ++= clockIOCell - p(ReferenceClockTrackerKey).set(dividerOnlyClkGenerator.module.referenceFreq) + // set the reference clock used + chiptop.refClockFreqMHz = Some(dividerOnlyClkGenerator.module.referenceFreq) referenceClockSource.out.unzip._1.map { o => o.clock := clock_wire diff --git a/generators/chipyard/src/main/scala/TestHarness.scala b/generators/chipyard/src/main/scala/TestHarness.scala index c0c28088..c02df03e 100644 --- a/generators/chipyard/src/main/scala/TestHarness.scala +++ b/generators/chipyard/src/main/scala/TestHarness.scala @@ -23,6 +23,7 @@ trait HasTestHarnessFunctions { } trait HasHarnessSignalReferences { + // clock/reset of the chiptop reference clock (can be different than the implicit harness clock/reset) def harnessClock: Clock def harnessReset: Reset def dutReset: Reset @@ -81,15 +82,25 @@ class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSign val success = Output(Bool()) }) + val harnessClock = Wire(Clock()) + val harnessReset = Wire(Reset()) + val lazyDut = LazyModule(p(BuildTop)(p)).suggestName("chiptop") - val dut = Module(lazyDut.module) + withClockAndReset(harnessClock, harnessReset) { + val dut = Module(lazyDut.module) + } io.success := false.B - val (harnessClock, harnessReset, dutReset) = { - val freqMHz = p(ReferenceClockTrackerKey).get.getOrElse(100.0) // default to 100MHz - val bundle = p(HarnessClockInstantiatorKey).getClockBundleWire("implicit_harness_clock", freqMHz*1000000.0) - (bundle.clock, WireInit(bundle.reset), bundle.reset.asAsyncReset) + val freqMHz = lazyDut match { + case d: HasReferenceClockFreq => d.refClockFreqMHz.getOrElse(p(DefaultClockFrequencyKey)) + case _ => p(DefaultClockFrequencyKey) } + val refClkBundle = p(HarnessClockInstantiatorKey).getClockBundleWire("chiptop_reference_clock", freqMHz * (1000 * 1000)) + + harnessClock := refClkBundle.clock + harnessReset := WireInit(refClkBundle.reset) + val dutReset = refClkBundle.reset.asAsyncReset + val success = io.success lazyDut match { case d: HasTestHarnessFunctions => diff --git a/generators/chipyard/src/main/scala/config/RocketConfigs.scala b/generators/chipyard/src/main/scala/config/RocketConfigs.scala index cbb8f06b..45f016bf 100644 --- a/generators/chipyard/src/main/scala/config/RocketConfigs.scala +++ b/generators/chipyard/src/main/scala/config/RocketConfigs.scala @@ -215,11 +215,11 @@ class LBWIFRocketConfig extends Config( class MulticlockAXIOverSerialConfig extends Config( new chipyard.config.WithSystemBusFrequencyAsDefault ++ - new chipyard.config.WithSystemBusFrequency(500) ++ - new chipyard.config.WithPeripheryBusFrequency(500) ++ - new chipyard.config.WithMemoryBusFrequency(500) ++ + new chipyard.config.WithSystemBusFrequency(250) ++ + new chipyard.config.WithPeripheryBusFrequency(250) ++ + new chipyard.config.WithMemoryBusFrequency(250) ++ new chipyard.config.WithFrontBusFrequency(50) ++ - new chipyard.config.WithTileFrequency(1000, Some(1)) ++ + new chipyard.config.WithTileFrequency(500, Some(1)) ++ new chipyard.config.WithTileFrequency(250, Some(0)) ++ new chipyard.config.WithFbusToSbusCrossingType(AsynchronousCrossing()) ++ From 6ab8f8f8fc776f9adcd6172349f7715124027a0c Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Mon, 8 Mar 2021 22:03:07 +0000 Subject: [PATCH 12/30] Update FireSim to support harness clocks | Small config renaming --- .../chipyard/src/main/scala/TestHarness.scala | 2 +- .../clocking/DividerOnlyClockGenerator.scala | 1 + .../src/main/scala/BridgeBinders.scala | 39 +++-- .../firechip/src/main/scala/FireSim.scala | 146 ++++++++++++++---- .../src/main/scala/TargetConfigs.scala | 7 +- generators/testchipip | 2 +- 6 files changed, 149 insertions(+), 48 deletions(-) diff --git a/generators/chipyard/src/main/scala/TestHarness.scala b/generators/chipyard/src/main/scala/TestHarness.scala index c02df03e..4c5dd4f6 100644 --- a/generators/chipyard/src/main/scala/TestHarness.scala +++ b/generators/chipyard/src/main/scala/TestHarness.scala @@ -95,7 +95,7 @@ class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSign case d: HasReferenceClockFreq => d.refClockFreqMHz.getOrElse(p(DefaultClockFrequencyKey)) case _ => p(DefaultClockFrequencyKey) } - val refClkBundle = p(HarnessClockInstantiatorKey).getClockBundleWire("chiptop_reference_clock", freqMHz * (1000 * 1000)) + val refClkBundle = p(HarnessClockInstantiatorKey).getClockBundleWire("buildtop_reference_clock", freqMHz * (1000 * 1000)) harnessClock := refClkBundle.clock harnessReset := WireInit(refClkBundle.reset) diff --git a/generators/chipyard/src/main/scala/clocking/DividerOnlyClockGenerator.scala b/generators/chipyard/src/main/scala/clocking/DividerOnlyClockGenerator.scala index 00cb6814..589d99c6 100644 --- a/generators/chipyard/src/main/scala/clocking/DividerOnlyClockGenerator.scala +++ b/generators/chipyard/src/main/scala/clocking/DividerOnlyClockGenerator.scala @@ -89,6 +89,7 @@ class SimplePllConfiguration( ElaborationArtefacts.add(s"${name}.freq-summary", summaryString) println(summaryString) } + def referenceSinkParams(): ClockSinkParameters = sinkDividerMap.find(_._2 == 1).get._1 } case class DividerOnlyClockGeneratorNode(pllName: String)(implicit valName: ValName) diff --git a/generators/firechip/src/main/scala/BridgeBinders.scala b/generators/firechip/src/main/scala/BridgeBinders.scala index b6b3caf9..174ea5bb 100644 --- a/generators/firechip/src/main/scala/BridgeBinders.scala +++ b/generators/firechip/src/main/scala/BridgeBinders.scala @@ -12,6 +12,8 @@ import freechips.rocketchip.devices.debug.{Debug, HasPeripheryDebugModuleImp} import freechips.rocketchip.amba.axi4.{AXI4Bundle} import freechips.rocketchip.subsystem._ import freechips.rocketchip.tile.{RocketTile} +import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters} +import freechips.rocketchip.util.{ResetCatchAndSync} import sifive.blocks.devices.uart._ import testchipip._ @@ -104,24 +106,43 @@ class WithBlockDeviceBridge extends OverrideHarnessBinder({ }) class WithAXIOverSerialTLCombinedBridges extends OverrideHarnessBinder({ - (system: CanHavePeripheryTLSerial, th: FireSim, ports: Seq[SerialAndPassthroughClockResetIO]) => { + (system: CanHavePeripheryTLSerial, th: FireSim, ports: Seq[ClockedIO[SerialIO]]) => { implicit val p = GetSystemParameters(system) p(SerialTLKey).map({ sVal => - // require having memory over the serdes link + // currently only the harness AXI port supports a passthrough clock + require(sVal.axiMemOverSerialTLParams.isDefined) + val axiDomainParams = sVal.axiMemOverSerialTLParams.get require(sVal.isMemoryDevice) + val memFreq: Double = axiDomainParams.axiClockParams match { + case Some(clkParams) => clkParams.clockFreqMHz * 1000000 + case None => { + // get freq. from what the master of the serial link specifies + system.asInstanceOf[HasTileLinkLocations].locateTLBusWrapper(p(SerialTLAttachKey).masterWhere).dtsFrequency.get.toDouble + } + } + ports.map({ port => - val offchipNetwork = SerialAdapter.connectHarnessMultiClockAXIRAM(system.serdesser.get, port, th.harnessReset) - SerialBridge(port.clocked_serial.clock, offchipNetwork.module.io.tsi_ser, Some(MainMemoryConsts.globalName)) + val axiClock = p(ClockBridgeInstantiatorKey).getClock("mem_over_serial_tl_clock", memFreq) + val axiClockBundle = Wire(new ClockBundle(ClockBundleParameters())) + axiClockBundle.clock := axiClock + axiClockBundle.reset := ResetCatchAndSync(axiClock, th.harnessReset.asBool) + + val harnessMultiClockAXIRAM = SerialAdapter.connectHarnessMultiClockAXIRAM( + system.serdesser.get, + port, + axiClockBundle, + th.harnessReset) + SerialBridge(port.clock, harnessMultiClockAXIRAM.module.io.tsi_ser, Some(MainMemoryConsts.globalName)) // connect SimAxiMem - (offchipNetwork.mem_axi4 zip offchipNetwork.memAXI4Node.edges.in).map { case (axi4, edge) => - val nastiKey = NastiParameters(axi4.r.bits.data.getWidth, - axi4.ar.bits.addr.getWidth, - axi4.ar.bits.id.getWidth) + (harnessMultiClockAXIRAM.mem_axi4 zip harnessMultiClockAXIRAM.memNode.edges.in).map { case (axi4, edge) => + val nastiKey = NastiParameters(axi4.bits.r.bits.data.getWidth, + axi4.bits.ar.bits.addr.getWidth, + axi4.bits.ar.bits.id.getWidth) system match { - case s: BaseSubsystem => FASEDBridge(port.passthrough_clock_reset.clock, axi4, port.passthrough_clock_reset.reset.asBool, + case s: BaseSubsystem => FASEDBridge(axi4.clock, axi4.bits, axi4.reset.asBool, CompleteConfig(p(firesim.configs.MemModelKey), nastiKey, Some(AXI4EdgeSummary(edge)), diff --git a/generators/firechip/src/main/scala/FireSim.scala b/generators/firechip/src/main/scala/FireSim.scala index ff765970..b1498a5b 100644 --- a/generators/firechip/src/main/scala/FireSim.scala +++ b/generators/firechip/src/main/scala/FireSim.scala @@ -2,6 +2,8 @@ package firesim.firesim +import scala.collection.mutable.{HashMap} + import chisel3._ import chisel3.experimental.{IO} @@ -38,44 +40,104 @@ object NodeIdx { /** * 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 + * 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 var _clockRecord: Option[RecordMap[Clock]] = None + private var _harnessClockMap: HashMap[String, (Double, Clock)] = HashMap.empty - def getClockRecord: RecordMap[Clock] = _clockRecord.get + // Assumes that the supernode implementation results in duplicated clocks + // (i.e. only 1 set of clocks is generated for all BuildTop designs) + private var _ratClockMap: HashMap[String, (RationalClock, Clock)] = HashMap.empty + private var _ratRefName: Option[String] = None - def getClockRecordOrInstantiate(allClocks: Seq[RationalClock], baseClockName: String): RecordMap[Clock] = { - if (_clockRecord.isEmpty) { - require(allClocks.exists(_.name == baseClockName), - s"Provided base-clock name, ${baseClockName}, does not match a defined clock. Available clocks:\n " + - allClocks.map(_.name).mkString("\n ")) + /** + * 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 getClock(name: String, freqRequested: Double): Clock = { + val clkWire = Wire(new Clock) + _harnessClockMap(name) = (freqRequested, clkWire) + clkWire + } - val baseClock = allClocks.find(_.name == baseClockName).get - val simplified = allClocks.map { c => - c.copy(multiplier = c.multiplier * baseClock.divisor, divisor = c.divisor * baseClock.multiplier) - .simplify - } + /** + * Get a RecordMap of clocks for a set of input RationalClocks + * + * @param allClocks Seq. of RationalClocks that want a clock + * + * @param baseClockName Name of domain that the allClocks is rational to + */ + def getClockRecordMap(allClocks: Seq[RationalClock], baseClockName: String): RecordMap[Clock] = { + val ratClockRecordMapWire = Wire(RecordMap(allClocks.map { c => (c.name, Clock()) }:_*)) - /** - * Removes clocks that have the same frequency before instantiating the - * clock bridge to avoid unnecessary BUFGCE use. - */ - val distinct = simplified.foldLeft(Seq(RationalClock(baseClockName, 1, 1))) { case (list, candidate) => - if (list.exists { clock => clock.equalFrequency(candidate) }) list else list :+ candidate - } - - val clockBridge = Module(new RationalClockBridge(distinct)) - val cbVecTuples = distinct.zip(clockBridge.io.clocks) - val outputWire = Wire(RecordMap(simplified.map { c => (c.name, Clock()) }:_*)) - for (parameter <- simplified) { - val (_, cbClockField) = cbVecTuples.find(_._1.equalFrequency(parameter)).get - outputWire(parameter.name).get := cbClockField - } - _clockRecord = Some(outputWire) + _ratRefName = Some(baseClockName) + for (clock <- allClocks) { + val clkWire = Wire(new Clock) + _ratClockMap(clock.name) = (clock, clkWire) + ratClockRecordMapWire(clock.name).get := clkWire + } + + ratClockRecordMapWire + } + + /** + * Connect all clocks requested to ClockBridge + */ + def instantiateFireSimDividerPLL: Unit = { + // Simplify the RationalClocks ratio's + val refRatClock = _ratClockMap.find(_._1 == _ratRefName.get).get._2._1 + val simpleRatClocks = _ratClockMap.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 refRatClockFreq = _harnessClockMap.find(_._1 == _ratRefName.get).get._2._1 + val refRatSinkParams = ClockSinkParameters(take=Some(ClockParameters(freqMHz=refRatClockFreq / (1000 * 1000))),name=Some(_ratRefName.get)) + val harSinkParams = _harnessClockMap.map { case (name, (freq, bundle)) => + ClockSinkParameters(take=Some(ClockParameters(freqMHz=freq / (1000 * 1000))),name=Some(name)) + }.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 + _ratClockMap.get(clock.name).map { case (_, clk) => clk := cbClockField } + _harnessClockMap.get(clock.name).map { case (_, clk) => clk := cbClockField } } - getClockRecord } } @@ -117,16 +179,19 @@ class WithFireSimSimpleClocks extends Config((site, here, up) => { clockBundle.reset := reset } - val pllConfig = new SimplePllConfiguration("FireSim RationalClockBridge", clockGroupEdge.sink.members) + val pllConfig = new SimplePllConfiguration("firesimBuildTopClockGenerator", clockGroupEdge.sink.members) pllConfig.emitSummaries val rationalClockSpecs = for ((sinkP, division) <- pllConfig.sinkDividerMap) yield { RationalClock(sinkP.name.get, 1, division) } + // Set the reference frequency used + chiptop.refClockFreqMHz = Some(pllConfig.referenceFreqMHz) + chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => { reset := th.harnessReset input_clocks := p(ClockBridgeInstantiatorKey) - .getClockRecordOrInstantiate(rationalClockSpecs.toSeq, p(FireSimBaseClockNameKey)) + .getClockRecordMap(rationalClockSpecs.toSeq, p(FireSimBaseClockNameKey)) Nil }) } } @@ -140,6 +205,8 @@ class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSigna def dutReset = { require(false, "dutReset should not be used in Firesim"); false.B } def success = { require(false, "success should not be used in Firesim"); false.B } + var btFreqMHz: Option[Double] = None + // Instantiate multiple instances of the DUT to implement supernode for (i <- 0 until p(NumNodes)) { // It's not a RC bump without some hacks... @@ -150,7 +217,15 @@ class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSigna val lazyModule = LazyModule(p(BuildTop)(p.alterPartial({ case AsyncClockGroupsKey => p(AsyncClockGroupsKey).copy }))) - val module = Module(lazyModule.module) + withClockAndReset(harnessClock, harnessReset) { + val module = Module(lazyModule.module) + } + + btFreqMHz = Some(lazyModule match { + case d: HasReferenceClockFreq => d.refClockFreqMHz.getOrElse(p(DefaultClockFrequencyKey)) + case _ => p(DefaultClockFrequencyKey) + }) + lazyModule match { case d: HasTestHarnessFunctions => require(d.harnessFunctions.size == 1, "There should only be 1 harness function to connect clock+reset") d.harnessFunctions.foreach(_(this)) @@ -160,5 +235,8 @@ class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSigna } NodeIdx.increment() } - harnessClock := p(ClockBridgeInstantiatorKey).getClockRecord("implicit_clock").get + + harnessClock := p(ClockBridgeInstantiatorKey).getClock(p(FireSimBaseClockNameKey), btFreqMHz.get * (1000 * 1000)) + + p(ClockBridgeInstantiatorKey).instantiateFireSimDividerPLL } diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index a7626f32..6be9cc21 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -59,7 +59,7 @@ class WithNIC extends icenet.WithIceNIC(inBufFlits = 8192, ctrlQueueDepth = 64) class WithNVDLALarge extends nvidia.blocks.dla.WithNVDLA("large") class WithNVDLASmall extends nvidia.blocks.dla.WithNVDLA("small") -class WithFireSimConfigTweaksWithoutClocking extends Config( +class WithFireSimDesignTweaks extends Config( // Required: Bake in the default FASED memory model new WithDefaultMemModel ++ // Required*: Uses FireSim ClockBridge and PeekPokeBridge to drive the system with a single clock/reset @@ -96,7 +96,7 @@ class WithFireSimConfigTweaks extends Config( new chipyard.config.WithAsynchrousMemoryBusCrossing ++ new testchipip.WithAsynchronousSerialSlaveCrossing ++ // Tweaks that are independent from multi-clock - new WithFireSimConfigTweaksWithoutClocking + new WithFireSimDesignTweaks ) /******************************************************************************* @@ -207,8 +207,9 @@ class FireSimMulticlockRocketConfig extends Config( class FireSimMulticlockAXIOverSerialConfig extends Config( new WithAXIOverSerialTLCombinedBridges ++ // use combined bridge to connect to axi mem over serial new WithDefaultFireSimBridges ++ + new testchipip.WithBlockDevice(false) ++ // disable blockdev new WithDefaultMemModel ++ - new WithFireSimConfigTweaksWithoutClocking ++ // don't inherit firesim clocking + new WithFireSimDesignTweaks ++ // don't inherit firesim clocking new chipyard.MulticlockAXIOverSerialConfig ) diff --git a/generators/testchipip b/generators/testchipip index 927709c0..03c4ac48 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit 927709c09e404c64108bb909f894e35c9a63396c +Subproject commit 03c4ac486209253aaa20a702842fba511cfeac04 From e4ccfe1bb9b7652db26f658458cfa5632505c1de Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Mon, 8 Mar 2021 23:43:00 +0000 Subject: [PATCH 13/30] Renaming updates | Have FireSim clocks request frequency by default --- .../src/main/scala/HarnessBinders.scala | 2 +- .../chipyard/src/main/scala/TestHarness.scala | 4 +-- .../firechip/src/main/scala/FireSim.scala | 30 ++++++++++++------- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/generators/chipyard/src/main/scala/HarnessBinders.scala b/generators/chipyard/src/main/scala/HarnessBinders.scala index bdff8995..a1f39c6c 100644 --- a/generators/chipyard/src/main/scala/HarnessBinders.scala +++ b/generators/chipyard/src/main/scala/HarnessBinders.scala @@ -160,7 +160,7 @@ class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({ val harnessMultiClockAXIRAM = SerialAdapter.connectHarnessMultiClockAXIRAM( system.serdesser.get, port, - p(HarnessClockInstantiatorKey).getClockBundleWire("mem_over_serial_tl_clock", memFreq), + p(HarnessClockInstantiatorKey).getClockBundle("mem_over_serial_tl_clock", memFreq), th.harnessReset) val success = SerialAdapter.connectSimSerial(harnessMultiClockAXIRAM.module.io.tsi_ser, port.clock, th.harnessReset.asBool) when (success) { th.success := true.B } diff --git a/generators/chipyard/src/main/scala/TestHarness.scala b/generators/chipyard/src/main/scala/TestHarness.scala index 4c5dd4f6..9090086f 100644 --- a/generators/chipyard/src/main/scala/TestHarness.scala +++ b/generators/chipyard/src/main/scala/TestHarness.scala @@ -34,7 +34,7 @@ class HarnessClockInstantiator { private var _clockMap: HashMap[String, (Double, ClockBundle)] = HashMap.empty // request a clock bundle at a particular frequency - def getClockBundleWire(name: String, freqRequested: Double): ClockBundle = { + def getClockBundle(name: String, freqRequested: Double): ClockBundle = { val clockBundle = Wire(new ClockBundle(ClockBundleParameters())) _clockMap(name) = (freqRequested, clockBundle) clockBundle @@ -95,7 +95,7 @@ class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSign case d: HasReferenceClockFreq => d.refClockFreqMHz.getOrElse(p(DefaultClockFrequencyKey)) case _ => p(DefaultClockFrequencyKey) } - val refClkBundle = p(HarnessClockInstantiatorKey).getClockBundleWire("buildtop_reference_clock", freqMHz * (1000 * 1000)) + val refClkBundle = p(HarnessClockInstantiatorKey).getClockBundle("buildtop_reference_clock", freqMHz * (1000 * 1000)) harnessClock := refClkBundle.clock harnessReset := WireInit(refClkBundle.reset) diff --git a/generators/firechip/src/main/scala/FireSim.scala b/generators/firechip/src/main/scala/FireSim.scala index b1498a5b..ca0ab1a0 100644 --- a/generators/firechip/src/main/scala/FireSim.scala +++ b/generators/firechip/src/main/scala/FireSim.scala @@ -49,7 +49,7 @@ class ClockBridgeInstantiator { // Assumes that the supernode implementation results in duplicated clocks // (i.e. only 1 set of clocks is generated for all BuildTop designs) private var _ratClockMap: HashMap[String, (RationalClock, Clock)] = HashMap.empty - private var _ratRefName: Option[String] = None + private var _ratRefTuple: Option[(String, Double)] = None /** * Request a clock at a particular frequency @@ -70,11 +70,15 @@ class ClockBridgeInstantiator { * @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 */ - def getClockRecordMap(allClocks: Seq[RationalClock], baseClockName: String): RecordMap[Clock] = { + def getClockRecordMap(allClocks: Seq[RationalClock], baseClockName: String, baseFreqRequested: Double): RecordMap[Clock] = { + require(!_ratRefTuple.isDefined, "Can only request one RecordMap of Clocks") + val ratClockRecordMapWire = Wire(RecordMap(allClocks.map { c => (c.name, Clock()) }:_*)) - _ratRefName = Some(baseClockName) + _ratRefTuple = Some((baseClockName, baseFreqRequested)) for (clock <- allClocks) { val clkWire = Wire(new Clock) _ratClockMap(clock.name) = (clock, clkWire) @@ -87,9 +91,14 @@ class ClockBridgeInstantiator { /** * Connect all clocks requested to ClockBridge */ - def instantiateFireSimDividerPLL: Unit = { + def instantiateFireSimClockBridge: Unit = { + require(_ratRefTuple.isDefined, "Must have rational clocks to assign to") + require(_ratClockMap.exists(_._1 == _ratRefTuple.get._1), + s"Provided base-clock name for rational clocks, ${_ratRefTuple.get._1}, doesn't match a name within specified rational clocks." + + "Available clocks:\n " + _ratClockMap.map(_._1).mkString("\n ")) + // Simplify the RationalClocks ratio's - val refRatClock = _ratClockMap.find(_._1 == _ratRefName.get).get._2._1 + val refRatClock = _ratClockMap.find(_._1 == _ratRefTuple.get._1).get._2._1 val simpleRatClocks = _ratClockMap.map { t => val ratClock = t._2._1 ratClock.copy( @@ -99,8 +108,8 @@ class ClockBridgeInstantiator { // Determine all the clock dividers (harness + rational clocks) // Note: Requires that the BuildTop reference frequency is requested with proper freq. - val refRatClockFreq = _harnessClockMap.find(_._1 == _ratRefName.get).get._2._1 - val refRatSinkParams = ClockSinkParameters(take=Some(ClockParameters(freqMHz=refRatClockFreq / (1000 * 1000))),name=Some(_ratRefName.get)) + val refRatClockFreq = _ratRefTuple.get._2 + val refRatSinkParams = ClockSinkParameters(take=Some(ClockParameters(freqMHz=refRatClockFreq / (1000 * 1000))),name=Some(_ratRefTuple.get._1)) val harSinkParams = _harnessClockMap.map { case (name, (freq, bundle)) => ClockSinkParameters(take=Some(ClockParameters(freqMHz=freq / (1000 * 1000))),name=Some(name)) }.toSeq @@ -191,7 +200,7 @@ class WithFireSimSimpleClocks extends Config((site, here, up) => { chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => { reset := th.harnessReset input_clocks := p(ClockBridgeInstantiatorKey) - .getClockRecordMap(rationalClockSpecs.toSeq, p(FireSimBaseClockNameKey)) + .getClockRecordMap(rationalClockSpecs.toSeq, p(FireSimBaseClockNameKey), pllConfig.referenceFreqMHz * (1000 * 1000)) Nil }) } } @@ -199,6 +208,7 @@ class WithFireSimSimpleClocks extends Config((site, here, up) => { class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSignalReferences { freechips.rocketchip.util.property.cover.setPropLib(new midas.passes.FireSimPropertyLibrary()) + val harnessClock = Wire(Clock()) val harnessReset = WireInit(false.B) val peekPokeBridge = PeekPokeBridge(harnessClock, harnessReset) @@ -236,7 +246,7 @@ class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSigna NodeIdx.increment() } - harnessClock := p(ClockBridgeInstantiatorKey).getClock(p(FireSimBaseClockNameKey), btFreqMHz.get * (1000 * 1000)) + harnessClock := p(ClockBridgeInstantiatorKey).getClock("buildtop_reference_clock", btFreqMHz.get * (1000 * 1000)) - p(ClockBridgeInstantiatorKey).instantiateFireSimDividerPLL + p(ClockBridgeInstantiatorKey).instantiateFireSimClockBridge } From ade8457870fdf12e8dfd3f47b1a35f23fc634221 Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Tue, 9 Mar 2021 05:11:24 +0000 Subject: [PATCH 14/30] First doc pass (no updated imgs) [ci skip] --- docs/Advanced-Concepts/Chip-Communication.rst | 134 +++++++++++++----- docs/Advanced-Concepts/Harness-Clocks.rst | 20 +++ docs/Advanced-Concepts/index.rst | 1 + .../src/main/scala/HarnessBinders.scala | 2 + .../src/main/scala/config/RocketConfigs.scala | 2 + 5 files changed, 120 insertions(+), 39 deletions(-) create mode 100644 docs/Advanced-Concepts/Harness-Clocks.rst diff --git a/docs/Advanced-Concepts/Chip-Communication.rst b/docs/Advanced-Concepts/Chip-Communication.rst index 50c5ac9a..9084f7ef 100644 --- a/docs/Advanced-Concepts/Chip-Communication.rst +++ b/docs/Advanced-Concepts/Chip-Communication.rst @@ -7,7 +7,7 @@ There are two types of DUTs that can be made: `tethered` or `standalone` DUTs. A `tethered` DUT is where a host computer (or just host) must send transactions to the DUT to bringup a program. This differs from a `standalone` DUT that can bringup itself (has its own bootrom, loads programs itself, etc). An example of a tethered DUT is a Chipyard simulation where the host loads the test program into the DUTs memory and signals to the DUT that the program is ready to run. -An example of a standalone DUT is a Chipyard simulation where a program can be loaded from an SDCard by default. +An example of a standalone DUT is a Chipyard simulation where a program can be loaded from an SDCard out of reset. In this section, we mainly describe how to communicate to tethered DUTs. There are two ways the host (otherwise known as the outside world) can communicate with a tethered Chipyard DUT: @@ -45,33 +45,21 @@ Using the Tethered Serial Interface (TSI) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ By default, Chipyard uses the Tethered Serial Interface (TSI) to communicate with the DUT. -TSI protocol is an implementation of HTIF that is used to send commands to the -RISC-V DUT. These TSI commands are simple R/W commands -that are able to probe the DUT's memory space. During simulation, the host sends TSI commands to a -simulation stub called ``SimSerial`` (C++ class) that resides in a ``SimSerial`` Verilog module -(both are located in the ``generators/testchipip`` project). This ``SimSerial`` Verilog module then -sends the TSI command recieved by the simulation stub into the DUT which then converts the TSI -command into a TileLink request. This conversion is done by the ``SerialAdapter`` module -(located in the ``generators/testchipip`` project). In simulation, FESVR -resets the DUT, writes into memory the test program, and indicates to the DUT to start the program -through an interrupt (see :ref:`customization/Boot-Process:Chipyard Boot Process`). Using TSI is currently the fastest -mechanism to communicate with the DUT in simulation. - -In the case of a chip tapeout bringup, TSI commands can be sent over a custom communication -medium to communicate with the chip. For example, some Berkeley tapeouts have a FPGA -with a RISC-V soft-core that runs FESVR. The FESVR on the soft-core sends TSI commands -to a TSI-to-TileLink converter living on the FPGA (i.e. ``SerialAdapter``). After the transaction is -converted to TileLink, the ``TLSerdesser`` (located in ``generators/testchipip``) serializes the -transaction and sends it to the chip (this ``TLSerdesser`` is sometimes also referred to as a -serial-link or serdes). Once the serialized transaction is received on the -chip, it is deserialized and masters a bus on the chip. The following image shows this flow: - -.. image:: ../_static/images/chip-bringup.png - -.. note:: - The ``TLSerdesser`` can also be used as a slave (client), so it can sink memory requests from the chip - and connect to off-chip backing memory. Or in other words, ``TLSerdesser`` creates a bi-directional TileLink - interface. +TSI protocol is an implementation of HTIF that is used to send commands to the RISC-V DUT. +These TSI commands are simple R/W commands that are able to probe the DUT's memory space. +During simulation, the host sends TSI commands to a simulation stub in the test harness called ``SimSerial`` +(C++ class) that resides in a ``SimSerial`` Verilog module (both are located in the ``generators/testchipip`` +project). +This ``SimSerial`` Verilog module then sends the TSI command recieved by the simulation stub +to an adapter that converts the TSI command into a TileLink request. +This conversion is done by the ``SerialAdapter`` module (located in the ``generators/testchipip`` project). +After the transaction is converted to TileLink, the ``TLSerdesser`` (located in ``generators/testchipip``) serializes the +transaction and sends it to the chip (this ``TLSerdesser`` is sometimes also referred to as a digital serial-link or SerDes). +Once the serialized transaction is received on the chip, it is deserialized and masters a TileLink bus on the chip +which handles the request. +In simulation, FESVR resets the DUT, writes into memory the test program, and indicates to the DUT to start the program +through an interrupt (see :ref:`customization/Boot-Process:Chipyard Boot Process`). +Using TSI is currently the fastest mechanism to communicate with the DUT in simulation and is also used by FireSim. Using the Debug Module Interface (DMI) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -95,9 +83,10 @@ Thus, Chipyard removes the DTM by default in favor of the TSI protocol for DUT c Starting the TSI or DMI Simulation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -All default Chipyard configurations use TSI to communicate between the simulation and the simulated SoC/DUT. Hence, when running a -software RTL simulation, as is indicated in the :ref:`simulation/Software-RTL-Simulation:Software RTL Simulation` section, you are in-fact using TSI to communicate with the DUT. As a -reminder, to run a software RTL simulation, run: +All default Chipyard configurations use TSI to communicate between the simulation and the simulated SoC/DUT. +Hence, when running a software RTL simulation, as is indicated in the +:ref:`simulation/Software-RTL-Simulation:Software RTL Simulation` section, you are in-fact using TSI to communicate with the DUT. +As a reminder, to run a software RTL simulation, run: .. code-block:: bash @@ -105,11 +94,10 @@ reminder, to run a software RTL simulation, run: # or cd sims/vcs - make CONFIG=LargeBoomConfig run-asm-tests + make CONFIG=RocketConfig run-asm-tests -FireSim FPGA-accelerated simulations use TSI by default as well. - -If you would like to build and simulate a Chipyard configuration with a DTM configured for DMI communication, then you must tie-off the TSI interface, and instantiate the `SimDTM`. Note that we use `WithTiedOffSerial ++ WithSimDebug` instead of `WithTiedOffDebug ++ WithSimSerial`. +If you would like to build and simulate a Chipyard configuration with a DTM configured for DMI communication, +then you must tie-off the serial-link interface, and instantiate the `SimDTM`. .. literalinclude:: ../../generators/chipyard/src/main/scala/config/RocketConfigs.scala :language: scala @@ -130,13 +118,81 @@ Using the JTAG Interface ------------------------ The main way to use JTAG with a Rocket Chip based system is to instantiate the Debug Transfer Module (DTM) -and configure it to use a JTAG interface. The default Chipyard designs instantiate the DTM and configure it -to use JTAG. You may attach OpenOCD and GDB to any of the default JTAG-enabled designs. +and configure it to use a JTAG interface. +The default Chipyard designs instantiate the DTM and configure it to use JTAG. +You may attach OpenOCD and GDB to any of the default JTAG-enabled designs. Debugging with JTAG -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~ -Please refer to the following resources on how to debug with JTAG. +Please refer to the following resources on how to debug a Rocket Chip system with JTAG. * https://github.com/chipsalliance/rocket-chip#-debugging-with-gdb * https://github.com/riscv/riscv-isa-sim#debugging-with-gdb + +Roughly the steps are as follows (refer to the links for details): + +1. Build a Chipyard JTAG-enabled RTL design (i.e. ``make CONFIG=RocketConfig`` in ``sims/*``) +2. Run the simulation with remote bit-bang enabled (i.e. ``make CONFIG=RocketConfig BINARY= SIM_FLAGS="+jtag_rbb_enable=1 --rbb-port=9823" run-binary``) +3. Launch OpenOCD +4. Connect to OpenOCD via GDB +5. Done! + +Example Test Chip Bringup Communication +--------------------------------------- + +Intro to Typical Chipyard Test Chip +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Most, if not all, Chipyard configurations are tethered using TSI (over a serial link) and have access +to external memory through an AXI port (backing AXI memory). +The following image shows the DUT with these set of default signals: + +.. image:: ../_static/images/chip-bringup.png + +In this setup, the serial-link is connected to the TSI/FESVR peripherals while the AXI port is connected +to a simulated AXI memory. +However, AXI ports tend to have many signals associated with them so instead of creating an AXI port off the DUT, +one can send the memory transactions over the bi-directional serial-link (``TLSerdesser``) so that main +interface to the DUT is the serial-link (which as comparatively less signals than an AXI port). +This new setup (shown below) is a typical Chipyard test chip setup: + +.. image:: ../_static/images/chip-bringup.png + +Simulation Setup +~~~~~~~~~~~~~~~~ + +To test this type of configuration (TSI/memory transactions over the serial-link), most of the same TSI collateral +would be used. +The main difference is that the TileLink-to-AXI converters and simulated AXI memory resides on the other side of the +serial-link. + +.. image:: ../_static/images/chip-bringup.png + +.. note:: + Here the simulated AXI memory and the converters can be in a different clock domain in the test harness + than the DUT. This is done in a harness binder doing these offchip connections. See + :ref:`Advanced-Concepts/Harness-Clocks:Creating Clocks in the Test Harness` on how to generate a clock in a harness binder. + +This type of simulation setup is done in the following multi-clock configuration: + +.. literalinclude:: ../../generators/chipyard/src/main/scala/config/RocketConfigs.scala + :language: scala + :start-after: DOC include start: MulticlockAXIOverSerialConfig + :end-before: DOC include end: MulticlockAXIOverSerialConfig + +Real-world FPGA Setup +~~~~~~~~~~~~~~~~~~~~~ + +Assuming this same chip configuration is being tested after tapeout (during bringup), +communication with the DUT is similar but slightly different. +For example, some Berkeley tapeouts have a FPGA with a RISC-V soft-core that runs FESVR. +This RISC-V soft-core would serve as the host of the test that will run on the DUT. +The FESVR on the soft-core sends TSI commands to the ``SerialAdapter`` which then sends the converted +TileLink transaction to the chip over the serial-link. +If the chip requests offchip memory, it can then send the transaction back over the serial-link to the +FPGA DRAM. +The following image shows this flow: + +.. image:: ../_static/images/chip-bringup.png + diff --git a/docs/Advanced-Concepts/Harness-Clocks.rst b/docs/Advanced-Concepts/Harness-Clocks.rst new file mode 100644 index 00000000..e0a7ac3e --- /dev/null +++ b/docs/Advanced-Concepts/Harness-Clocks.rst @@ -0,0 +1,20 @@ +.. _harness-clocks: + +Creating Clocks in the Test Harness +=================================== + +By default, all modules in the Test Harness, including those made by harness binders +use the implicit clock and reset of the Test Harness. +However, the test harness and harness binders, have the ability to generate a standalone +clock and reset signal. +This is done by the ``HarnessClockInstantiator`` which allows you to request a clock at a +particular frequency. +Take the following harness binder example: + +.. literalinclude:: ../../generators/chipyard/src/main/scala/config/HarnessBinders.scala + :language: scala + :start-after: DOC include start: HarnessClockInstantiatorEx + :end-before: DOC include end: HarnessClockInstantiatorEx + +While the purpose of the binder isn't necessary here, you can see that the ``p(HarnessClockInstantiatorKey).getClockBundle`` +allows the binder to request a clock/reset bundle at a particular frequency. diff --git a/docs/Advanced-Concepts/index.rst b/docs/Advanced-Concepts/index.rst index 12b12716..b294d11b 100644 --- a/docs/Advanced-Concepts/index.rst +++ b/docs/Advanced-Concepts/index.rst @@ -14,4 +14,5 @@ They expect you to know about Chisel, Parameters, configs, etc. Debugging-BOOM Resources CDEs + Harness-Clocks diff --git a/generators/chipyard/src/main/scala/HarnessBinders.scala b/generators/chipyard/src/main/scala/HarnessBinders.scala index a1f39c6c..bed779d0 100644 --- a/generators/chipyard/src/main/scala/HarnessBinders.scala +++ b/generators/chipyard/src/main/scala/HarnessBinders.scala @@ -157,11 +157,13 @@ class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({ } ports.map({ port => +// DOC include start: HarnessClockInstantiatorEx val harnessMultiClockAXIRAM = SerialAdapter.connectHarnessMultiClockAXIRAM( system.serdesser.get, port, p(HarnessClockInstantiatorKey).getClockBundle("mem_over_serial_tl_clock", memFreq), th.harnessReset) +// DOC include end: HarnessClockInstantiatorEx val success = SerialAdapter.connectSimSerial(harnessMultiClockAXIRAM.module.io.tsi_ser, port.clock, th.harnessReset.asBool) when (success) { th.success := true.B } diff --git a/generators/chipyard/src/main/scala/config/RocketConfigs.scala b/generators/chipyard/src/main/scala/config/RocketConfigs.scala index 45f016bf..a81c1449 100644 --- a/generators/chipyard/src/main/scala/config/RocketConfigs.scala +++ b/generators/chipyard/src/main/scala/config/RocketConfigs.scala @@ -213,6 +213,7 @@ class LBWIFRocketConfig extends Config( new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) +// DOC include start: MulticlockAXIOverSerialConfig class MulticlockAXIOverSerialConfig extends Config( new chipyard.config.WithSystemBusFrequencyAsDefault ++ new chipyard.config.WithSystemBusFrequency(250) ++ @@ -233,3 +234,4 @@ class MulticlockAXIOverSerialConfig extends Config( new freechips.rocketchip.subsystem.WithNBigCores(2) ++ new chipyard.config.AbstractConfig) +// DOC include end: MulticlockAXIOverSerialConfig From d5d547d27b248089af6e528d7b8d6e79bb8ee47e Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Mon, 8 Mar 2021 21:18:34 -0800 Subject: [PATCH 15/30] Update doc images [ci skip] --- docs/Advanced-Concepts/Chip-Communication.rst | 6 +++--- .../bringup-chipyard-config-communication.png | Bin 0 -> 16564 bytes .../images/chip-bringup-simulation.png | Bin 0 -> 36255 bytes docs/_static/images/chip-bringup.png | Bin 18536 -> 30740 bytes docs/_static/images/chip-communication.png | Bin 106042 -> 85405 bytes .../default-chipyard-config-communication.png | Bin 0 -> 17717 bytes 6 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 docs/_static/images/bringup-chipyard-config-communication.png create mode 100644 docs/_static/images/chip-bringup-simulation.png create mode 100644 docs/_static/images/default-chipyard-config-communication.png diff --git a/docs/Advanced-Concepts/Chip-Communication.rst b/docs/Advanced-Concepts/Chip-Communication.rst index 9084f7ef..dc4c95cf 100644 --- a/docs/Advanced-Concepts/Chip-Communication.rst +++ b/docs/Advanced-Concepts/Chip-Communication.rst @@ -148,7 +148,7 @@ Most, if not all, Chipyard configurations are tethered using TSI (over a serial to external memory through an AXI port (backing AXI memory). The following image shows the DUT with these set of default signals: -.. image:: ../_static/images/chip-bringup.png +.. image:: ../_static/images/default-chipyard-config-communication.png In this setup, the serial-link is connected to the TSI/FESVR peripherals while the AXI port is connected to a simulated AXI memory. @@ -157,7 +157,7 @@ one can send the memory transactions over the bi-directional serial-link (``TLSe interface to the DUT is the serial-link (which as comparatively less signals than an AXI port). This new setup (shown below) is a typical Chipyard test chip setup: -.. image:: ../_static/images/chip-bringup.png +.. image:: ../_static/images/bringup-chipyard-config-communication.png Simulation Setup ~~~~~~~~~~~~~~~~ @@ -167,7 +167,7 @@ would be used. The main difference is that the TileLink-to-AXI converters and simulated AXI memory resides on the other side of the serial-link. -.. image:: ../_static/images/chip-bringup.png +.. image:: ../_static/images/chip-bringup-simulation.png .. note:: Here the simulated AXI memory and the converters can be in a different clock domain in the test harness diff --git a/docs/_static/images/bringup-chipyard-config-communication.png b/docs/_static/images/bringup-chipyard-config-communication.png new file mode 100644 index 0000000000000000000000000000000000000000..9da84dcfe40d262c7ffe863a1ff22edd92c76cfd GIT binary patch literal 16564 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 E0L6hVivR!s literal 0 HcmV?d00001 diff --git a/docs/_static/images/chip-bringup.png b/docs/_static/images/chip-bringup.png index 4e8d060271ceb46cd26c61a3d6dacd901fcf43f2..07c80f0528240e4212420a8b4a943319655ef3bc 100644 GIT binary patch literal 30740 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 z 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 Dtd0iD literal 18536 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

KQ#R-kDv(crYU*DN3>t9(mI#9)>%RzSDJtGln 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 z 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 R@C5iLEFi&O%&Xz~zW_6N2Au!^ diff --git a/docs/_static/images/default-chipyard-config-communication.png b/docs/_static/images/default-chipyard-config-communication.png new file mode 100644 index 0000000000000000000000000000000000000000..9763e1d44fc78e0e84422a073aa1a7aed934216c GIT binary patch literal 17717 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 literal 0 HcmV?d00001 From 6e1b9429bdf3f181952749b39a9d05a2199291b5 Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Mon, 8 Mar 2021 21:31:33 -0800 Subject: [PATCH 16/30] Fix docs harness binders reference --- docs/Advanced-Concepts/Harness-Clocks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Advanced-Concepts/Harness-Clocks.rst b/docs/Advanced-Concepts/Harness-Clocks.rst index e0a7ac3e..ba599722 100644 --- a/docs/Advanced-Concepts/Harness-Clocks.rst +++ b/docs/Advanced-Concepts/Harness-Clocks.rst @@ -11,7 +11,7 @@ This is done by the ``HarnessClockInstantiator`` which allows you to request a c particular frequency. Take the following harness binder example: -.. literalinclude:: ../../generators/chipyard/src/main/scala/config/HarnessBinders.scala +.. literalinclude:: ../../generators/chipyard/src/main/scala/HarnessBinders.scala :language: scala :start-after: DOC include start: HarnessClockInstantiatorEx :end-before: DOC include end: HarnessClockInstantiatorEx From d204ccd9fc1ec4fcc6de4f84c8db06e0500e55fa Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Tue, 9 Mar 2021 23:56:32 -0800 Subject: [PATCH 17/30] Clean up the chip communication docs a bit more [ci skip] --- docs/Advanced-Concepts/Chip-Communication.rst | 87 ++++++++++++------- 1 file changed, 57 insertions(+), 30 deletions(-) diff --git a/docs/Advanced-Concepts/Chip-Communication.rst b/docs/Advanced-Concepts/Chip-Communication.rst index dc4c95cf..5c18783d 100644 --- a/docs/Advanced-Concepts/Chip-Communication.rst +++ b/docs/Advanced-Concepts/Chip-Communication.rst @@ -78,7 +78,6 @@ command into a TileLink request. This conversion is done by the DTM named ``Debu When the DTM receives the program to load, it starts to write the binary byte-wise into memory. This is considerably slower than the TSI protocol communication pipeline (i.e. ``SimSerial``/``SerialAdapter``/TileLink) which directly writes the program binary to memory. -Thus, Chipyard removes the DTM by default in favor of the TSI protocol for DUT communication. Starting the TSI or DMI Simulation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -117,26 +116,48 @@ Then you can run simulations with the new DMI-enabled top-level and test-harness Using the JTAG Interface ------------------------ -The main way to use JTAG with a Rocket Chip based system is to instantiate the Debug Transfer Module (DTM) -and configure it to use a JTAG interface. -The default Chipyard designs instantiate the DTM and configure it to use JTAG. -You may attach OpenOCD and GDB to any of the default JTAG-enabled designs. +Another way to interface with the DUT is to use JTAG. +Similar to the :ref:`Advanced-Concepts/Chip-Communication:Using the Debug Module interface (DMI)` section, in order to use the JTAG protocol, +the DUT needs to contain a Debug Transfer Module (DTM) configured to use JTAG instead of DMI. +Once the JTAG port is exposed, the host can communicate over JTAG to the DUT through a simulation stub +called ``SimJTAG`` (C++ class) that resides in a ``SimJTAG`` Verilog module (both reside in the ``generators/rocket-chip`` project). +This simulation stub creates a socket that OpenOCD and GDB can connect to when the simulation is running. +The default Chipyard designs instantiate the DTM configured to use JTAG (i.e. ``RocketConfig``). + +.. note:: + As mentioned, default Chipyard designs are enabled with JTAG. + However, they also use TSI/Serialized-TL with FESVR in case the JTAG interface isn't used. + This allows users to choose how to communicate with the DUT (use TSI or JTAG). Debugging with JTAG ~~~~~~~~~~~~~~~~~~~ -Please refer to the following resources on how to debug a Rocket Chip system with JTAG. +Roughly the steps to debug with JTAG in simulation are as follows: -* https://github.com/chipsalliance/rocket-chip#-debugging-with-gdb -* https://github.com/riscv/riscv-isa-sim#debugging-with-gdb +1. Build a Chipyard JTAG-enabled RTL design. Remember default Chipyard designs are JTAG ready. -Roughly the steps are as follows (refer to the links for details): +.. code-block:: bash -1. Build a Chipyard JTAG-enabled RTL design (i.e. ``make CONFIG=RocketConfig`` in ``sims/*``) -2. Run the simulation with remote bit-bang enabled (i.e. ``make CONFIG=RocketConfig BINARY= SIM_FLAGS="+jtag_rbb_enable=1 --rbb-port=9823" run-binary``) -3. Launch OpenOCD -4. Connect to OpenOCD via GDB -5. Done! + cd sims/verilator + # or + cd sims/vcs + + make CONFIG=RocketConfig + +2. Run the simulation with remote bit-bang enabled. Since we hope to load/run the binary using JTAG, + we can pass ``none`` as a binary (prevents FESVR from loading the program). (Adapted from: https://github.com/chipsalliance/rocket-chip#3-launch-the-emulator) + +.. code-block:: bash + + # note: this uses Chipyard make invocation to run the simulation to properly wrap the simulation args + make CONFIG=RocketConfig BINARY=none SIM_FLAGS="+jtag_rbb_enable=1 --rbb-port=9823" run-binary + +3. `Follow the instructions here to connect to the simulation using OpenOCD + GDB. `__ + +.. note:: + This section was adapted from the instruction in Rocket Chip and riscv-isa-sim. For more information refer + to that documentation: `Rocket Chip GDB Docs `__, + `riscv-isa-sim GDB Docs `__ Example Test Chip Bringup Communication --------------------------------------- @@ -144,7 +165,7 @@ Example Test Chip Bringup Communication Intro to Typical Chipyard Test Chip ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Most, if not all, Chipyard configurations are tethered using TSI (over a serial link) and have access +Most, if not all, Chipyard configurations are tethered using TSI (over a serial-link) and have access to external memory through an AXI port (backing AXI memory). The following image shows the DUT with these set of default signals: @@ -153,14 +174,14 @@ The following image shows the DUT with these set of default signals: In this setup, the serial-link is connected to the TSI/FESVR peripherals while the AXI port is connected to a simulated AXI memory. However, AXI ports tend to have many signals associated with them so instead of creating an AXI port off the DUT, -one can send the memory transactions over the bi-directional serial-link (``TLSerdesser``) so that main -interface to the DUT is the serial-link (which as comparatively less signals than an AXI port). +one can send the memory transactions over the bi-directional serial-link (``TLSerdesser``) so that the main +interface to the DUT is the serial-link (which has comparatively less signals than an AXI port). This new setup (shown below) is a typical Chipyard test chip setup: .. image:: ../_static/images/bringup-chipyard-config-communication.png -Simulation Setup -~~~~~~~~~~~~~~~~ +Simulation Setup of the Example Test Chip +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To test this type of configuration (TSI/memory transactions over the serial-link), most of the same TSI collateral would be used. @@ -171,8 +192,12 @@ serial-link. .. note:: Here the simulated AXI memory and the converters can be in a different clock domain in the test harness - than the DUT. This is done in a harness binder doing these offchip connections. See - :ref:`Advanced-Concepts/Harness-Clocks:Creating Clocks in the Test Harness` on how to generate a clock in a harness binder. + than the reference clock of the DUT. + For example, the DUT can be clocked at 3.2GHz while the simulated AXI memory can be clocked at 1GHz. + This functionality is done in the harness binder that instantiates the TSI collateral, TL-to-AXI converters, + and simulated AXI memory. + See :ref:`Advanced-Concepts/Harness-Clocks:Creating Clocks in the Test Harness` on how to generate a clock + in a harness binder. This type of simulation setup is done in the following multi-clock configuration: @@ -181,18 +206,20 @@ This type of simulation setup is done in the following multi-clock configuration :start-after: DOC include start: MulticlockAXIOverSerialConfig :end-before: DOC include end: MulticlockAXIOverSerialConfig -Real-world FPGA Setup -~~~~~~~~~~~~~~~~~~~~~ +Bringup Setup of the Example Test Chip after Tapeout +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Assuming this same chip configuration is being tested after tapeout (during bringup), -communication with the DUT is similar but slightly different. -For example, some Berkeley tapeouts have a FPGA with a RISC-V soft-core that runs FESVR. +Assuming this example test chip is taped out and now ready to be tested, we can communicate with the chip using this serial-link. +For example, some Berkeley tapeouts of Chipyard chips have an FPGA running a RISC-V soft-core that is able to speak to the DUT. This RISC-V soft-core would serve as the host of the test that will run on the DUT. -The FESVR on the soft-core sends TSI commands to the ``SerialAdapter`` which then sends the converted -TileLink transaction to the chip over the serial-link. -If the chip requests offchip memory, it can then send the transaction back over the serial-link to the -FPGA DRAM. +This is done by the RISC-V soft-core running FESVR, sending TSI commands to a ``SerialAdapter`` / ``TLSerdesser`` programmed on the FPGA. +Once the commands are converted to serialized TileLink, then they can be sent over some medium to the DUT +(like an FMC cable or a set of wires connecting FPGA outputs to the DUT board). +Similar to simulation, if the chip requests offchip memory, it can then send the transaction back over the serial-link. +Then the request can be serviced by the channel of FPGA DRAM. The following image shows this flow: .. image:: ../_static/images/chip-bringup.png +In fact, this exact type of bringup setup is what the following section discusses: +:ref:`Prototyping/VCU118:Introduction to the Bringup Platform`. From 1ebc0f7a7e19bf3279eeabddaa42a73469537491 Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Thu, 11 Mar 2021 03:30:14 +0000 Subject: [PATCH 18/30] Allow the PLL to request the max freq --- .../src/main/scala/clocking/DividerOnlyClockGenerator.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/chipyard/src/main/scala/clocking/DividerOnlyClockGenerator.scala b/generators/chipyard/src/main/scala/clocking/DividerOnlyClockGenerator.scala index 589d99c6..1723b756 100644 --- a/generators/chipyard/src/main/scala/clocking/DividerOnlyClockGenerator.scala +++ b/generators/chipyard/src/main/scala/clocking/DividerOnlyClockGenerator.scala @@ -51,7 +51,7 @@ object FrequencyUtils { require(!requestedOutputs.contains(0.0)) val requestedFreqs = requestedOutputs.map(_.freqMHz) val fastestFreq = requestedFreqs.max - require(fastestFreq < maximumAllowableFreqMHz) + require(fastestFreq <= maximumAllowableFreqMHz) val candidateFreqs = Seq.tabulate(Math.ceil(maximumAllowableFreqMHz / fastestFreq).toInt)(i => (i + 1) * fastestFreq) From 30c9b63e7b15ec1ae2b2a6d936987aeefe3cf784 Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Thu, 11 Mar 2021 03:54:56 +0000 Subject: [PATCH 19/30] More clarifications on harness clocks --- docs/Advanced-Concepts/Harness-Clocks.rst | 36 ++++++++++++++----- .../src/main/scala/HarnessBinders.scala | 3 +- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/docs/Advanced-Concepts/Harness-Clocks.rst b/docs/Advanced-Concepts/Harness-Clocks.rst index ba599722..70efc33b 100644 --- a/docs/Advanced-Concepts/Harness-Clocks.rst +++ b/docs/Advanced-Concepts/Harness-Clocks.rst @@ -3,18 +3,36 @@ Creating Clocks in the Test Harness =================================== -By default, all modules in the Test Harness, including those made by harness binders -use the implicit clock and reset of the Test Harness. -However, the test harness and harness binders, have the ability to generate a standalone -clock and reset signal. -This is done by the ``HarnessClockInstantiator`` which allows you to request a clock at a -particular frequency. -Take the following harness binder example: +Chipyard currently allows the SoC design (everything under ``ChipTop``) to +have independent clock domains through diplomacy. +This implies that some reference clock enters the ``ChipTop`` and then is divided down into +separate clock domains. +From the perspective of the ``TestHarness`` module, the ``ChipTop`` clock and reset is +provided from the harness clock and reset (called ``harnessClock`` and ``harnessReset``). +In the default case, this ``harnessClock`` and ``harnessReset`` is directly wired to the +clock and reset IO's of the ``TestHarness`` module. +However, the ``TestHarness`` has the ability to generate a standalone clock and reset signal +that is separate from the reference clock/reset of ``ChipTop``. +This allows harness components (including harness binders) the ability to "request" a clock +for a new clock domain. +This is useful for simulating systems in which modules in the harness have independent clock domains +from the DUT. + +Requests for a harness clock is done by the ``HarnessClockInstantiator`` class in ``generators/chipyard/src/main/scala/TestHarness.scala``. +This class is accessed in harness components by referencing the Rocket Chip parameters key ``p(HarnessClockInstantiatorKey)``. +Then you can request a clock and syncronized reset at a particular frequency by invoking the ``getClockBundle`` function. +Take the following example: .. literalinclude:: ../../generators/chipyard/src/main/scala/HarnessBinders.scala :language: scala :start-after: DOC include start: HarnessClockInstantiatorEx :end-before: DOC include end: HarnessClockInstantiatorEx -While the purpose of the binder isn't necessary here, you can see that the ``p(HarnessClockInstantiatorKey).getClockBundle`` -allows the binder to request a clock/reset bundle at a particular frequency. +Here you can see the ``p(HarnessClockInstantiatorKey)`` is used to request a clock and reset at ``memFreq`` frequency. + +.. note:: + In the case that the reference clock entering ``ChipTop`` is not the overall reference clock of the simulation + (i.e. not the clock/reset coming into the ``TestHarness`` module), the ``harnessClock`` and ``harnessReset`` can + differ from the implicit ``TestHarness`` clock and reset. For example, if the ``ChipTop`` reference is 500MHz but an + extra harness clock is requested at 1GHz, the ``TestHarness`` implicit clock/reset will be at 1GHz while the ``harnessClock`` + and ``harnessReset`` will be at 500MHz. diff --git a/generators/chipyard/src/main/scala/HarnessBinders.scala b/generators/chipyard/src/main/scala/HarnessBinders.scala index bed779d0..faa504b4 100644 --- a/generators/chipyard/src/main/scala/HarnessBinders.scala +++ b/generators/chipyard/src/main/scala/HarnessBinders.scala @@ -158,10 +158,11 @@ class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({ ports.map({ port => // DOC include start: HarnessClockInstantiatorEx + val memOverSerialTLClockBundle = p(HarnessClockInstantiatorKey).getClockBundle("mem_over_serial_tl_clock", memFreq) val harnessMultiClockAXIRAM = SerialAdapter.connectHarnessMultiClockAXIRAM( system.serdesser.get, port, - p(HarnessClockInstantiatorKey).getClockBundle("mem_over_serial_tl_clock", memFreq), + memOverSerialTLClockBundle, th.harnessReset) // DOC include end: HarnessClockInstantiatorEx val success = SerialAdapter.connectSimSerial(harnessMultiClockAXIRAM.module.io.tsi_ser, port.clock, th.harnessReset.asBool) From 6476c7e7f0bfafa02acb719b8e9079099d51b475 Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Mon, 15 Mar 2021 16:54:42 -0700 Subject: [PATCH 20/30] Small renaming/cleanup | Use LinkedHashMaps --- .../chipyard/src/main/scala/Clocks.scala | 2 +- .../src/main/scala/ConfigFragments.scala | 6 +++ .../src/main/scala/HarnessBinders.scala | 12 ++--- .../chipyard/src/main/scala/TestHarness.scala | 15 +++---- .../clocking/DividerOnlyClockGenerator.scala | 4 -- .../src/main/scala/BridgeBinders.scala | 11 +---- .../firechip/src/main/scala/FireSim.scala | 44 +++++++++---------- .../src/main/scala/TargetConfigs.scala | 3 +- generators/testchipip | 2 +- 9 files changed, 43 insertions(+), 56 deletions(-) diff --git a/generators/chipyard/src/main/scala/Clocks.scala b/generators/chipyard/src/main/scala/Clocks.scala index 00c07417..9d400e6c 100644 --- a/generators/chipyard/src/main/scala/Clocks.scala +++ b/generators/chipyard/src/main/scala/Clocks.scala @@ -86,7 +86,7 @@ object ClockingSchemeGenerators { :*= aggregator) val referenceClockSource = ClockSourceNode(Seq(ClockSourceParameters())) - val dividerOnlyClkGenerator = DividerOnlyClockGenerator() + val dividerOnlyClkGenerator = LazyModule(new DividerOnlyClockGenerator("buildTopClockGenerator")) // provides all the divided clocks (from the top-level clock) (aggregator := ClockGroupFrequencySpecifier(p(ClockFrequencyAssignersKey), p(DefaultClockFrequencyKey)) diff --git a/generators/chipyard/src/main/scala/ConfigFragments.scala b/generators/chipyard/src/main/scala/ConfigFragments.scala index 490baa93..a175d5a5 100644 --- a/generators/chipyard/src/main/scala/ConfigFragments.scala +++ b/generators/chipyard/src/main/scala/ConfigFragments.scala @@ -217,6 +217,12 @@ class WithSerialTLBackingMemory extends Config((site, here, up) => { )} }) +/** + * Mixins to define either a specific tile frequency for a single hart or all harts + * + * @param fMHz Frequency in MHz of the tile or all tiles + * @param hartId Optional hartid to assign the frequency to (if unspecified default to all harts) + */ class WithTileFrequency(fMHz: Double, hartId: Option[Int] = None) extends ClockNameContainsAssignment({ hartId match { case Some(id) => s"tile_$id" diff --git a/generators/chipyard/src/main/scala/HarnessBinders.scala b/generators/chipyard/src/main/scala/HarnessBinders.scala index faa504b4..32931977 100644 --- a/generators/chipyard/src/main/scala/HarnessBinders.scala +++ b/generators/chipyard/src/main/scala/HarnessBinders.scala @@ -144,21 +144,15 @@ class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({ implicit val p = chipyard.iobinders.GetSystemParameters(system) p(SerialTLKey).map({ sVal => - // currently only the harness AXI port supports a passthrough clock require(sVal.axiMemOverSerialTLParams.isDefined) val axiDomainParams = sVal.axiMemOverSerialTLParams.get + require(sVal.isMemoryDevice) - val memFreq: Double = axiDomainParams.axiClockParams match { - case Some(clkParams) => clkParams.clockFreqMHz * 1000000 - case None => { - // get freq. from what the master of the serial link specifies - system.asInstanceOf[HasTileLinkLocations].locateTLBusWrapper(p(SerialTLAttachKey).masterWhere).dtsFrequency.get.toDouble - } - } + val memFreq = axiDomainParams.getMemFrequency(system.asInstanceOf[HasTileLinkLocations]) ports.map({ port => // DOC include start: HarnessClockInstantiatorEx - val memOverSerialTLClockBundle = p(HarnessClockInstantiatorKey).getClockBundle("mem_over_serial_tl_clock", memFreq) + val memOverSerialTLClockBundle = p(HarnessClockInstantiatorKey).requestClockBundle("mem_over_serial_tl_clock", memFreq) val harnessMultiClockAXIRAM = SerialAdapter.connectHarnessMultiClockAXIRAM( system.serdesser.get, port, diff --git a/generators/chipyard/src/main/scala/TestHarness.scala b/generators/chipyard/src/main/scala/TestHarness.scala index 9090086f..e5af755a 100644 --- a/generators/chipyard/src/main/scala/TestHarness.scala +++ b/generators/chipyard/src/main/scala/TestHarness.scala @@ -2,7 +2,7 @@ package chipyard import chisel3._ -import scala.collection.mutable.{ArrayBuffer, HashMap} +import scala.collection.mutable.{ArrayBuffer, LinkedHashMap} import freechips.rocketchip.diplomacy.{LazyModule} import freechips.rocketchip.config.{Field, Parameters} import freechips.rocketchip.util.{ResetCatchAndSync} @@ -31,10 +31,10 @@ trait HasHarnessSignalReferences { } class HarnessClockInstantiator { - private var _clockMap: HashMap[String, (Double, ClockBundle)] = HashMap.empty + private val _clockMap: LinkedHashMap[String, (Double, ClockBundle)] = LinkedHashMap.empty // request a clock bundle at a particular frequency - def getClockBundle(name: String, freqRequested: Double): ClockBundle = { + def requestClockBundle(name: String, freqRequested: Double): ClockBundle = { val clockBundle = Wire(new ClockBundle(ClockBundleParameters())) _clockMap(name) = (freqRequested, clockBundle) clockBundle @@ -49,7 +49,7 @@ class HarnessClockInstantiator { val pllConfig = new SimplePllConfiguration("harnessDividerOnlyClockGenerator", sinks) pllConfig.emitSummaries() - val dividedClocks = HashMap[Int, Clock]() + val dividedClocks = LinkedHashMap[Int, Clock]() def instantiateDivider(div: Int): Clock = { val divider = Module(new ClockDividerN(div)) divider.suggestName(s"ClockDivideBy${div}") @@ -86,16 +86,15 @@ class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSign val harnessReset = Wire(Reset()) val lazyDut = LazyModule(p(BuildTop)(p)).suggestName("chiptop") - withClockAndReset(harnessClock, harnessReset) { - val dut = Module(lazyDut.module) - } + val dut = Module(lazyDut.module) + io.success := false.B val freqMHz = lazyDut match { case d: HasReferenceClockFreq => d.refClockFreqMHz.getOrElse(p(DefaultClockFrequencyKey)) case _ => p(DefaultClockFrequencyKey) } - val refClkBundle = p(HarnessClockInstantiatorKey).getClockBundle("buildtop_reference_clock", freqMHz * (1000 * 1000)) + val refClkBundle = p(HarnessClockInstantiatorKey).requestClockBundle("buildtop_reference_clock", freqMHz * (1000 * 1000)) harnessClock := refClkBundle.clock harnessReset := WireInit(refClkBundle.reset) diff --git a/generators/chipyard/src/main/scala/clocking/DividerOnlyClockGenerator.scala b/generators/chipyard/src/main/scala/clocking/DividerOnlyClockGenerator.scala index 1723b756..b272c80c 100644 --- a/generators/chipyard/src/main/scala/clocking/DividerOnlyClockGenerator.scala +++ b/generators/chipyard/src/main/scala/clocking/DividerOnlyClockGenerator.scala @@ -145,7 +145,3 @@ class DividerOnlyClockGenerator(pllName: String)(implicit p: Parameters, valName } } } - -object DividerOnlyClockGenerator { - def apply()(implicit p: Parameters, valName: ValName) = LazyModule(new DividerOnlyClockGenerator(valName.name)) -} diff --git a/generators/firechip/src/main/scala/BridgeBinders.scala b/generators/firechip/src/main/scala/BridgeBinders.scala index 174ea5bb..bc44b9f7 100644 --- a/generators/firechip/src/main/scala/BridgeBinders.scala +++ b/generators/firechip/src/main/scala/BridgeBinders.scala @@ -110,21 +110,14 @@ class WithAXIOverSerialTLCombinedBridges extends OverrideHarnessBinder({ implicit val p = GetSystemParameters(system) p(SerialTLKey).map({ sVal => - // currently only the harness AXI port supports a passthrough clock require(sVal.axiMemOverSerialTLParams.isDefined) val axiDomainParams = sVal.axiMemOverSerialTLParams.get require(sVal.isMemoryDevice) - val memFreq: Double = axiDomainParams.axiClockParams match { - case Some(clkParams) => clkParams.clockFreqMHz * 1000000 - case None => { - // get freq. from what the master of the serial link specifies - system.asInstanceOf[HasTileLinkLocations].locateTLBusWrapper(p(SerialTLAttachKey).masterWhere).dtsFrequency.get.toDouble - } - } + val memFreq = axiDomainParams.getMemFrequency(system.asInstanceOf[HasTileLinkLocations]) ports.map({ port => - val axiClock = p(ClockBridgeInstantiatorKey).getClock("mem_over_serial_tl_clock", memFreq) + 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.harnessReset.asBool) diff --git a/generators/firechip/src/main/scala/FireSim.scala b/generators/firechip/src/main/scala/FireSim.scala index ca0ab1a0..7a66c896 100644 --- a/generators/firechip/src/main/scala/FireSim.scala +++ b/generators/firechip/src/main/scala/FireSim.scala @@ -2,7 +2,7 @@ package firesim.firesim -import scala.collection.mutable.{HashMap} +import scala.collection.mutable.{LinkedHashMap} import chisel3._ import chisel3.experimental.{IO} @@ -44,12 +44,12 @@ object NodeIdx { * memoize its instantiation such that it can be referenced from within a ClockScheme function. */ class ClockBridgeInstantiator { - private var _harnessClockMap: HashMap[String, (Double, Clock)] = HashMap.empty + private val _harnessClockMap: LinkedHashMap[String, (Double, Clock)] = LinkedHashMap.empty // Assumes that the supernode implementation results in duplicated clocks // (i.e. only 1 set of clocks is generated for all BuildTop designs) - private var _ratClockMap: HashMap[String, (RationalClock, Clock)] = HashMap.empty - private var _ratRefTuple: Option[(String, Double)] = None + private val _buildtopClockMap: LinkedHashMap[String, (RationalClock, Clock)] = LinkedHashMap.empty + private var _buildtopRefTuple: Option[(String, Double)] = None /** * Request a clock at a particular frequency @@ -58,7 +58,7 @@ class ClockBridgeInstantiator { * * @param freqRequested Freq. for the domain in Hz */ - def getClock(name: String, freqRequested: Double): Clock = { + def requestClock(name: String, freqRequested: Double): Clock = { val clkWire = Wire(new Clock) _harnessClockMap(name) = (freqRequested, clkWire) clkWire @@ -73,15 +73,15 @@ class ClockBridgeInstantiator { * * @param baseFreqRequested Freq. for the reference domain in Hz */ - def getClockRecordMap(allClocks: Seq[RationalClock], baseClockName: String, baseFreqRequested: Double): RecordMap[Clock] = { - require(!_ratRefTuple.isDefined, "Can only request one RecordMap of Clocks") + def requestClockRecordMap(allClocks: Seq[RationalClock], baseClockName: String, baseFreqRequested: Double): RecordMap[Clock] = { + require(!_buildtopRefTuple.isDefined, "Can only request one RecordMap of Clocks") val ratClockRecordMapWire = Wire(RecordMap(allClocks.map { c => (c.name, Clock()) }:_*)) - _ratRefTuple = Some((baseClockName, baseFreqRequested)) + _buildtopRefTuple = Some((baseClockName, baseFreqRequested)) for (clock <- allClocks) { val clkWire = Wire(new Clock) - _ratClockMap(clock.name) = (clock, clkWire) + _buildtopClockMap(clock.name) = (clock, clkWire) ratClockRecordMapWire(clock.name).get := clkWire } @@ -92,14 +92,14 @@ class ClockBridgeInstantiator { * Connect all clocks requested to ClockBridge */ def instantiateFireSimClockBridge: Unit = { - require(_ratRefTuple.isDefined, "Must have rational clocks to assign to") - require(_ratClockMap.exists(_._1 == _ratRefTuple.get._1), - s"Provided base-clock name for rational clocks, ${_ratRefTuple.get._1}, doesn't match a name within specified rational clocks." + - "Available clocks:\n " + _ratClockMap.map(_._1).mkString("\n ")) + require(_buildtopRefTuple.isDefined, "Must have rational clocks to assign to") + require(_buildtopClockMap.exists(_._1 == _buildtopRefTuple.get._1), + s"Provided base-clock name for rational clocks, ${_buildtopRefTuple.get._1}, doesn't match a name within specified rational clocks." + + "Available clocks:\n " + _buildtopClockMap.map(_._1).mkString("\n ")) // Simplify the RationalClocks ratio's - val refRatClock = _ratClockMap.find(_._1 == _ratRefTuple.get._1).get._2._1 - val simpleRatClocks = _ratClockMap.map { t => + val refRatClock = _buildtopClockMap.find(_._1 == _buildtopRefTuple.get._1).get._2._1 + val simpleRatClocks = _buildtopClockMap.map { t => val ratClock = t._2._1 ratClock.copy( multiplier = ratClock.multiplier * refRatClock.divisor, @@ -108,8 +108,8 @@ class ClockBridgeInstantiator { // Determine all the clock dividers (harness + rational clocks) // Note: Requires that the BuildTop reference frequency is requested with proper freq. - val refRatClockFreq = _ratRefTuple.get._2 - val refRatSinkParams = ClockSinkParameters(take=Some(ClockParameters(freqMHz=refRatClockFreq / (1000 * 1000))),name=Some(_ratRefTuple.get._1)) + val refRatClockFreq = _buildtopRefTuple.get._2 + val refRatSinkParams = ClockSinkParameters(take=Some(ClockParameters(freqMHz=refRatClockFreq / (1000 * 1000))),name=Some(_buildtopRefTuple.get._1)) val harSinkParams = _harnessClockMap.map { case (name, (freq, bundle)) => ClockSinkParameters(take=Some(ClockParameters(freqMHz=freq / (1000 * 1000))),name=Some(name)) }.toSeq @@ -144,7 +144,7 @@ class ClockBridgeInstantiator { // Connect all clocks (harness + BuildTop clocks) for (clock <- allAdjRatClks) { val (_, cbClockField) = cbVecTuples.find(_._1.equalFrequency(clock)).get - _ratClockMap.get(clock.name).map { case (_, clk) => clk := cbClockField } + _buildtopClockMap.get(clock.name).map { case (_, clk) => clk := cbClockField } _harnessClockMap.get(clock.name).map { case (_, clk) => clk := cbClockField } } } @@ -200,7 +200,7 @@ class WithFireSimSimpleClocks extends Config((site, here, up) => { chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => { reset := th.harnessReset input_clocks := p(ClockBridgeInstantiatorKey) - .getClockRecordMap(rationalClockSpecs.toSeq, p(FireSimBaseClockNameKey), pllConfig.referenceFreqMHz * (1000 * 1000)) + .requestClockRecordMap(rationalClockSpecs.toSeq, p(FireSimBaseClockNameKey), pllConfig.referenceFreqMHz * (1000 * 1000)) Nil }) } } @@ -227,9 +227,7 @@ class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSigna val lazyModule = LazyModule(p(BuildTop)(p.alterPartial({ case AsyncClockGroupsKey => p(AsyncClockGroupsKey).copy }))) - withClockAndReset(harnessClock, harnessReset) { - val module = Module(lazyModule.module) - } + val module = Module(lazyModule.module) btFreqMHz = Some(lazyModule match { case d: HasReferenceClockFreq => d.refClockFreqMHz.getOrElse(p(DefaultClockFrequencyKey)) @@ -246,7 +244,7 @@ class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSigna NodeIdx.increment() } - harnessClock := p(ClockBridgeInstantiatorKey).getClock("buildtop_reference_clock", btFreqMHz.get * (1000 * 1000)) + harnessClock := p(ClockBridgeInstantiatorKey).requestClock("buildtop_reference_clock", btFreqMHz.get * (1000 * 1000)) p(ClockBridgeInstantiatorKey).instantiateFireSimClockBridge } diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index 6be9cc21..ca94c8f8 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -59,6 +59,7 @@ class WithNIC extends icenet.WithIceNIC(inBufFlits = 8192, ctrlQueueDepth = 64) class WithNVDLALarge extends nvidia.blocks.dla.WithNVDLA("large") class WithNVDLASmall extends nvidia.blocks.dla.WithNVDLA("small") +// Tweaks that are generally applied to all firesim configs (without default FireSim clocks) class WithFireSimDesignTweaks extends Config( // Required: Bake in the default FASED memory model new WithDefaultMemModel ++ @@ -82,7 +83,7 @@ class WithFireSimDesignTweaks extends Config( new chipyard.config.WithNoDebug ) -// Tweaks that are generally applied to all firesim configs +// Tweaks that are generally applied to all firesim configs (with default FireSim clocks) class WithFireSimConfigTweaks extends Config( // Optional*: Removing this will require adjusting the UART baud rate and // potential target-software changes to properly capture UART output diff --git a/generators/testchipip b/generators/testchipip index 03c4ac48..6b082f1e 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit 03c4ac486209253aaa20a702842fba511cfeac04 +Subproject commit 6b082f1edb6c8e4342587ca80aefd8af6e6e8a53 From 3439266b2ec29e541d081cb2fdb6f5a3536b44ec Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Mon, 15 Mar 2021 16:55:13 -0700 Subject: [PATCH 21/30] Small renaming in docs --- docs/Advanced-Concepts/Harness-Clocks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Advanced-Concepts/Harness-Clocks.rst b/docs/Advanced-Concepts/Harness-Clocks.rst index 70efc33b..c49ee29f 100644 --- a/docs/Advanced-Concepts/Harness-Clocks.rst +++ b/docs/Advanced-Concepts/Harness-Clocks.rst @@ -20,7 +20,7 @@ from the DUT. Requests for a harness clock is done by the ``HarnessClockInstantiator`` class in ``generators/chipyard/src/main/scala/TestHarness.scala``. This class is accessed in harness components by referencing the Rocket Chip parameters key ``p(HarnessClockInstantiatorKey)``. -Then you can request a clock and syncronized reset at a particular frequency by invoking the ``getClockBundle`` function. +Then you can request a clock and syncronized reset at a particular frequency by invoking the ``requestClockBundle`` function. Take the following example: .. literalinclude:: ../../generators/chipyard/src/main/scala/HarnessBinders.scala From 53017234047b292b89f38dcadbd1de0d795e21c7 Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Tue, 16 Mar 2021 19:42:24 -0700 Subject: [PATCH 22/30] Use def instead of var Option for ref frequency --- generators/chipyard/src/main/scala/ChipTop.scala | 5 +++-- generators/chipyard/src/main/scala/Clocks.scala | 12 ++++++------ generators/chipyard/src/main/scala/TestHarness.scala | 2 +- generators/firechip/src/main/scala/FireSim.scala | 8 ++++---- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/generators/chipyard/src/main/scala/ChipTop.scala b/generators/chipyard/src/main/scala/ChipTop.scala index e6cfa8cb..8d05d10e 100644 --- a/generators/chipyard/src/main/scala/ChipTop.scala +++ b/generators/chipyard/src/main/scala/ChipTop.scala @@ -16,7 +16,7 @@ import barstools.iocell.chisel._ case object BuildSystem extends Field[Parameters => LazyModule]((p: Parameters) => new DigitalTop()(p)) trait HasReferenceClockFreq { - var refClockFreqMHz: Option[Double] = None + def refClockFreqMHz: Double } /** @@ -35,7 +35,8 @@ class ChipTop(implicit p: Parameters) extends LazyModule with BindingScope val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters(name = Some("implicit_clock")))) // Generate Clocks and Reset - p(ClockingSchemeKey)(this) + val mvRefClkFreq = p(ClockingSchemeKey)(this) + def refClockFreqMHz: Double = mvRefClkFreq.getWrappedValue // NOTE: Making this a LazyRawModule is moderately dangerous, as anonymous children // of ChipTop (ex: ClockGroup) do not receive clock or reset. diff --git a/generators/chipyard/src/main/scala/Clocks.scala b/generators/chipyard/src/main/scala/Clocks.scala index 9d400e6c..c25366c6 100644 --- a/generators/chipyard/src/main/scala/Clocks.scala +++ b/generators/chipyard/src/main/scala/Clocks.scala @@ -7,7 +7,7 @@ import scala.collection.mutable.{ArrayBuffer} import freechips.rocketchip.prci._ import freechips.rocketchip.subsystem.{BaseSubsystem, SubsystemDriveAsyncClockGroupsKey, InstantiatesTiles} import freechips.rocketchip.config.{Parameters, Field, Config} -import freechips.rocketchip.diplomacy.{OutwardNodeHandle, InModuleBody, LazyModule} +import freechips.rocketchip.diplomacy.{ModuleValue, OutwardNodeHandle, InModuleBody, LazyModule} import freechips.rocketchip.util.{ResetCatchAndSync} import barstools.iocell.chisel._ @@ -38,7 +38,7 @@ object GenerateReset { } -case object ClockingSchemeKey extends Field[ChipTop => Unit](ClockingSchemeGenerators.dividerOnlyClockGenerator) +case object ClockingSchemeKey extends Field[ChipTop => ModuleValue[Double]](ClockingSchemeGenerators.dividerOnlyClockGenerator) /* * This is a Seq of assignment functions, that accept a clock name and return an optional frequency. * Functions that appear later in this seq have higher precedence that earlier ones. @@ -59,7 +59,7 @@ class ClockNameContainsAssignment(name: String, fMHz: Double) extends Config((si }) object ClockingSchemeGenerators { - val dividerOnlyClockGenerator: ChipTop => Unit = { chiptop => + val dividerOnlyClockGenerator: ChipTop => ModuleValue[Double] = { chiptop => implicit val p = chiptop.p // Requires existence of undriven asyncClockGroups in subsystem @@ -100,9 +100,6 @@ object ClockingSchemeGenerators { val (clock_io, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, "clock") chiptop.iocells ++= clockIOCell - // set the reference clock used - chiptop.refClockFreqMHz = Some(dividerOnlyClkGenerator.module.referenceFreq) - referenceClockSource.out.unzip._1.map { o => o.clock := clock_wire o.reset := reset_wire @@ -111,6 +108,9 @@ object ClockingSchemeGenerators { chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => { clock_io := th.harnessClock Nil }) + + // return the reference frequency + dividerOnlyClkGenerator.module.referenceFreq } } } diff --git a/generators/chipyard/src/main/scala/TestHarness.scala b/generators/chipyard/src/main/scala/TestHarness.scala index e5af755a..82be0093 100644 --- a/generators/chipyard/src/main/scala/TestHarness.scala +++ b/generators/chipyard/src/main/scala/TestHarness.scala @@ -91,7 +91,7 @@ class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSign io.success := false.B val freqMHz = lazyDut match { - case d: HasReferenceClockFreq => d.refClockFreqMHz.getOrElse(p(DefaultClockFrequencyKey)) + case d: HasReferenceClockFreq => d.refClockFreqMHz case _ => p(DefaultClockFrequencyKey) } val refClkBundle = p(HarnessClockInstantiatorKey).requestClockBundle("buildtop_reference_clock", freqMHz * (1000 * 1000)) diff --git a/generators/firechip/src/main/scala/FireSim.scala b/generators/firechip/src/main/scala/FireSim.scala index 7a66c896..68533146 100644 --- a/generators/firechip/src/main/scala/FireSim.scala +++ b/generators/firechip/src/main/scala/FireSim.scala @@ -194,14 +194,14 @@ class WithFireSimSimpleClocks extends Config((site, here, up) => { RationalClock(sinkP.name.get, 1, division) } - // Set the reference frequency used - chiptop.refClockFreqMHz = Some(pllConfig.referenceFreqMHz) - chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => { reset := th.harnessReset input_clocks := p(ClockBridgeInstantiatorKey) .requestClockRecordMap(rationalClockSpecs.toSeq, p(FireSimBaseClockNameKey), pllConfig.referenceFreqMHz * (1000 * 1000)) Nil }) + + // return the reference frequency + pllConfig.referenceFreqMHz } } }) @@ -230,7 +230,7 @@ class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSigna val module = Module(lazyModule.module) btFreqMHz = Some(lazyModule match { - case d: HasReferenceClockFreq => d.refClockFreqMHz.getOrElse(p(DefaultClockFrequencyKey)) + case d: HasReferenceClockFreq => d.refClockFreqMHz case _ => p(DefaultClockFrequencyKey) }) From 4a565088b51265230049bc0ea6869d00e1d596ad Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Thu, 18 Mar 2021 20:01:45 -0700 Subject: [PATCH 23/30] Small spacing fixes --- generators/chipyard/src/main/scala/TestHarness.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/chipyard/src/main/scala/TestHarness.scala b/generators/chipyard/src/main/scala/TestHarness.scala index 82be0093..d8c7ec20 100644 --- a/generators/chipyard/src/main/scala/TestHarness.scala +++ b/generators/chipyard/src/main/scala/TestHarness.scala @@ -43,7 +43,7 @@ class HarnessClockInstantiator { // connect all clock wires specified to a divider only PLL def instantiateHarnessDividerPLL(refClock: ClockBundle): Unit = { val sinks = _clockMap.map({ case (name, (freq, bundle)) => - ClockSinkParameters(take=Some(ClockParameters(freqMHz=freq/1000000)),name=Some(name)) + ClockSinkParameters(take=Some(ClockParameters(freqMHz=freq / (1000 * 1000))), name=Some(name)) }).toSeq val pllConfig = new SimplePllConfiguration("harnessDividerOnlyClockGenerator", sinks) From 0d6e971d17a01b4bd6db0780004a0e5f5b4a9e30 Mon Sep 17 00:00:00 2001 From: Abraham Gonzalez Date: Thu, 18 Mar 2021 20:02:15 -0700 Subject: [PATCH 24/30] Update docs/Advanced-Concepts/Chip-Communication.rst Co-authored-by: alonamid --- docs/Advanced-Concepts/Chip-Communication.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Advanced-Concepts/Chip-Communication.rst b/docs/Advanced-Concepts/Chip-Communication.rst index 5c18783d..f9fa8229 100644 --- a/docs/Advanced-Concepts/Chip-Communication.rst +++ b/docs/Advanced-Concepts/Chip-Communication.rst @@ -210,7 +210,7 @@ Bringup Setup of the Example Test Chip after Tapeout ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Assuming this example test chip is taped out and now ready to be tested, we can communicate with the chip using this serial-link. -For example, some Berkeley tapeouts of Chipyard chips have an FPGA running a RISC-V soft-core that is able to speak to the DUT. +For example, a common test setup used at Berkeley to evaluate Chipyard-based test-chips includes an FPGA running a RISC-V soft-core that is able to speak to the DUT (over an FMC). This RISC-V soft-core would serve as the host of the test that will run on the DUT. This is done by the RISC-V soft-core running FESVR, sending TSI commands to a ``SerialAdapter`` / ``TLSerdesser`` programmed on the FPGA. Once the commands are converted to serialized TileLink, then they can be sent over some medium to the DUT From 1e421139268ec6ff7d9bce4c114094fa4f21847c Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Fri, 19 Mar 2021 17:33:39 -0700 Subject: [PATCH 25/30] Splitting up FireSim default frequencies into a separate config frag. --- .../firechip/src/main/scala/TargetConfigs.scala | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index ca94c8f8..04920acc 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -59,7 +59,7 @@ class WithNIC extends icenet.WithIceNIC(inBufFlits = 8192, ctrlQueueDepth = 64) class WithNVDLALarge extends nvidia.blocks.dla.WithNVDLA("large") class WithNVDLASmall extends nvidia.blocks.dla.WithNVDLA("small") -// Tweaks that are generally applied to all firesim configs (without default FireSim clocks) +// Non-frequency tweaks that are generally applied to all firesim configs class WithFireSimDesignTweaks extends Config( // Required: Bake in the default FASED memory model new WithDefaultMemModel ++ @@ -83,8 +83,8 @@ class WithFireSimDesignTweaks extends Config( new chipyard.config.WithNoDebug ) -// Tweaks that are generally applied to all firesim configs (with default FireSim clocks) -class WithFireSimConfigTweaks extends Config( +// Tweaks to modify target clock frequencies / crossings to firesim defaults +class WithFireSimDefaultFrequencyTweaks extends Config( // Optional*: Removing this will require adjusting the UART baud rate and // potential target-software changes to properly capture UART output new chipyard.config.WithPeripheryBusFrequency(3200.0) ++ @@ -96,7 +96,11 @@ class WithFireSimConfigTweaks extends Config( new chipyard.config.WithMemoryBusFrequency(1000.0) ++ new chipyard.config.WithAsynchrousMemoryBusCrossing ++ new testchipip.WithAsynchronousSerialSlaveCrossing ++ - // Tweaks that are independent from multi-clock +) + +// Tweaks that are generally applied to all firesim configs +class WithFireSimConfigTweaks extends Config( + new WithFireSimDefaultFrequencyTweaks ++ new WithFireSimDesignTweaks ) From b729a5f4a492bd9c8360fb35d52bfd5235963a36 Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Fri, 19 Mar 2021 17:34:47 -0700 Subject: [PATCH 26/30] Allow run-asm/bmark debug make targets to specify random seed --- sims/vcs/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sims/vcs/Makefile b/sims/vcs/Makefile index 2c44ae6e..405cda54 100644 --- a/sims/vcs/Makefile +++ b/sims/vcs/Makefile @@ -66,7 +66,7 @@ $(sim_debug): $(sim_vsrcs) $(sim_common_files) $(dramsim_lib) $(EXTRA_SIM_REQS) ######################################################################################### .PRECIOUS: $(output_dir)/%.vpd %.vpd $(output_dir)/%.vpd: $(output_dir)/% $(sim_debug) - (set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(VERBOSE_FLAGS) +vcdplusfile=$@ $(PERMISSIVE_OFF) $< >(spike-dasm > $<.out) | tee $<.log) + (set -o pipefail && $(sim_debug) $(PERMISSIVE_ON) $(SIM_FLAGS) $(EXTRA_SIM_FLAGS) $(SEED_FLAG) $(VERBOSE_FLAGS) +vcdplusfile=$@ $(PERMISSIVE_OFF) $< >(spike-dasm > $<.out) | tee $<.log) ######################################################################################### # general cleanup rules From 87fa481cbbc52f7a8cd075403cf40b9981ff6e4f Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Fri, 19 Mar 2021 17:35:30 -0700 Subject: [PATCH 27/30] Fix TileResetCtrl so that tiles come out of reset after rest of uncore --- generators/testchipip | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/testchipip b/generators/testchipip index 0c1b871d..b014c24e 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit 0c1b871dddd1fef3fd773e721384392beba9a203 +Subproject commit b014c24e7a14d71d20ecae38928294b7ecaa082b From f59a7901b0db2dea3581e450e69547537eea1195 Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Fri, 19 Mar 2021 18:43:17 -0700 Subject: [PATCH 28/30] Bump testchipip --- generators/testchipip | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/testchipip b/generators/testchipip index b014c24e..289ad47e 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit b014c24e7a14d71d20ecae38928294b7ecaa082b +Subproject commit 289ad47e6c22f4aed3cbe79f58193a227047728e From 5ffad327dbde357fd223d58b0553fd27021308ae Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Sun, 21 Mar 2021 15:34:01 -0700 Subject: [PATCH 29/30] Bump testchipip --- .circleci/config.yml | 1 + generators/firechip/src/main/scala/BridgeBinders.scala | 2 +- generators/firechip/src/main/scala/TargetConfigs.scala | 2 +- generators/testchipip | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7dcbc809..9c6e9f80 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -308,6 +308,7 @@ jobs: tools-version: "esp-tools" group-key: "group-accels" project-key: "chipyard-hwacha" + timeout: "30m" chipyard-gemmini-run-tests: executor: main-env steps: diff --git a/generators/firechip/src/main/scala/BridgeBinders.scala b/generators/firechip/src/main/scala/BridgeBinders.scala index 419071bc..4ea31df5 100644 --- a/generators/firechip/src/main/scala/BridgeBinders.scala +++ b/generators/firechip/src/main/scala/BridgeBinders.scala @@ -130,7 +130,7 @@ class WithAXIOverSerialTLCombinedBridges extends OverrideHarnessBinder({ val harnessMultiClockAXIRAM = withClockAndReset(th.harnessClock, th.harnessReset) { SerialAdapter.connectHarnessMultiClockAXIRAM( system.serdesser.get, - port, + serial_bits, axiClockBundle, th.harnessReset) } diff --git a/generators/firechip/src/main/scala/TargetConfigs.scala b/generators/firechip/src/main/scala/TargetConfigs.scala index 04920acc..43fea874 100644 --- a/generators/firechip/src/main/scala/TargetConfigs.scala +++ b/generators/firechip/src/main/scala/TargetConfigs.scala @@ -95,7 +95,7 @@ class WithFireSimDefaultFrequencyTweaks extends Config( // runnings the FASED runtime configuration generator to generate faithful DDR3 timing values. new chipyard.config.WithMemoryBusFrequency(1000.0) ++ new chipyard.config.WithAsynchrousMemoryBusCrossing ++ - new testchipip.WithAsynchronousSerialSlaveCrossing ++ + new testchipip.WithAsynchronousSerialSlaveCrossing ) // Tweaks that are generally applied to all firesim configs diff --git a/generators/testchipip b/generators/testchipip index ef59e54c..1d2ac9c1 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit ef59e54c42eb990036f13378dea5900713154228 +Subproject commit 1d2ac9c13bd1d4c053bbf9c7d57436f0113c39fd From 09ef82cabf8186833aa75480bf5669435b43b463 Mon Sep 17 00:00:00 2001 From: abejgonzalez Date: Mon, 22 Mar 2021 11:54:20 -0700 Subject: [PATCH 30/30] Update harnessClk/Rst naming to buildtop | Small docs cleanup --- docs/Advanced-Concepts/Chip-Communication.rst | 8 ++-- docs/Advanced-Concepts/Harness-Clocks.rst | 10 ++--- fpga/src/main/scala/arty/HarnessBinders.scala | 2 +- fpga/src/main/scala/arty/TestHarness.scala | 4 +- fpga/src/main/scala/vcu118/TestHarness.scala | 8 ++-- .../chipyard/src/main/scala/Clocks.scala | 2 +- .../src/main/scala/HarnessBinders.scala | 38 +++++++++---------- .../chipyard/src/main/scala/TestHarness.scala | 12 +++--- .../src/main/scala/BridgeBinders.scala | 22 +++++------ .../firechip/src/main/scala/FireSim.scala | 10 ++--- generators/testchipip | 2 +- 11 files changed, 59 insertions(+), 59 deletions(-) diff --git a/docs/Advanced-Concepts/Chip-Communication.rst b/docs/Advanced-Concepts/Chip-Communication.rst index f9fa8229..6e8d2c0e 100644 --- a/docs/Advanced-Concepts/Chip-Communication.rst +++ b/docs/Advanced-Concepts/Chip-Communication.rst @@ -46,7 +46,7 @@ Using the Tethered Serial Interface (TSI) By default, Chipyard uses the Tethered Serial Interface (TSI) to communicate with the DUT. TSI protocol is an implementation of HTIF that is used to send commands to the RISC-V DUT. -These TSI commands are simple R/W commands that are able to probe the DUT's memory space. +These TSI commands are simple R/W commands that are able to access the DUT's memory space. During simulation, the host sends TSI commands to a simulation stub in the test harness called ``SimSerial`` (C++ class) that resides in a ``SimSerial`` Verilog module (both are located in the ``generators/testchipip`` project). @@ -59,7 +59,7 @@ Once the serialized transaction is received on the chip, it is deserialized and which handles the request. In simulation, FESVR resets the DUT, writes into memory the test program, and indicates to the DUT to start the program through an interrupt (see :ref:`customization/Boot-Process:Chipyard Boot Process`). -Using TSI is currently the fastest mechanism to communicate with the DUT in simulation and is also used by FireSim. +Using TSI is currently the fastest mechanism to communicate with the DUT in simulation (compared to DMI/JTAG) and is also used by FireSim. Using the Debug Module Interface (DMI) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -173,7 +173,7 @@ The following image shows the DUT with these set of default signals: In this setup, the serial-link is connected to the TSI/FESVR peripherals while the AXI port is connected to a simulated AXI memory. -However, AXI ports tend to have many signals associated with them so instead of creating an AXI port off the DUT, +However, AXI ports tend to have many signals, and thus wires, associated with them so instead of creating an AXI port off the DUT, one can send the memory transactions over the bi-directional serial-link (``TLSerdesser``) so that the main interface to the DUT is the serial-link (which has comparatively less signals than an AXI port). This new setup (shown below) is a typical Chipyard test chip setup: @@ -216,7 +216,7 @@ This is done by the RISC-V soft-core running FESVR, sending TSI commands to a `` Once the commands are converted to serialized TileLink, then they can be sent over some medium to the DUT (like an FMC cable or a set of wires connecting FPGA outputs to the DUT board). Similar to simulation, if the chip requests offchip memory, it can then send the transaction back over the serial-link. -Then the request can be serviced by the channel of FPGA DRAM. +Then the request can be serviced by the FPGA DRAM. The following image shows this flow: .. image:: ../_static/images/chip-bringup.png diff --git a/docs/Advanced-Concepts/Harness-Clocks.rst b/docs/Advanced-Concepts/Harness-Clocks.rst index c49ee29f..ef224974 100644 --- a/docs/Advanced-Concepts/Harness-Clocks.rst +++ b/docs/Advanced-Concepts/Harness-Clocks.rst @@ -8,8 +8,8 @@ have independent clock domains through diplomacy. This implies that some reference clock enters the ``ChipTop`` and then is divided down into separate clock domains. From the perspective of the ``TestHarness`` module, the ``ChipTop`` clock and reset is -provided from the harness clock and reset (called ``harnessClock`` and ``harnessReset``). -In the default case, this ``harnessClock`` and ``harnessReset`` is directly wired to the +provided from a clock and reset called ``buildtopClock`` and ``buildtopReset``. +In the default case, this ``buildtopClock`` and ``buildtopReset`` is directly wired to the clock and reset IO's of the ``TestHarness`` module. However, the ``TestHarness`` has the ability to generate a standalone clock and reset signal that is separate from the reference clock/reset of ``ChipTop``. @@ -32,7 +32,7 @@ Here you can see the ``p(HarnessClockInstantiatorKey)`` is used to request a clo .. note:: In the case that the reference clock entering ``ChipTop`` is not the overall reference clock of the simulation - (i.e. not the clock/reset coming into the ``TestHarness`` module), the ``harnessClock`` and ``harnessReset`` can + (i.e. the clock/reset coming into the ``TestHarness`` module), the ``buildtopClock`` and ``buildtopReset`` can differ from the implicit ``TestHarness`` clock and reset. For example, if the ``ChipTop`` reference is 500MHz but an - extra harness clock is requested at 1GHz, the ``TestHarness`` implicit clock/reset will be at 1GHz while the ``harnessClock`` - and ``harnessReset`` will be at 500MHz. + extra harness clock is requested at 1GHz, the ``TestHarness`` implicit clock/reset will be at 1GHz while the ``buildtopClock`` + and ``buildtopReset`` will be at 500MHz. diff --git a/fpga/src/main/scala/arty/HarnessBinders.scala b/fpga/src/main/scala/arty/HarnessBinders.scala index ef7b1805..3581ae3d 100644 --- a/fpga/src/main/scala/arty/HarnessBinders.scala +++ b/fpga/src/main/scala/arty/HarnessBinders.scala @@ -32,7 +32,7 @@ class WithArtyJTAGHarnessBinder extends OverrideHarnessBinder({ (system: HasPeripheryDebug, th: ArtyFPGATestHarness, ports: Seq[Data]) => { ports.map { case j: JTAGIO => - withClockAndReset(th.harnessClock, th.hReset) { + withClockAndReset(th.buildtopClock, th.hReset) { val io_jtag = Wire(new JTAGPins(() => new BasePin(), false)).suggestName("jtag") JTAGPinsFromPort(io_jtag, j) diff --git a/fpga/src/main/scala/arty/TestHarness.scala b/fpga/src/main/scala/arty/TestHarness.scala index 503d2de6..db7ddc01 100644 --- a/fpga/src/main/scala/arty/TestHarness.scala +++ b/fpga/src/main/scala/arty/TestHarness.scala @@ -27,8 +27,8 @@ class ArtyFPGATestHarness(override implicit val p: Parameters) extends ArtyShell val dut = Module(lazyDut.module) } - val harnessClock = clock_32MHz - val harnessReset = hReset + val buildtopClock = clock_32MHz + val buildtopReset = hReset val success = false.B val dutReset = dReset diff --git a/fpga/src/main/scala/vcu118/TestHarness.scala b/fpga/src/main/scala/vcu118/TestHarness.scala index 5002817f..45afe7f7 100644 --- a/fpga/src/main/scala/vcu118/TestHarness.scala +++ b/fpga/src/main/scala/vcu118/TestHarness.scala @@ -121,13 +121,13 @@ class VCU118FPGATestHarnessImp(_outer: VCU118FPGATestHarness) extends LazyRawMod val hReset = Wire(Reset()) hReset := _outer.dutClock.in.head._1.reset - val harnessClock = _outer.dutClock.in.head._1.clock - val harnessReset = WireInit(hReset) + val buildtopClock = _outer.dutClock.in.head._1.clock + val buildtopReset = WireInit(hReset) val dutReset = hReset.asAsyncReset val success = false.B - childClock := harnessClock - childReset := harnessReset + childClock := buildtopClock + childReset := buildtopReset // harness binders are non-lazy _outer.topDesign match { case d: HasTestHarnessFunctions => diff --git a/generators/chipyard/src/main/scala/Clocks.scala b/generators/chipyard/src/main/scala/Clocks.scala index 2123c754..b5553347 100644 --- a/generators/chipyard/src/main/scala/Clocks.scala +++ b/generators/chipyard/src/main/scala/Clocks.scala @@ -118,7 +118,7 @@ object ClockingSchemeGenerators { } chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => { - clock_io := th.harnessClock + clock_io := th.buildtopClock Nil }) // return the reference frequency diff --git a/generators/chipyard/src/main/scala/HarnessBinders.scala b/generators/chipyard/src/main/scala/HarnessBinders.scala index 686721e5..b87659f4 100644 --- a/generators/chipyard/src/main/scala/HarnessBinders.scala +++ b/generators/chipyard/src/main/scala/HarnessBinders.scala @@ -90,21 +90,21 @@ class WithUARTAdapter extends OverrideHarnessBinder({ class WithSimSPIFlashModel(rdOnly: Boolean = true) extends OverrideHarnessBinder({ (system: HasPeripherySPIFlashModuleImp, th: HasHarnessSignalReferences, ports: Seq[SPIChipIO]) => { - SimSPIFlashModel.connect(ports, th.harnessReset, rdOnly)(system.p) + SimSPIFlashModel.connect(ports, th.buildtopReset, rdOnly)(system.p) } }) class WithSimBlockDevice extends OverrideHarnessBinder({ (system: CanHavePeripheryBlockDevice, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => { implicit val p: Parameters = GetSystemParameters(system) - ports.map { b => SimBlockDevice.connect(b.clock, th.harnessReset.asBool, Some(b.bits)) } + ports.map { b => SimBlockDevice.connect(b.clock, th.buildtopReset.asBool, Some(b.bits)) } } }) class WithBlockDeviceModel extends OverrideHarnessBinder({ (system: CanHavePeripheryBlockDevice, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[BlockDeviceIO]]) => { implicit val p: Parameters = GetSystemParameters(system) - ports.map { b => withClockAndReset(b.clock, th.harnessReset) { BlockDeviceModel.connect(Some(b.bits)) } } + ports.map { b => withClockAndReset(b.clock, th.buildtopReset) { BlockDeviceModel.connect(Some(b.bits)) } } } }) @@ -112,7 +112,7 @@ class WithLoopbackNIC extends OverrideHarnessBinder({ (system: CanHavePeripheryIceNIC, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => { implicit val p: Parameters = GetSystemParameters(system) ports.map { n => - withClockAndReset(n.clock, th.harnessReset) { + withClockAndReset(n.clock, th.buildtopReset) { NicLoopback.connect(Some(n.bits), p(NICKey)) } } @@ -122,7 +122,7 @@ class WithLoopbackNIC extends OverrideHarnessBinder({ class WithSimNetwork extends OverrideHarnessBinder({ (system: CanHavePeripheryIceNIC, th: BaseModule with HasHarnessSignalReferences, ports: Seq[ClockedIO[NICIOvonly]]) => { implicit val p: Parameters = GetSystemParameters(system) - ports.map { n => SimNetwork.connect(Some(n.bits), n.clock, th.harnessReset.asBool) } + ports.map { n => SimNetwork.connect(Some(n.bits), n.clock, th.buildtopReset.asBool) } } }) @@ -152,23 +152,23 @@ class WithSimAXIMemOverSerialTL extends OverrideHarnessBinder({ ports.map({ port => // DOC include start: HarnessClockInstantiatorEx - withClockAndReset(th.harnessClock, th.harnessReset) { + withClockAndReset(th.buildtopClock, th.buildtopReset) { val memOverSerialTLClockBundle = p(HarnessClockInstantiatorKey).requestClockBundle("mem_over_serial_tl_clock", memFreq) - val serial_bits = SerialAdapter.asyncQueue(port, th.harnessClock, th.harnessReset) + val serial_bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset) val harnessMultiClockAXIRAM = SerialAdapter.connectHarnessMultiClockAXIRAM( system.serdesser.get, serial_bits, memOverSerialTLClockBundle, - th.harnessReset) + th.buildtopReset) // DOC include end: HarnessClockInstantiatorEx - val success = SerialAdapter.connectSimSerial(harnessMultiClockAXIRAM.module.io.tsi_ser, th.harnessClock, th.harnessReset.asBool) + val success = SerialAdapter.connectSimSerial(harnessMultiClockAXIRAM.module.io.tsi_ser, th.buildtopClock, th.buildtopReset.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 lineSize = p(CacheBlockBytes) - val mem = Module(new SimDRAM(memSize, lineSize, BigInt(memFreq.toInt), edge.bundle)).suggestName("simdram") + val mem = Module(new SimDRAM(memSize, lineSize, BigInt(memFreq.toLong), edge.bundle)).suggestName("simdram") mem.io.axi <> axi_port.bits mem.io.clock := axi_port.clock mem.io.reset := axi_port.reset @@ -244,11 +244,11 @@ class WithSimDebug extends OverrideHarnessBinder({ case d: ClockedDMIIO => val dtm_success = WireInit(false.B) when (dtm_success) { th.success := true.B } - val dtm = Module(new SimDTM).connect(th.harnessClock, th.harnessReset.asBool, d, dtm_success) + val dtm = Module(new SimDTM).connect(th.buildtopClock, th.buildtopReset.asBool, d, dtm_success) case j: JTAGIO => val dtm_success = WireInit(false.B) when (dtm_success) { th.success := true.B } - val jtag = Module(new SimJTAG(tickDelay=3)).connect(j, th.harnessClock, th.harnessReset.asBool, ~(th.harnessReset.asBool), dtm_success) + val jtag = Module(new SimJTAG(tickDelay=3)).connect(j, th.buildtopClock, th.buildtopReset.asBool, ~(th.buildtopReset.asBool), dtm_success) } } }) @@ -282,9 +282,9 @@ class WithSerialAdapterTiedOff extends OverrideHarnessBinder({ (system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { implicit val p = chipyard.iobinders.GetSystemParameters(system) ports.map({ port => - val bits = SerialAdapter.asyncQueue(port, th.harnessClock, th.harnessReset) - withClockAndReset(th.harnessClock, th.harnessReset) { - val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, bits, th.harnessReset) + val bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset) + withClockAndReset(th.buildtopClock, th.buildtopReset) { + val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, bits, th.buildtopReset) SerialAdapter.tieoff(ram.module.io.tsi_ser) } }) @@ -295,10 +295,10 @@ class WithSimSerial extends OverrideHarnessBinder({ (system: CanHavePeripheryTLSerial, th: HasHarnessSignalReferences, ports: Seq[ClockedIO[SerialIO]]) => { implicit val p = chipyard.iobinders.GetSystemParameters(system) ports.map({ port => - val bits = SerialAdapter.asyncQueue(port, th.harnessClock, th.harnessReset) - withClockAndReset(th.harnessClock, th.harnessReset) { - val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, bits, th.harnessReset) - val success = SerialAdapter.connectSimSerial(ram.module.io.tsi_ser, th.harnessClock, th.harnessReset.asBool) + val bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset) + withClockAndReset(th.buildtopClock, th.buildtopReset) { + val ram = SerialAdapter.connectHarnessRAM(system.serdesser.get, bits, th.buildtopReset) + val success = SerialAdapter.connectSimSerial(ram.module.io.tsi_ser, th.buildtopClock, th.buildtopReset.asBool) when (success) { th.success := true.B } } }) diff --git a/generators/chipyard/src/main/scala/TestHarness.scala b/generators/chipyard/src/main/scala/TestHarness.scala index d8c7ec20..ba09e6dc 100644 --- a/generators/chipyard/src/main/scala/TestHarness.scala +++ b/generators/chipyard/src/main/scala/TestHarness.scala @@ -24,8 +24,8 @@ trait HasTestHarnessFunctions { trait HasHarnessSignalReferences { // clock/reset of the chiptop reference clock (can be different than the implicit harness clock/reset) - def harnessClock: Clock - def harnessReset: Reset + def buildtopClock: Clock + def buildtopReset: Reset def dutReset: Reset def success: Bool } @@ -82,8 +82,8 @@ class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSign val success = Output(Bool()) }) - val harnessClock = Wire(Clock()) - val harnessReset = Wire(Reset()) + val buildtopClock = Wire(Clock()) + val buildtopReset = Wire(Reset()) val lazyDut = LazyModule(p(BuildTop)(p)).suggestName("chiptop") val dut = Module(lazyDut.module) @@ -96,8 +96,8 @@ class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSign } val refClkBundle = p(HarnessClockInstantiatorKey).requestClockBundle("buildtop_reference_clock", freqMHz * (1000 * 1000)) - harnessClock := refClkBundle.clock - harnessReset := WireInit(refClkBundle.reset) + buildtopClock := refClkBundle.clock + buildtopReset := WireInit(refClkBundle.reset) val dutReset = refClkBundle.reset.asAsyncReset val success = io.success diff --git a/generators/firechip/src/main/scala/BridgeBinders.scala b/generators/firechip/src/main/scala/BridgeBinders.scala index 4ea31df5..bf1ff680 100644 --- a/generators/firechip/src/main/scala/BridgeBinders.scala +++ b/generators/firechip/src/main/scala/BridgeBinders.scala @@ -72,11 +72,11 @@ class WithSerialBridge extends OverrideHarnessBinder({ (system: CanHavePeripheryTLSerial, th: FireSim, ports: Seq[ClockedIO[SerialIO]]) => { ports.map { port => implicit val p = GetSystemParameters(system) - val bits = SerialAdapter.asyncQueue(port, th.harnessClock, th.harnessReset) - val ram = withClockAndReset(th.harnessClock, th.harnessReset) { - SerialAdapter.connectHarnessRAM(system.serdesser.get, bits, th.harnessReset) + val bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset) + val ram = withClockAndReset(th.buildtopClock, th.buildtopReset) { + SerialAdapter.connectHarnessRAM(system.serdesser.get, bits, th.buildtopReset) } - SerialBridge(th.harnessClock, ram.module.io.tsi_ser, p(ExtMem).map(_ => MainMemoryConsts.globalName)) + SerialBridge(th.buildtopClock, ram.module.io.tsi_ser, p(ExtMem).map(_ => MainMemoryConsts.globalName)) } Nil } @@ -103,7 +103,7 @@ class WithUARTBridge extends OverrideHarnessBinder({ 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.harnessReset.asBool) } + ports.map { b => BlockDevBridge(b.clock, b.bits, th.buildtopReset.asBool) } Nil } }) @@ -123,18 +123,18 @@ class WithAXIOverSerialTLCombinedBridges extends OverrideHarnessBinder({ 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.harnessReset.asBool) + axiClockBundle.reset := ResetCatchAndSync(axiClock, th.buildtopReset.asBool) - val serial_bits = SerialAdapter.asyncQueue(port, th.harnessClock, th.harnessReset) + val serial_bits = SerialAdapter.asyncQueue(port, th.buildtopClock, th.buildtopReset) - val harnessMultiClockAXIRAM = withClockAndReset(th.harnessClock, th.harnessReset) { + val harnessMultiClockAXIRAM = withClockAndReset(th.buildtopClock, th.buildtopReset) { SerialAdapter.connectHarnessMultiClockAXIRAM( system.serdesser.get, serial_bits, axiClockBundle, - th.harnessReset) + th.buildtopReset) } - SerialBridge(th.harnessClock, harnessMultiClockAXIRAM.module.io.tsi_ser, Some(MainMemoryConsts.globalName)) + SerialBridge(th.buildtopClock, harnessMultiClockAXIRAM.module.io.tsi_ser, Some(MainMemoryConsts.globalName)) // connect SimAxiMem (harnessMultiClockAXIRAM.mem_axi4 zip harnessMultiClockAXIRAM.memNode.edges.in).map { case (axi4, edge) => @@ -192,7 +192,7 @@ class WithDromajoBridge extends ComposeHarnessBinder({ class WithTraceGenBridge extends OverrideHarnessBinder({ (system: TraceGenSystemModuleImp, th: FireSim, ports: Seq[Bool]) => - ports.map { p => GroundTestBridge(th.harnessClock, p)(system.p) }; Nil + ports.map { p => GroundTestBridge(th.buildtopClock, 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 68533146..95594807 100644 --- a/generators/firechip/src/main/scala/FireSim.scala +++ b/generators/firechip/src/main/scala/FireSim.scala @@ -195,7 +195,7 @@ class WithFireSimSimpleClocks extends Config((site, here, up) => { } chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => { - reset := th.harnessReset + reset := th.buildtopReset input_clocks := p(ClockBridgeInstantiatorKey) .requestClockRecordMap(rationalClockSpecs.toSeq, p(FireSimBaseClockNameKey), pllConfig.referenceFreqMHz * (1000 * 1000)) Nil }) @@ -209,9 +209,9 @@ class WithFireSimSimpleClocks extends Config((site, here, up) => { class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSignalReferences { freechips.rocketchip.util.property.cover.setPropLib(new midas.passes.FireSimPropertyLibrary()) - val harnessClock = Wire(Clock()) - val harnessReset = WireInit(false.B) - val peekPokeBridge = PeekPokeBridge(harnessClock, harnessReset) + val buildtopClock = Wire(Clock()) + val buildtopReset = WireInit(false.B) + val peekPokeBridge = PeekPokeBridge(buildtopClock, buildtopReset) def dutReset = { require(false, "dutReset should not be used in Firesim"); false.B } def success = { require(false, "success should not be used in Firesim"); false.B } @@ -244,7 +244,7 @@ class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSigna NodeIdx.increment() } - harnessClock := p(ClockBridgeInstantiatorKey).requestClock("buildtop_reference_clock", btFreqMHz.get * (1000 * 1000)) + buildtopClock := p(ClockBridgeInstantiatorKey).requestClock("buildtop_reference_clock", btFreqMHz.get * (1000 * 1000)) p(ClockBridgeInstantiatorKey).instantiateFireSimClockBridge } diff --git a/generators/testchipip b/generators/testchipip index 1d2ac9c1..fd7760e2 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit 1d2ac9c13bd1d4c053bbf9c7d57436f0113c39fd +Subproject commit fd7760e2862661bf6277acfeeb42644797e876d0