diff --git a/docs/Advanced-Concepts/Top-Testharness.rst b/docs/Advanced-Concepts/Top-Testharness.rst index 23f3f56aa9..e412eeff3e 100644 --- a/docs/Advanced-Concepts/Top-Testharness.rst +++ b/docs/Advanced-Concepts/Top-Testharness.rst @@ -18,6 +18,13 @@ The ``IOBinders`` are responsible for instantiating the IO cells for ``ChipTop`` The ``HarnessBinders`` are responsible for instantiating test harness collateral that connects to the ``ChipTop`` ports. Most types of devices and testing collateral can be instantiated using custom ``IOBinders`` and ``HarnessBinders``. +Custom ChipTops +^^^^^^^^^^^^^^^^^^^^^^^^^ + +The default standard ``ChipTop`` provides a mimimal, barebones template for ``IOBinders`` to generate IOCells around ``DigitalTop`` traits. +For tapeouts, integrating Analog IP, or other non-standard use cases, Chipyard supports specifying a custom ``ChipTop`` using the ``BuildTop`` key. +An example of a custom ChipTop which uses non-standard IOCells is provided in `generators/chipyard/src/main/scala/example/CustomChipTop.scala `__ + System/DigitalTop ------------------------- diff --git a/generators/chipyard/src/main/scala/IOBinders.scala b/generators/chipyard/src/main/scala/IOBinders.scala index 71eef713b6..9ef320912b 100644 --- a/generators/chipyard/src/main/scala/IOBinders.scala +++ b/generators/chipyard/src/main/scala/IOBinders.scala @@ -51,6 +51,12 @@ case object IOBinders extends Field[Map[String, Seq[IOBinderFunction]]]( Map[String, Seq[IOBinderFunction]]().withDefaultValue(Nil) ) +case object DontTouchIOBindersPorts extends Field[Boolean](true) + +class WithDontTouchIOBinders(b: Boolean = true) extends Config((site, here, up) => { + case DontTouchIOBindersPorts => b +}) + abstract trait HasIOBinders { this: LazyModule => val lazySystem: LazyModule private val iobinders = p(IOBinders) @@ -67,10 +73,33 @@ abstract trait HasIOBinders { this: LazyModule => }) // A publicly accessible list of IO cells (useful for a floorplanning tool, for example) - lazy val iocells = (lzyFlattened.values ++ impFlattened.values).unzip._2.flatten.toBuffer + val iocells = InModuleBody { (lzyFlattened.values ++ impFlattened.values).unzip._2.flatten.toBuffer } // A mapping between stringified DigitalSystem traits and their corresponding ChipTop ports - lazy val portMap = iobinders.keys.map(k => k -> (lzyFlattened(k)._1 ++ impFlattened(k)._1)).toMap + val portMap = InModuleBody { iobinders.keys.map(k => k -> (lzyFlattened(k)._1 ++ impFlattened(k)._1)).toMap } + + // A mapping between stringified DigitalSystem traits and their corresponding ChipTop iocells + val iocellMap = InModuleBody { iobinders.keys.map(k => k -> (lzyFlattened(k)._2 ++ impFlattened(k)._2)).toMap } + + InModuleBody { + if (p(DontTouchIOBindersPorts)) { + portMap.values.foreach(_.foreach(dontTouch(_))) + } + + println("IOCells generated by IOBinders:") + for ((k, v) <- iocellMap) { + if (!v.isEmpty) { + val cells = v.map(_.getClass.getSimpleName).groupBy(identity).mapValues(_.size) + + println(s" IOBinder for $k generated:") + for ((t, c) <- cells) { println(s" $c X $t") } + } + } + println() + val totals = iocells.map(_.getClass.getSimpleName).groupBy(identity).mapValues(_.size) + println(s" Total generated ${iocells.size} IOCells:") + for ((t, c) <- totals) { println(s" $c X $t") } + } } // Note: The parameters instance is accessible only through LazyModule diff --git a/generators/chipyard/src/main/scala/config/MMIOAcceleratorConfigs.scala b/generators/chipyard/src/main/scala/config/MMIOAcceleratorConfigs.scala index fcb4804dd8..aa04cfe184 100644 --- a/generators/chipyard/src/main/scala/config/MMIOAcceleratorConfigs.scala +++ b/generators/chipyard/src/main/scala/config/MMIOAcceleratorConfigs.scala @@ -9,6 +9,7 @@ import freechips.rocketchip.diplomacy.{AsynchronousCrossing} // DOC include start: FFTRocketConfig class FFTRocketConfig extends Config( + new chipyard.iobinders.WithDontTouchIOBinders(false) ++ // TODO: hack around dontTouch not working in SFC new fftgenerator.WithFFTGenerator(numPoints=8, width=16, decPt=8) ++ // add 8-point mmio fft at the default addr (0x2400) with 16bit fixed-point numbers. new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) @@ -58,6 +59,7 @@ class LargeNVDLARocketConfig extends Config( new chipyard.config.AbstractConfig) class ManyMMIOAcceleratorRocketConfig extends Config( + new chipyard.iobinders.WithDontTouchIOBinders(false) ++ // TODO: hack around dontTouch not working in SFC new fftgenerator.WithFFTGenerator(numPoints=8, width=16, decPt=8) ++ // add 8-point mmio fft at the default addr (0x2400) with 16bit fixed-point numbers. new nvidia.blocks.dla.WithNVDLA("small") ++ // add a small NVDLA new chipyard.example.WithStreamingPassthrough ++ // use top with tilelink-controlled streaming passthrough diff --git a/generators/chipyard/src/main/scala/config/RocketConfigs.scala b/generators/chipyard/src/main/scala/config/RocketConfigs.scala index b6677cb1b3..f70ef27406 100644 --- a/generators/chipyard/src/main/scala/config/RocketConfigs.scala +++ b/generators/chipyard/src/main/scala/config/RocketConfigs.scala @@ -12,6 +12,7 @@ class RocketConfig extends Config( new chipyard.config.AbstractConfig) class TinyRocketConfig extends Config( + new chipyard.iobinders.WithDontTouchIOBinders(false) ++ // TODO FIX: Don't dontTouch the ports new chipyard.config.WithTLSerialLocation( freechips.rocketchip.subsystem.FBUS, freechips.rocketchip.subsystem.PBUS) ++ // attach TL serial adapter to f/p busses @@ -126,3 +127,9 @@ class MulticlockAXIOverSerialConfig extends Config( new freechips.rocketchip.subsystem.WithNBigCores(2) ++ new chipyard.config.AbstractConfig) // DOC include end: MulticlockAXIOverSerialConfig + +class CustomIOChipTopRocketConfig extends Config( + new chipyard.example.WithCustomChipTop ++ + new chipyard.example.WithCustomIOCells ++ + new freechips.rocketchip.subsystem.WithNBigCores(1) ++ // single rocket-core + new chipyard.config.AbstractConfig) diff --git a/generators/chipyard/src/main/scala/config/TutorialConfigs.scala b/generators/chipyard/src/main/scala/config/TutorialConfigs.scala index c9956b7aaf..c871ba6f74 100644 --- a/generators/chipyard/src/main/scala/config/TutorialConfigs.scala +++ b/generators/chipyard/src/main/scala/config/TutorialConfigs.scala @@ -77,6 +77,7 @@ class TutorialSha3BlackBoxConfig extends Config( // Tutorial Phase 5: Map a multicore heterogeneous SoC with multiple cores and memory-mapped accelerators class TutorialNoCConfig extends Config( + new chipyard.iobinders.WithDontTouchIOBinders(false) ++ // Try changing the dimensions of the Mesh topology new constellation.soc.WithGlobalNoC(constellation.soc.GlobalNoCParams( NoCParams( diff --git a/generators/chipyard/src/main/scala/example/CustomChipTop.scala b/generators/chipyard/src/main/scala/example/CustomChipTop.scala new file mode 100644 index 0000000000..19be7d5bd4 --- /dev/null +++ b/generators/chipyard/src/main/scala/example/CustomChipTop.scala @@ -0,0 +1,64 @@ +package chipyard.example + +import chisel3._ +import chipyard.iobinders._ + +import freechips.rocketchip.config._ +import freechips.rocketchip.diplomacy.{InModuleBody} +import barstools.iocell.chisel._ +import chipyard._ + +// A "custom" IOCell with additional I/O +// The IO don't do anything here in this example +class CustomDigitalInIOCellBundle extends DigitalInIOCellBundle { + val custom_out = Output(Bool()) + val custom_in = Input(Bool()) +} + +// Using a custom digital in iocell instead of the default one +class CustomDigitalInIOCell extends RawModule with DigitalInIOCell { + val io = IO(new CustomDigitalInIOCellBundle) + io.i := io.pad + io.custom_out := io.pad +} + +case class CustomIOCellParams() extends IOCellTypeParams { + def analog() = Module(new GenericAnalogIOCell) + def gpio() = Module(new GenericDigitalGPIOCell) + def input() = Module(new CustomDigitalInIOCell) + def output() = Module(new GenericDigitalOutIOCell) +} + +class CustomChipTop(implicit p: Parameters) extends ChipTop { + // making the module name ChipTop instead of CustomChipTop means + // we don't have to set the TOP make variable to CustomChipTop + override lazy val desiredName = "ChipTop" + + // InModuleBody blocks are executed within the LazyModuleImp of this block + InModuleBody { + iocellMap.foreach { case (interface, cells) => { + cells.foreach { _ match { + case c: CustomDigitalInIOCell => { + c.io.custom_in := false.B + } + case c: GenericDigitalOutIOCell => { + // do nothing + } + case c => { + require(false, "Unsupported iocell type ${c.getClass}") + } + }} + }} + + // demonstrate accessing the iocellMap directly + val serialTLIOCells = iocellMap("interface testchipip.CanHavePeripheryTLSerial") + } +} + +class WithCustomIOCells extends Config((site, here, up) => { + case IOCellKey => CustomIOCellParams() +}) + +class WithCustomChipTop extends Config((site, here, up) => { + case BuildTop => (p: Parameters) => new CustomChipTop()(p) +})