diff --git a/build.sbt b/build.sbt index 5d642c1d76..3ca021a796 100644 --- a/build.sbt +++ b/build.sbt @@ -211,7 +211,7 @@ lazy val midas = ProjectRef(firesimDir, "midas") lazy val firesimLib = ProjectRef(firesimDir, "firesimLib") lazy val firechip = conditionalDependsOn(project in file("generators/firechip")) - .dependsOn(chipyard, midasTargetUtils, midas, firesimLib % "test->test;compile->compile") + .dependsOn(chipyard, midasTargetUtils, midas, iocell, firesimLib % "test->test;compile->compile") .settings( commonSettings, testGrouping in Test := isolateAllTests( (definedTests in Test).value ), diff --git a/generators/chipyard/src/main/scala/ChipTop.scala b/generators/chipyard/src/main/scala/ChipTop.scala index cf71987bba..6ae63d5768 100644 --- a/generators/chipyard/src/main/scala/ChipTop.scala +++ b/generators/chipyard/src/main/scala/ChipTop.scala @@ -9,7 +9,7 @@ import freechips.rocketchip.subsystem.{BaseSubsystem, SubsystemDriveAsyncClockGr import freechips.rocketchip.config.{Parameters, Field} import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, LazyRawModuleImp, LazyModuleImpLike} import freechips.rocketchip.util.{ResetCatchAndSync} -import chipyard.iobinders.{IOBinders, TestHarnessFunction, IOBinderTuple} +import chipyard.iobinders._ import barstools.iocell.chisel._ @@ -26,11 +26,9 @@ case object BuildSystem extends Field[Parameters => LazyModule]((p: Parameters) class ChipTop(implicit p: Parameters) extends LazyModule with HasTestHarnessFunctions { // A publicly accessible list of IO cells (useful for a floorplanning tool, for example) val iocells = ArrayBuffer.empty[IOCell] - // A list of functions to call in the test harness - val harnessFunctions = ArrayBuffer.empty[TestHarnessFunction] // The system module specified by BuildSystem - val lSystem = LazyModule(p(BuildSystem)(p)).suggestName("system") + val lazySystem = LazyModule(p(BuildSystem)(p)).suggestName("system") // The implicitClockSinkNode provides the implicit clock and reset for the System val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters())) @@ -50,15 +48,13 @@ class ChipTop(implicit p: Parameters) extends LazyModule with HasTestHarnessFunc // The implicit clock and reset for the system is also, by convention, used for all the IOBinders // TODO: This may not be the right thing to do in all cases - withClockAndReset(implicit_clock, implicit_reset) { - val (_ports, _iocells, _harnessFunctions) = p(IOBinders).values.flatMap(f => f(lSystem) ++ f(lSystem.module)).unzip3 - // We ignore _ports for now... - iocells ++= _iocells.flatten - harnessFunctions ++= _harnessFunctions.flatten - } + val (_ports, _iocells, _portMap) = ApplyIOBinders(lazySystem, p(IOBinders)) + // We ignore _ports for now... + iocells ++= _iocells + portMap ++= _portMap // Connect the implicit clock/reset, if present - lSystem.module match { case l: LazyModuleImp => { + lazySystem.module match { case l: LazyModuleImp => { l.clock := implicit_clock l.reset := implicit_reset }} diff --git a/generators/chipyard/src/main/scala/Clocks.scala b/generators/chipyard/src/main/scala/Clocks.scala index 3fa349b599..d6b19e8d42 100644 --- a/generators/chipyard/src/main/scala/Clocks.scala +++ b/generators/chipyard/src/main/scala/Clocks.scala @@ -91,7 +91,7 @@ object ClockingSchemeGenerators { chiptop.implicitClockSinkNode := implicitClockSourceNode // Drive the diplomaticclock graph of the DigitalTop (if present) - val simpleClockGroupSourceNode = chiptop.lSystem match { + val simpleClockGroupSourceNode = chiptop.lazySystem match { case l: BaseSubsystem if (p(SubsystemDriveAsyncClockGroupsKey).isEmpty) => { val n = ClockGroupSourceNode(Seq(ClockGroupSourceParameters())) l.asyncClockGroupsNode := n @@ -120,6 +120,7 @@ object ClockingSchemeGenerators { } }} + chiptop.harnessFunctions += ((th: HasHarnessSignalReferences) => { clock_io := th.harnessClock Nil @@ -137,7 +138,7 @@ object ClockingSchemeGenerators { val implicitClockSourceNode = ClockSourceNode(Seq(ClockSourceParameters())) chiptop.implicitClockSinkNode := implicitClockSourceNode - val simpleClockGroupSourceNode = chiptop.lSystem match { + val simpleClockGroupSourceNode = chiptop.lazySystem match { case l: BaseSubsystem if (p(SubsystemDriveAsyncClockGroupsKey).isEmpty) => { val n = ClockGroupSourceNode(Seq(ClockGroupSourceParameters())) l.asyncClockGroupsNode := n diff --git a/generators/chipyard/src/main/scala/HarnessBinders.scala b/generators/chipyard/src/main/scala/HarnessBinders.scala new file mode 100644 index 0000000000..54c9904291 --- /dev/null +++ b/generators/chipyard/src/main/scala/HarnessBinders.scala @@ -0,0 +1,274 @@ +package chipyard.harness + +import chisel3._ + +import freechips.rocketchip.config.{Field, Config, Parameters} +import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImpLike} +import freechips.rocketchip.amba.axi4.{AXI4Bundle, AXI4SlaveNode, AXI4MasterNode, AXI4EdgeParameters} +import freechips.rocketchip.devices.debug._ +import freechips.rocketchip.jtag.{JTAGIO} +import freechips.rocketchip.system.{SimAXIMem} +import freechips.rocketchip.subsystem._ + +import sifive.blocks.devices.gpio._ +import sifive.blocks.devices.uart._ +import sifive.blocks.devices.spi._ + +import barstools.iocell.chisel._ + +import testchipip._ + +import chipyard.HasHarnessSignalReferences + +import tracegen.{TraceGenSystemModuleImp} +import icenet.{CanHavePeripheryIceNICModuleImp, SimNetwork, NicLoopback, NICKey, NICIOvonly} + +import scala.reflect.{ClassTag} + +case object HarnessBinders extends Field[Map[String, (Any, HasHarnessSignalReferences, Seq[Data]) => Seq[Any]]]( + Map[String, (Any, HasHarnessSignalReferences, Seq[Data]) => Seq[Any]]().withDefaultValue((t: Any, th: HasHarnessSignalReferences, d: Seq[Data]) => Nil) +) + + +object ApplyHarnessBinders { + def apply(th: HasHarnessSignalReferences, sys: LazyModule, map: Map[String, (Any, HasHarnessSignalReferences, Seq[Data]) => Seq[Any]], portMap: Map[String, Seq[Data]]) = { + val pm = portMap.withDefaultValue(Nil) + map.map { case (s, f) => f(sys, th, pm(s)) ++ f(sys.module, th, pm(s)) } + } +} + +class OverrideHarnessBinder[T](fn: => (T, HasHarnessSignalReferences, Seq[Data]) => Seq[Any])(implicit tag: ClassTag[T]) extends Config((site, here, up) => { + case HarnessBinders => up(HarnessBinders, site) + (tag.runtimeClass.toString -> + ((t: Any, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + t match { + case system: T => fn(system, th, ports) + case _ => Nil + } + }) + ) +}) + +class ComposeHarnessBinder[T](fn: => (T, HasHarnessSignalReferences, Seq[Data]) => Seq[Any])(implicit tag: ClassTag[T]) extends Config((site, here, up) => { + case HarnessBinders => up(HarnessBinders, site) + (tag.runtimeClass.toString -> + ((t: Any, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + t match { + case system: T => up(HarnessBinders, site)(tag.runtimeClass.toString)(system, th, ports) ++ fn(system, th, ports) + case _ => Nil + } + }) + ) +}) + +class WithGPIOTiedOff extends OverrideHarnessBinder({ + (system: HasPeripheryGPIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + ports.map { case p: GPIOPortIO => p <> AnalogConst(0) } + Nil + } +}) + +class WithUARTAdapter extends OverrideHarnessBinder({ + (system: HasPeripheryUARTModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + UARTAdapter.connect(ports.map(_.asInstanceOf[UARTPortIO]))(system.p) + Nil + } +}) + +class WithSimSPIFlashModel(rdOnly: Boolean = true) extends OverrideHarnessBinder({ + (system: HasPeripherySPIFlashModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + SimSPIFlashModel.connect(ports.map(_.asInstanceOf[SPIChipIO]), th.harnessReset, rdOnly)(system.p) + Nil + } +}) + +class WithSimBlockDevice extends OverrideHarnessBinder({ + (system: CanHavePeripheryBlockDeviceModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + val clock = WireInit(false.B.asClock) + ports.map { + case p: BlockDeviceIO => SimBlockDevice.connect(clock, th.harnessReset.asBool, Some(p))(system.p) + case c: Clock => clock := c + } + Nil + } +}) + +class WithBlockDeviceModel extends OverrideHarnessBinder({ + (system: CanHavePeripheryBlockDeviceModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + val clock = WireInit(false.B.asClock) + ports.map { + case p: BlockDeviceIO => withClockAndReset(clock, th.harnessReset) { BlockDeviceModel.connect(Some(p))(system.p) } + case c: Clock => clock := c + } + Nil + } +}) + +class WithLoopbackNIC extends OverrideHarnessBinder({ + (system: CanHavePeripheryIceNICModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + val clock = WireInit(false.B.asClock) + ports.map { + case p: NICIOvonly => withClockAndReset(clock, th.harnessReset) { + NicLoopback.connect(Some(p), system.p(NICKey)) + } + case c: Clock => clock := c + } + Nil + } +}) + +class WithSimNetwork extends OverrideHarnessBinder({ + (system: CanHavePeripheryIceNICModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + val clock = WireInit(false.B.asClock) + ports.map { + case p: NICIOvonly => SimNetwork.connect(Some(p), clock, th.harnessReset.asBool) + case c: Clock => clock := c + } + Nil + } +}) + +class WithSimAXIMem extends OverrideHarnessBinder({ + (system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + val p: Parameters = chipyard.iobinders.GetSystemParameters(system) + val clock = WireInit(false.B.asClock) + ports.filter(_.isInstanceOf[Clock]).map { case p: Clock => clock := p } + val axi4_ports = ports.filter(_.isInstanceOf[AXI4Bundle]) + (axi4_ports zip system.memAXI4Node.edges.in).map { case (port: AXI4Bundle, edge) => + val mem = LazyModule(new SimAXIMem(edge, size=p(ExtMem).get.master.size)(p)) + withClockAndReset(clock, th.harnessReset) { + Module(mem.module).suggestName("mem") + } + mem.io_axi4.head <> port + } + Nil + } +}) + +class WithBlackBoxSimMem extends OverrideHarnessBinder({ + (system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + val p: Parameters = chipyard.iobinders.GetSystemParameters(system) + val clock = WireInit(false.B.asClock) + ports.filter(_.isInstanceOf[Clock]).map { case p: Clock => clock := p } + val axi4_ports = ports.collect { case p: AXI4Bundle => p } + (axi4_ports zip system.memAXI4Node.edges.in).map { case (port: AXI4Bundle, edge) => + val memSize = p(ExtMem).get.master.size + val lineSize = p(CacheBlockBytes) + val mem = Module(new SimDRAM(memSize, lineSize, edge.bundle)).suggestName("simdram") + mem.io.axi <> port + mem.io.clock := clock + mem.io.reset := th.harnessReset + } + Nil + } +}) + +class WithSimAXIMMIO extends OverrideHarnessBinder({ + (system: CanHaveMasterAXI4MMIOPort, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + val p: Parameters = chipyard.iobinders.GetSystemParameters(system) + val clock = WireInit(false.B.asClock) + ports.filter(_.isInstanceOf[Clock]).map { case p: Clock => clock := p } + (ports zip system.mmioAXI4Node.edges.in).zipWithIndex.map { case ((port: AXI4Bundle, edge), i) => + val mmio_mem = LazyModule(new SimAXIMem(edge, size = 4096)(p)) + withClockAndReset(clock, th.harnessReset) { + Module(mmio_mem.module).suggestName(s"mmio_mem_${i}") + } + mmio_mem.io_axi4.head <> port + } + Nil + } +}) + +class WithTieOffInterrupts extends OverrideHarnessBinder({ + (system: HasExtInterruptsModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + ports.map { case p: UInt => p := 0.U } + Nil + } +}) + +class WithTieOffL2FBusAXI extends OverrideHarnessBinder({ + (system: CanHaveSlaveAXI4Port, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + ports.map { case p: AXI4Bundle => + p := DontCare + p.tieoff() + } + Nil + } +}) + +class WithSimDebug extends OverrideHarnessBinder({ + (system: HasPeripheryDebugModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + if (!ports.isEmpty) { + val dtm_success = Wire(Bool()) + when (dtm_success) { th.success := true.B } + ports.map { + case d: ClockedDMIIO => + val dtm = Module(new SimDTM()(system.p)).connect(th.harnessClock, th.harnessReset.asBool, d, dtm_success) + case j: JTAGIO => + val jtag = Module(new SimJTAG(tickDelay=3)).connect(j, th.harnessClock, th.harnessReset.asBool, ~(th.harnessReset.asBool), dtm_success) + case _ => + require(false, "We only support DMI or JTAG simulated debug connections") + } + } + Nil + } +}) + +class WithTiedOffDebug extends OverrideHarnessBinder({ + (system: HasPeripheryDebugModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + ports.map { + case d: ClockedDMIIO => + d.dmi.req.valid := false.B + d.dmi.req.bits := DontCare + d.dmi.resp.ready := true.B + d.dmiClock := false.B.asClock + d.dmiReset := true.B + case j: JTAGIO => + j.TCK := true.B.asClock + j.TMS := true.B + j.TDI := true.B + j.TRSTn.foreach { r => r := true.B } + case a: ClockedAPBBundle => + a.tieoff() + a.clock := false.B.asClock + a.reset := true.B.asAsyncReset + a.psel := false.B + a.penable := false.B + case _ => require(false) + } + Nil + } +}) + +class WithTiedOffSerial extends OverrideHarnessBinder({ + (system: CanHavePeripherySerial, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + ports.map { case p: SerialIO => SerialAdapter.tieoff(Some(p)) } + Nil + } +}) + +class WithSimSerial extends OverrideHarnessBinder({ + (system: CanHavePeripherySerial, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + val serial_clock = WireInit(false.B.asClock) + ports.map { + case p: SerialIO => + val ser_success = SerialAdapter.connectSimSerial(p, serial_clock, th.harnessReset) + when (ser_success) { th.success := true.B } + case c: Clock => + serial_clock := c + } + Nil + } +}) + +class WithTraceGenSuccess extends OverrideHarnessBinder({ + (system: TraceGenSystemModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + ports.map { case p: Bool => when (p) { th.success := true.B } } + Nil + } +}) + +class WithSimDromajoBridge extends ComposeHarnessBinder({ + (system: CanHaveTraceIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + ports.map { case p: TraceOutputTop => p.traces.map(tileTrace => SimDromajoBridge(tileTrace)(system.p)) } + Nil + } +}) diff --git a/generators/chipyard/src/main/scala/IOBinders.scala b/generators/chipyard/src/main/scala/IOBinders.scala index 54a0d1dc72..0dad7e21b9 100644 --- a/generators/chipyard/src/main/scala/IOBinders.scala +++ b/generators/chipyard/src/main/scala/IOBinders.scala @@ -1,9 +1,8 @@ -package chipyard -package object iobinders { +package chipyard.iobinders import chisel3._ import chisel3.util.experimental.{BoringUtils} -import chisel3.experimental.{Analog, IO} +import chisel3.experimental.{Analog, IO, DataMirror} import freechips.rocketchip.config.{Field, Config, Parameters} import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImpLike} @@ -23,7 +22,9 @@ import tracegen.{TraceGenSystemModuleImp} import barstools.iocell.chisel._ import testchipip._ -import icenet.{CanHavePeripheryIceNICModuleImp, SimNetwork, NicLoopback, NICKey} +import icenet.{CanHavePeripheryIceNICModuleImp, SimNetwork, NicLoopback, NICKey, NICIOvonly} + +import chipyard.GlobalResetSchemeKey import scala.reflect.{ClassTag} @@ -43,17 +44,22 @@ import scala.reflect.{ClassTag} // DOC include start: IOBinders // This type describes a function callable on the TestHarness instance. Its return type is unused. -type TestHarnessFunction = (chipyard.HasHarnessSignalReferences) => Seq[Any] -// IOBinders will return a Seq of this tuple, which contains three fields: -// 1. A Seq containing all IO ports created by the IOBinder function -// 2. A Seq containing all IO cell modules created by the IOBinder function -// 3. An optional function to call inside the test harness (e.g. to connect the IOs) -type IOBinderTuple = (Seq[Data], Seq[IOCell], Option[TestHarnessFunction]) - -case object IOBinders extends Field[Map[String, (Any) => Seq[IOBinderTuple]]]( - Map[String, (Any) => Seq[IOBinderTuple]]().withDefaultValue((Any) => Nil) + + + +case object IOBinders extends Field[Map[String, (Any) => (Seq[Data], Seq[IOCell])]]( + Map[String, (Any) => (Seq[Data], Seq[IOCell])]().withDefaultValue((Any) => (Nil, Nil)) ) +object ApplyIOBinders { + def apply(sys: LazyModule, map: Map[String, (Any) => (Seq[Data], Seq[IOCell])]): + (Iterable[Data], Iterable[IOCell], Map[String, Seq[Data]]) = { + val r = map.map({ case (s,f) => (f(sys), s) }) ++ map.map({ case (s,f) => (f(sys.module), s) }) + (r.flatMap(_._1._1), r.flatMap(_._1._2), r.map { t => t._2 -> t._1._1 }) + } +} + + // Note: The parameters instance is accessible only through LazyModule // or LazyModuleImpLike. The self-type requirement in traits like // CanHaveMasterAXI4MemPort is insufficient to make it accessible to the IOBinder @@ -71,12 +77,12 @@ object GetSystemParameters { // This macro overrides previous matches on some Top mixin. This is useful for // binders which drive IO, since those typically cannot be composed -class OverrideIOBinder[T](fn: => (T) => Seq[IOBinderTuple])(implicit tag: ClassTag[T]) extends Config((site, here, up) => { +class OverrideIOBinder[T](fn: => (T) => (Seq[Data], Seq[IOCell]))(implicit tag: ClassTag[T]) extends Config((site, here, up) => { case IOBinders => up(IOBinders, site) + (tag.runtimeClass.toString -> ((t: Any) => { t match { case system: T => fn(system) - case _ => Nil + case _ => (Nil, Nil) } }) ) @@ -84,32 +90,44 @@ class OverrideIOBinder[T](fn: => (T) => Seq[IOBinderTuple])(implicit tag: ClassT // This macro composes with previous matches on some Top mixin. This is useful for // annotation-like binders, since those can typically be composed -class ComposeIOBinder[T](fn: => (T) => Seq[IOBinderTuple])(implicit tag: ClassTag[T]) extends Config((site, here, up) => { +class ComposeIOBinder[T](fn: => (T) => (Seq[Data], Seq[IOCell]))(implicit tag: ClassTag[T]) extends Config((site, here, up) => { case IOBinders => up(IOBinders, site) + (tag.runtimeClass.toString -> ((t: Any) => { t match { - case system: T => (up(IOBinders, site)(tag.runtimeClass.toString)(system) - ++ fn(system)) - case _ => Nil + case system: T => + val r = up(IOBinders, site)(tag.runtimeClass.toString)(system) + val h = fn(system) + (r._1 ++ h._1, r._2 ++ h._2) + case _ => (Nil, Nil) } }) ) }) +object BoreHelper { + def apply(name: String, source: Clock): Clock = { + val clock_io = IO(Output(Clock())).suggestName(name) + val clock_wire = Wire(Clock()).suggestName(s"chiptop_${name}") + dontTouch(clock_wire) + clock_wire := false.B.asClock // necessary for BoringUtils to work properly + BoringUtils.bore(source, Seq(clock_wire)) + clock_io := clock_wire + clock_io + } +} + // DOC include end: IOBinders -object AddIOCells { - /** - * Add IO cells to a SiFive GPIO devices and name the IO ports. - * @param gpios A Seq of GPIO port bundles - * @param genFn A callable function to generate a DigitalGPIOCell module to use - * @return Returns a tuple of (a 2D Seq of Analog IOs corresponding to individual GPIO pins; a 2D Seq of IOCell module references) - */ - def gpio(gpios: Seq[GPIOPortIO], genFn: () => DigitalGPIOCell = IOCell.genericGPIO): (Seq[Seq[Analog]], Seq[Seq[IOCell]]) = { - gpios.zipWithIndex.map({ case (gpio, i) => + +case object IOCellKey extends Field[IOCellTypeParams](GenericIOCellParams()) + + +class WithGPIOCells extends OverrideIOBinder({ + (system: HasPeripheryGPIOModuleImp) => { + val (ports2d, cells2d) = system.gpio.zipWithIndex.map({ case (gpio, i) => gpio.pins.zipWithIndex.map({ case (pin, j) => val g = IO(Analog(1.W)).suggestName(s"gpio_${i}_${j}") - val iocell = genFn().suggestName(s"iocell_gpio_${i}_${j}") + val iocell = system.p(IOCellKey).gpio().suggestName(s"iocell_gpio_${i}_${j}") iocell.io.o := pin.o.oval iocell.io.oe := pin.o.oe iocell.io.ie := pin.o.ie @@ -118,40 +136,35 @@ object AddIOCells { (g, iocell) }).unzip }).unzip + (ports2d.flatten, cells2d.flatten) } +}) + - /** - * Add IO cells to a SiFive UART devices and name the IO ports. - * @param uartPins A Seq of UART port bundles - * @return Returns a tuple of (A Seq of top-level UARTPortIO IOs; a 2D Seq of IOCell module references) - */ - def uart(uartPins: Seq[UARTPortIO]): (Seq[UARTPortIO], Seq[Seq[IOCell]]) = { - uartPins.zipWithIndex.map({ case (u, i) => - val (port, ios) = IOCell.generateIOFromSignal(u, Some(s"iocell_uart_${i}")) +class WithUARTIOCells extends OverrideIOBinder({ + (system: HasPeripheryUARTModuleImp) => { + val (ports, cells2d) = system.uart.zipWithIndex.map({ case (u, i) => + val (port, ios) = IOCell.generateIOFromSignal(u, Some(s"iocell_uart_${i}"), system.p(IOCellKey)) port.suggestName(s"uart_${i}") (port, ios) }).unzip + (ports, cells2d.flatten) } +}) - /** - * Add IO cells to a SiFive SPI devices and name the IO ports. - * @param spiPins A Seq of SPI port bundles - * @param basename The base name for this port (defaults to "spi") - * @param genFn A callable function to generate a DigitalGPIOCell module to use - * @return Returns a tuple of (A Seq of top-level SPIChipIO IOs; a 2D Seq of IOCell module references) - */ - def spi(spiPins: Seq[SPIPortIO], basename: String = "spi", genFn: () => DigitalGPIOCell = IOCell.genericGPIO): (Seq[SPIChipIO], Seq[Seq[IOCell]]) = { - spiPins.zipWithIndex.map({ case (s, i) => - val port = IO(new SPIChipIO(s.c.csWidth)).suggestName(s"${basename}_${i}") - val iocellBase = s"iocell_${basename}_${i}" +class WithSPIIOCells extends OverrideIOBinder({ + (system: HasPeripherySPIFlashModuleImp) => { + val (ports, cells2d) = system.qspi.zipWithIndex.map({ case (s, i) => + val port = IO(new SPIChipIO(s.c.csWidth)).suggestName(s"spi_${i}") + val iocellBase = s"iocell_spi_${i}" // SCK and CS are unidirectional outputs - val sckIOs = IOCell.generateFromSignal(s.sck, port.sck, Some(s"${iocellBase}_sck")) - val csIOs = IOCell.generateFromSignal(s.cs, port.cs, Some(s"${iocellBase}_cs")) + val sckIOs = IOCell.generateFromSignal(s.sck, port.sck, Some(s"${iocellBase}_sck"), system.p(IOCellKey)) + val csIOs = IOCell.generateFromSignal(s.cs, port.cs, Some(s"${iocellBase}_cs"), system.p(IOCellKey)) // DQ are bidirectional, so then need special treatment val dqIOs = s.dq.zip(port.dq).zipWithIndex.map { case ((pin, ana), j) => - val iocell = genFn().suggestName(s"${iocellBase}_dq_${j}") + val iocell = system.p(IOCellKey).gpio().suggestName(s"${iocellBase}_dq_${j}") iocell.io.o := pin.o iocell.io.oe := pin.oe iocell.io.ie := true.B @@ -162,17 +175,27 @@ object AddIOCells { (port, dqIOs ++ csIOs ++ sckIOs) }).unzip + (ports, cells2d.flatten) + } +}) + +class WithExtInterruptIOCells extends OverrideIOBinder({ + (system: HasExtInterruptsModuleImp) => { + if (system.outer.nExtInterrupts > 0) { + val (port, cells) = IOCell.generateIOFromSignal(system.interrupts, Some("iocell_interrupts"), system.p(IOCellKey)) + port.suggestName("ext_interrupts") + (Seq(port), cells) + } else { + (Nil, Nil) + } } +}) + - /** - * Add IO cells to a debug module and name the IO ports, for debug IO which must go off-chip - * For on-chip debug IO, drive them appropriately - * Mostly copied from rocket-chip/src/main/scala/devices/debug/Periphery.scala - * @param system A BaseSubsystem that might have a debug module - * @return Returns a tuple2 of (Generated debug io ports, Generated IOCells) - */ - def debug(system: HasPeripheryDebugModuleImp)(implicit p: Parameters): (Seq[Bundle], Seq[IOCell]) = { - system.debug.map { debug => +class WithDebugIOCells extends OverrideIOBinder({ + (system: HasPeripheryDebugModuleImp) => { + system.debug.map({ debug => + val p = system.p val tlbus = system.outer.asInstanceOf[BaseSubsystem].locateTLBusWrapper(p(ExportDebug).slaveWhere) val debug_clock = Wire(Clock()).suggestName("debug_clock") val debug_reset = Wire(Reset()).suggestName("debug_reset") @@ -204,288 +227,130 @@ object AddIOCells { // Add IOCells for the DMI/JTAG/APB ports val dmiTuple = debug.clockeddmi.map { d => - IOCell.generateIOFromSignal(d, Some("iocell_dmi"), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync) + IOCell.generateIOFromSignal(d, Some("iocell_dmi"), p(IOCellKey), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync) } dmiTuple.map(_._1).foreach(_.suggestName("dmi")) val jtagTuple = debug.systemjtag.map { j => - IOCell.generateIOFromSignal(j.jtag, Some("iocell_jtag"), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync) + IOCell.generateIOFromSignal(j.jtag, Some("iocell_jtag"), p(IOCellKey), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync) } jtagTuple.map(_._1).foreach(_.suggestName("jtag")) val apbTuple = debug.apb.map { a => - IOCell.generateIOFromSignal(a, Some("iocell_apb"), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync) + IOCell.generateIOFromSignal(a, Some("iocell_apb"), p(IOCellKey), abstractResetAsAsync = p(GlobalResetSchemeKey).pinIsAsync) } apbTuple.map(_._1).foreach(_.suggestName("apb")) val allTuples = (dmiTuple ++ jtagTuple ++ apbTuple).toSeq (allTuples.map(_._1).toSeq, allTuples.flatMap(_._2).toSeq) - }.getOrElse((Nil, Nil)) - } - - /** - * Add IO cells to a serial module and name the IO ports. - * @param serial A SerialIO bundle - * @return Returns a tuple of (Top-level SerialIO IO; a list of IOCell module references) - */ - def serial(serial: SerialIO): (SerialIO, Seq[IOCell]) = { - val (port, ios) = IOCell.generateIOFromSignal(serial, Some("iocell_serial")) - port.suggestName("serial") - (port, ios) - } - - def axi4(io: Seq[AXI4Bundle], node: AXI4SlaveNode, name: String): Seq[(AXI4Bundle, AXI4EdgeParameters, Seq[IOCell])] = { - io.zip(node.edges.in).zipWithIndex.map{ case ((mem_axi4, edge), i) => { - val (port, ios) = IOCell.generateIOFromSignal(mem_axi4, Some(s"iocell_${name}_axi4_slave_${i}")) - port.suggestName(s"${name}_axi4_slave_${i}") - (port, edge, ios) - }} - } - def axi4(io: Seq[AXI4Bundle], node: AXI4MasterNode, name: String): Seq[(AXI4Bundle, AXI4EdgeParameters, Seq[IOCell])] = { - io.zip(node.edges.out).zipWithIndex.map{ case ((mem_axi4, edge), i) => { - //val (port, ios) = IOCell.generateIOFromSignal(mem_axi4, Some(s"iocell_${name}_axi4_master_${i}")) - val port = IO(Flipped(AXI4Bundle(edge.bundle))) - val ios = IOCell.generateFromSignal(mem_axi4, port, Some(s"iocell_${name}_axi4_master_${i}")) - port.suggestName(s"${name}_axi4_master_${i}") - (port, edge, ios) - }} - } - - def blockDev(bdev: BlockDeviceIO): (BlockDeviceIO, Seq[IOCell]) = { - val (port, ios) = IOCell.generateIOFromSignal(bdev, Some("iocell_bdev")) - port.suggestName("bdev") - (port, ios) - } -} - -// DOC include start: WithGPIOTiedOff -class WithGPIOTiedOff extends OverrideIOBinder({ - (system: HasPeripheryGPIOModuleImp) => { - val (ports2d, ioCells2d) = AddIOCells.gpio(system.gpio) - val harnessFn = (th: HasHarnessSignalReferences) => { ports2d.flatten.foreach(_ <> AnalogConst(0)); Nil } - Seq((ports2d.flatten, ioCells2d.flatten, Some(harnessFn))) - } -}) -// DOC include end: WithGPIOTiedOff - -class WithUARTAdapter extends OverrideIOBinder({ - (system: HasPeripheryUARTModuleImp) => { - val (ports, ioCells2d) = AddIOCells.uart(system.uart) - val harnessFn = (th: HasHarnessSignalReferences) => { UARTAdapter.connect(ports)(system.p); Nil } - Seq((ports, ioCells2d.flatten, Some(harnessFn))) + }).getOrElse((Nil, Nil)) } }) -class WithSimSPIFlashModel(rdOnly: Boolean = true) extends OverrideIOBinder({ - (system: HasPeripherySPIFlashModuleImp) => { - val (ports, ioCells2d) = AddIOCells.spi(system.qspi, "qspi") - val harnessFn = (th: HasHarnessSignalReferences) => { SimSPIFlashModel.connect(ports, th.harnessReset, rdOnly)(system.p); Nil } - Seq((ports, ioCells2d.flatten, Some(harnessFn))) - } -}) - -class WithSimBlockDevice extends OverrideIOBinder({ - (system: CanHavePeripheryBlockDeviceModuleImp) => system.bdev.map { bdev => - val (port, ios) = AddIOCells.blockDev(bdev) - val harnessFn = (th: HasHarnessSignalReferences) => { - // TODO: Using harness clock/reset will be incorrect when systemClock =/= harnessClock - SimBlockDevice.connect(th.harnessClock, th.harnessReset.asBool, Some(port))(system.p) - Nil - } - Seq((Seq(port), ios, Some(harnessFn))) - }.getOrElse(Nil) -}) - -class WithBlockDeviceModel extends OverrideIOBinder({ - (system: CanHavePeripheryBlockDeviceModuleImp) => system.bdev.map { bdev => - val (port, ios) = AddIOCells.blockDev(bdev) - val harnessFn = (th: HasHarnessSignalReferences) => { - BlockDeviceModel.connect(Some(port))(system.p) - Nil - } - Seq((Seq(port), ios, Some(harnessFn))) - }.getOrElse(Nil) -}) - -class WithLoopbackNIC extends OverrideIOBinder({ - (system: CanHavePeripheryIceNICModuleImp) => system.connectNicLoopback(); Nil -}) - -class WithSimNIC extends OverrideIOBinder({ - (system: CanHavePeripheryIceNICModuleImp) => system.connectSimNetwork(system.clock, system.reset.asBool); Nil +class WithSerialIOCells extends OverrideIOBinder({ + (system: CanHavePeripherySerial) => system.serial.map({ s => + val sys = system.asInstanceOf[BaseSubsystem] + val (port, cells) = IOCell.generateIOFromSignal(s, Some("iocell_serial"), sys.p(IOCellKey)) + val serial_clock = Wire(Output(Clock())).suggestName("chiptop_serial_clock") + serial_clock := false.B.asClock // necessary for BoringUtils to work properly + dontTouch(serial_clock) + BoringUtils.bore(sys.fbus.module.clock, Seq(serial_clock)) + val (serial_clock_io, serial_clock_cell) = IOCell.generateIOFromSignal(serial_clock, Some("serial_clock"), sys.p(IOCellKey)) + serial_clock_io.suggestName("serial_clock") + port.suggestName("serial") + (Seq(port, serial_clock_io), cells ++ serial_clock_cell) + }).getOrElse((Nil, Nil)) }) -// DOC include start: WithSimAXIMem -class WithSimAXIMem extends OverrideIOBinder({ - (system: CanHaveMasterAXI4MemPort) => { - implicit val p: Parameters = GetSystemParameters(system) - val peiTuples = AddIOCells.axi4(system.mem_axi4, system.memAXI4Node, "mem") - // TODO: we are inlining the connectMem method of SimAXIMem because - // it takes in a dut rather than seq of axi4 ports - val harnessFn = (th: HasHarnessSignalReferences) => { - peiTuples.map { case (port, edge, ios) => - val mem = LazyModule(new SimAXIMem(edge, size = p(ExtMem).get.master.size)) - Module(mem.module).suggestName("mem") - mem.io_axi4.head <> port - } - Nil - } - Seq((peiTuples.map(_._1), peiTuples.flatMap(_._3), Some(harnessFn))) - } -}) -// DOC include end: WithSimAXIMem -class WithBlackBoxSimMem extends OverrideIOBinder({ +class WithAXI4MemPunchthrough extends OverrideIOBinder({ (system: CanHaveMasterAXI4MemPort) => { - implicit val p: Parameters = GetSystemParameters(system) - val peiTuples = AddIOCells.axi4(system.mem_axi4, system.memAXI4Node, "mem") - val harnessFn = (th: HasHarnessSignalReferences) => { - peiTuples.map { case (port, edge, ios) => - val memSize = p(ExtMem).get.master.size - val lineSize = p(CacheBlockBytes) - val mem = Module(new SimDRAM(memSize, lineSize, edge.bundle)) - mem.io.axi <> port - // TODO: Using harness clock/reset will be incorrect when systemClock =/= harnessClock - mem.io.clock := th.harnessClock - mem.io.reset := th.harnessReset - } - Nil + val clock = if (!system.mem_axi4.isEmpty) { + Some(BoreHelper("axi4_mem_clock", system.asInstanceOf[BaseSubsystem].mbus.module.clock)) + } else { + None } - Seq((peiTuples.map(_._1), peiTuples.flatMap(_._3), Some(harnessFn))) + val ports = system.mem_axi4.map({ m => + val p = IO(DataMirror.internal.chiselTypeClone[AXI4Bundle](m)).suggestName("axi4_mem") + p <> m + p + }) + (ports ++ clock, Nil) } }) -class WithSimAXIMMIO extends OverrideIOBinder({ +class WithAXI4MMIOPunchthrough extends OverrideIOBinder({ (system: CanHaveMasterAXI4MMIOPort) => { - implicit val p: Parameters = GetSystemParameters(system) - val peiTuples = AddIOCells.axi4(system.mmio_axi4, system.mmioAXI4Node, "mmio_mem") - val harnessFn = (th: HasHarnessSignalReferences) => { - peiTuples.zipWithIndex.map { case ((port, edge, ios), i) => - val mmio_mem = LazyModule(new SimAXIMem(edge, size = 4096)) - Module(mmio_mem.module).suggestName(s"mmio_mem_${i}") - mmio_mem.io_axi4.head <> port - } - Nil + val clock = if (!system.mmio_axi4.isEmpty) { + Some(BoreHelper("axi4_mmio_clock", system.asInstanceOf[BaseSubsystem].mbus.module.clock)) + } else { + None } - Seq((peiTuples.map(_._1), peiTuples.flatMap(_._3), Some(harnessFn))) + val ports = system.mmio_axi4.map({ m => + val p = IO(DataMirror.internal.chiselTypeClone[AXI4Bundle](m)).suggestName("axi4_mmio") + p <> m + p + }) + (ports ++ clock, Nil) } }) -class WithDontTouchPorts extends OverrideIOBinder({ - (system: DontTouch) => system.dontTouchPorts(); Nil -}) - -class WithTieOffInterrupts extends OverrideIOBinder({ - (system: HasExtInterruptsModuleImp) => { - val (port, ioCells) = IOCell.generateIOFromSignal(system.interrupts, Some("iocell_interrupts")) - port.suggestName("interrupts") - val harnessFn = (th: HasHarnessSignalReferences) => { port := 0.U; Nil } - Seq((Seq(port), ioCells, Some(harnessFn))) - } -}) - -class WithTieOffL2FBusAXI extends OverrideIOBinder({ +class WithL2FBusAXI4Punchthrough extends OverrideIOBinder({ (system: CanHaveSlaveAXI4Port) => { - val peiTuples = AddIOCells.axi4(system.l2_frontend_bus_axi4, system.l2FrontendAXI4Node, "l2_fbus") - val harnessFn = (th: HasHarnessSignalReferences) => { - peiTuples.zipWithIndex.map { case ((port, edge, ios), i) => - port := DontCare // tieoff doesn't completely tie-off, for some reason - port.tieoff() - } - Nil + val port = system.l2_frontend_bus_axi4.map { m => + val p = IO(DataMirror.internal.chiselTypeClone[AXI4Bundle](m)).suggestName("axi4_fbus") + p <> m + p } - Seq((peiTuples.map(_._1), peiTuples.flatMap(_._3), Some(harnessFn))) + (port, Nil) } }) -class WithSimDebug extends OverrideIOBinder({ - (system: HasPeripheryDebugModuleImp) => { - val (ports, iocells) = AddIOCells.debug(system)(system.p) - val harnessFn = (th: HasHarnessSignalReferences) => { - val dtm_success = WireInit(false.B) - when (dtm_success) { th.success := true.B } - ports.map { - case d: ClockedDMIIO => - val dtm = Module(new SimDTM()(system.p)).connect(th.harnessClock, th.harnessReset.asBool, d, dtm_success) - case j: JTAGIO => - val jtag = Module(new SimJTAG(tickDelay=3)).connect(j, th.harnessClock, th.harnessReset.asBool, ~(th.harnessReset.asBool), dtm_success) - case _ => - require(false, "We only support DMI or JTAG simulated debug connections") - } - Nil - } - Seq((ports, iocells, Some(harnessFn))) +class WithBlockDeviceIOPunchthrough extends OverrideIOBinder({ + (system: CanHavePeripheryBlockDeviceModuleImp) => { + val ports = system.bdev.map({ bdev => + val p = IO(new BlockDeviceIO()(system.p)).suggestName("blockdev") + val clock = BoreHelper("blkdev_clk", system.outer.controller.get.module.clock) + p <> bdev + Seq(p, clock) + }).getOrElse(Nil) + (ports, Nil) } }) -class WithTiedOffDebug extends OverrideIOBinder({ - (system: HasPeripheryDebugModuleImp) => { - val (ports, iocells) = AddIOCells.debug(system)(system.p) - val harnessFn = (th: HasHarnessSignalReferences) => { - ports.map { - case d: ClockedDMIIO => - d.dmi.req.valid := false.B - d.dmi.req.bits := DontCare - d.dmi.resp.ready := true.B - d.dmiClock := false.B.asClock - d.dmiReset := true.B - case j: JTAGIO => - j.TCK := true.B.asClock - j.TMS := true.B - j.TDI := true.B - j.TRSTn.foreach { r => r := true.B } - case a: ClockedAPBBundle => - a.tieoff() - a.clock := false.B.asClock - a.reset := true.B.asAsyncReset - a.psel := false.B - a.penable := false.B - case _ => require(false) - } - Nil - } - Seq((ports, iocells, Some(harnessFn))) +class WithNICIOPunchthrough extends OverrideIOBinder({ + (system: CanHavePeripheryIceNICModuleImp) => { + val port = system.net.map({ n => + val p = IO(new NICIOvonly).suggestName("nic") + val clock = BoreHelper("nic_clk", system.outer.icenicOpt.get.module.clock) + p <> n + Seq(p, clock) + }).getOrElse(Nil) + (port.toSeq, Nil) } }) -class WithTiedOffSerial extends OverrideIOBinder({ - (system: CanHavePeripherySerialModuleImp) => system.serial.map({ serial => - val (port, ioCells) = AddIOCells.serial(serial) - val harnessFn = (th: HasHarnessSignalReferences) => { - SerialAdapter.tieoff(port) - Nil - } - Seq((Seq(port), ioCells, Some(harnessFn))) - }).getOrElse(Nil) +class WithTraceGenSuccessPunchthrough extends OverrideIOBinder({ + (system: TraceGenSystemModuleImp) => { + val success = IO(Output(Bool())).suggestName("success") + success := system.success + (Seq(success), Nil) + } }) -class WithSimSerial extends OverrideIOBinder({ - (system: CanHavePeripherySerialModuleImp) => system.serial.map({ serial => - val (port, ioCells) = AddIOCells.serial(serial) - val harnessFn = (th: HasHarnessSignalReferences) => { - val ser_success = SerialAdapter.connectSimSerial(port, th.harnessClock, th.harnessReset) - when (ser_success) { th.success := true.B } - Nil +class WithTraceIOPunchthrough extends OverrideIOBinder({ + (system: CanHaveTraceIOModuleImp) => { + val ports = system.traceIO.map { t => + val trace = IO(DataMirror.internal.chiselTypeClone[TraceOutputTop](t)).suggestName("trace") + trace <> t + trace } - Seq((Seq(port), ioCells, Some(harnessFn))) - }).getOrElse(Nil) -}) - -class WithTraceGenSuccessBinder extends OverrideIOBinder({ - (system: TraceGenSystemModuleImp) => { - val (successPort, ioCells) = IOCell.generateIOFromSignal(system.success, Some("iocell_success")) - successPort.suggestName("success") - val harnessFn = (th: HasHarnessSignalReferences) => { when (successPort) { th.success := true.B }; Nil } - Seq((Seq(successPort), ioCells, Some(harnessFn))) + (ports.toSeq, Nil) } }) -class WithSimDromajoBridge extends ComposeIOBinder({ - (system: CanHaveTraceIOModuleImp) => { - system.traceIO match { case Some(t) => t.traces.map(tileTrace => SimDromajoBridge(tileTrace)(system.p)) } - Nil - } -}) +class WithDontTouchPorts extends OverrideIOBinder({ + (system: DontTouch) => system.dontTouchPorts(); (Nil, Nil) +}) -} /* end package object */ diff --git a/generators/chipyard/src/main/scala/TestHarness.scala b/generators/chipyard/src/main/scala/TestHarness.scala index b296e328d8..67cf03bf93 100644 --- a/generators/chipyard/src/main/scala/TestHarness.scala +++ b/generators/chipyard/src/main/scala/TestHarness.scala @@ -1,19 +1,22 @@ package chipyard import chisel3._ - +import scala.collection.mutable.{ArrayBuffer} import freechips.rocketchip.diplomacy.{LazyModule} import freechips.rocketchip.config.{Field, Parameters} -import chipyard.iobinders.{TestHarnessFunction} + +import chipyard.harness.{ApplyHarnessBinders, HarnessBinders} // ------------------------------- // Chipyard Test Harness // ------------------------------- -case object BuildTop extends Field[Parameters => LazyModule with HasTestHarnessFunctions]((p: Parameters) => new ChipTop()(p)) +case object BuildTop extends Field[Parameters => LazyModule]((p: Parameters) => new ChipTop()(p)) trait HasTestHarnessFunctions { - val harnessFunctions: Seq[TestHarnessFunction] + val lazySystem: LazyModule + val harnessFunctions = ArrayBuffer.empty[HasHarnessSignalReferences => Seq[Any]] + val portMap = scala.collection.mutable.Map[String, Seq[Data]]() } trait HasHarnessSignalReferences { @@ -39,7 +42,9 @@ class TestHarness(implicit val p: Parameters) extends Module with HasHarnessSign // dutReset assignment can be overridden via a harnessFunction, but by default it is just reset val dutReset = WireDefault(if (p(GlobalResetSchemeKey).pinIsAsync) reset.asAsyncReset else reset) - ldut.harnessFunctions.foreach(_(this)) - + ldut match { case d: HasTestHarnessFunctions => + d.harnessFunctions.foreach(_(this)) + ApplyHarnessBinders(this, d.lazySystem, p(HarnessBinders), d.portMap.toMap) + } } diff --git a/generators/chipyard/src/main/scala/config/AbstractConfig.scala b/generators/chipyard/src/main/scala/config/AbstractConfig.scala index a925ec56c9..59bc68d039 100644 --- a/generators/chipyard/src/main/scala/config/AbstractConfig.scala +++ b/generators/chipyard/src/main/scala/config/AbstractConfig.scala @@ -5,18 +5,49 @@ import freechips.rocketchip.config.{Config} // -------------- // Chipyard abstract ("base") configuration // NOTE: This configuration is NOT INSTANTIABLE, as it defines a empty system with no tiles +// +// The default set of IOBinders instantiate IOcells and ChipTop IOs for digital IO bundles. +// The default set of HarnessBinders instantiate TestHarness hardware for interacting with ChipTop IOs // -------------- class AbstractConfig extends Config( - new chipyard.iobinders.WithUARTAdapter ++ // display UART with a SimUARTAdapter - new chipyard.iobinders.WithTieOffInterrupts ++ // tie off top-level interrupts - new chipyard.iobinders.WithBlackBoxSimMem ++ // drive the master AXI4 memory with a blackbox DRAMSim model - new chipyard.iobinders.WithSimDebug ++ // attach SimJTAG - new chipyard.iobinders.WithSimSerial ++ // drive TSI with SimSerial for testing + // 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.WithBlackBoxSimMem ++ // add SimDRAM DRAM model for axi4 backing memory, if axi4 mem is enabled + new chipyard.harness.WithSimDebug ++ // add SimJTAG or SimDTM adapters if debug module is enabled + new chipyard.harness.WithSimSerial ++ // add SimSerial adapter for HTIF, if serial port is present + 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.WithSerialIOCells ++ + 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 testchipip.WithTSI ++ // use testchipip serial offchip link 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.WithTileClockFreq(1000) ++ + new chipyard.config.WithSystemBusFreq(1000) ++ + new chipyard.config.WithFrontBusFreq(1000) ++ + new chipyard.config.WithControlBusFreq(1000) ++ + new chipyard.config.WithMemoryBusFreq(1000) ++ new chipyard.config.WithNoSubsystemDrivenClocks ++ // drive the subsystem diplomatic clocks from ChipTop instead of using implicit clocks 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) diff --git a/generators/chipyard/src/main/scala/config/ArianeConfigs.scala b/generators/chipyard/src/main/scala/config/ArianeConfigs.scala index 6bc7cf6952..47e7c15b10 100644 --- a/generators/chipyard/src/main/scala/config/ArianeConfigs.scala +++ b/generators/chipyard/src/main/scala/config/ArianeConfigs.scala @@ -13,7 +13,7 @@ class ArianeConfig extends Config( new chipyard.config.AbstractConfig) class dmiArianeConfig extends Config( - new chipyard.iobinders.WithTiedOffSerial ++ // Tie off the serial port, override default instantiation of SimSerial + new chipyard.harness.WithTiedOffSerial ++ // Tie off the serial port, override default instantiation of SimSerial new chipyard.config.WithDMIDTM ++ // have debug module expose a clocked DMI port new ariane.WithNArianeCores(1) ++ // single Ariane core new chipyard.config.AbstractConfig) diff --git a/generators/chipyard/src/main/scala/config/BoomConfigs.scala b/generators/chipyard/src/main/scala/config/BoomConfigs.scala index 575e1f9892..9e1f558ae1 100644 --- a/generators/chipyard/src/main/scala/config/BoomConfigs.scala +++ b/generators/chipyard/src/main/scala/config/BoomConfigs.scala @@ -33,13 +33,13 @@ class HwachaLargeBoomConfig extends Config( new chipyard.config.AbstractConfig) class LoopbackNICLargeBoomConfig extends Config( - new chipyard.iobinders.WithLoopbackNIC ++ // drive NIC IOs with loopback + new chipyard.harness.WithLoopbackNIC ++ // drive NIC IOs with loopback new icenet.WithIceNIC ++ // build a NIC new boom.common.WithNLargeBooms(1) ++ new chipyard.config.AbstractConfig) class DromajoBoomConfig extends Config( - new chipyard.iobinders.WithSimDromajoBridge ++ // attach Dromajo + new chipyard.harness.WithSimDromajoBridge ++ // attach Dromajo new chipyard.config.WithTraceIO ++ // enable the traceio new boom.common.WithNSmallBooms(1) ++ new chipyard.config.AbstractConfig) diff --git a/generators/chipyard/src/main/scala/config/RocketConfigs.scala b/generators/chipyard/src/main/scala/config/RocketConfigs.scala index 420ba192d7..a868696161 100644 --- a/generators/chipyard/src/main/scala/config/RocketConfigs.scala +++ b/generators/chipyard/src/main/scala/config/RocketConfigs.scala @@ -25,7 +25,7 @@ class GemminiRocketConfig extends Config( // DOC include start: DmiRocket class dmiRocketConfig extends Config( - new chipyard.iobinders.WithTiedOffSerial ++ // don't use serial to drive the chip, since we use DMI instead + new chipyard.harness.WithTiedOffSerial ++ // don't use serial to drive the chip, since we use DMI instead new chipyard.config.WithDMIDTM ++ // have debug module expose a clocked DMI port new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) @@ -46,37 +46,36 @@ class GCDAXI4BlackBoxRocketConfig extends Config( // DOC include end: GCDAXI4BlackBoxRocketConfig class LargeSPIFlashROMRocketConfig extends Config( - new chipyard.iobinders.WithSimSPIFlashModel(true) ++ // add the SPI flash model in the harness (read-only) + new chipyard.harness.WithSimSPIFlashModel(true) ++ // add the SPI flash model in the harness (read-only) new chipyard.config.WithSPIFlash ++ // add the SPI flash controller new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) class SmallSPIFlashRocketConfig extends Config( - new chipyard.iobinders.WithSimSPIFlashModel(false) ++ // add the SPI flash model in the harness (writeable) + new chipyard.harness.WithSimSPIFlashModel(false) ++ // add the SPI flash model in the harness (writeable) new chipyard.config.WithSPIFlash(0x100000) ++ // add the SPI flash controller (1 MiB) new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) class SimAXIRocketConfig extends Config( - new chipyard.iobinders.WithSimAXIMem ++ // drive the master AXI4 memory with a SimAXIMem, a 1-cycle magic memory, instead of default SimDRAM + new chipyard.harness.WithSimAXIMem ++ // drive the master AXI4 memory with a SimAXIMem, a 1-cycle magic memory, instead of default SimDRAM new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) class SimBlockDeviceRocketConfig extends Config( - new chipyard.iobinders.WithSimBlockDevice ++ // drive block-device IOs with SimBlockDevice + new chipyard.harness.WithSimBlockDevice ++ // drive block-device IOs with SimBlockDevice new testchipip.WithBlockDevice ++ // add block-device module to peripherybus new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) class BlockDeviceModelRocketConfig extends Config( - new chipyard.iobinders.WithBlockDeviceModel ++ // drive block-device IOs with a BlockDeviceModel + new chipyard.harness.WithBlockDeviceModel ++ // drive block-device IOs with a BlockDeviceModel new testchipip.WithBlockDevice ++ // add block-device module to periphery bus new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) // DOC include start: GPIORocketConfig class GPIORocketConfig extends Config( - new chipyard.iobinders.WithGPIOTiedOff ++ // tie off GPIO inputs into the top new chipyard.config.WithGPIO ++ // add GPIOs to the peripherybus new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) @@ -111,7 +110,7 @@ class InitZeroRocketConfig extends Config( // DOC include end: InitZeroRocketConfig class LoopbackNICRocketConfig extends Config( - new chipyard.iobinders.WithLoopbackNIC ++ // drive NIC IOs with loopback + new chipyard.harness.WithLoopbackNIC ++ // drive NIC IOs with loopback new icenet.WithIceNIC ++ // add an IceNIC new freechips.rocketchip.subsystem.WithNBigCores(1) ++ new chipyard.config.AbstractConfig) @@ -170,8 +169,6 @@ class LargeNVDLARocketConfig extends Config( new chipyard.config.AbstractConfig) class MMIORocketConfig extends Config( - new chipyard.iobinders.WithTieOffL2FBusAXI ++ // Tie-off the incoming MMIO port - new chipyard.iobinders.WithSimAXIMMIO ++ // Attach a simulated memory to the outwards MMIO port new freechips.rocketchip.subsystem.WithDefaultMMIOPort ++ // add default external master port new freechips.rocketchip.subsystem.WithDefaultSlavePort ++ // add default external slave port new freechips.rocketchip.subsystem.WithNBigCores(1) ++ diff --git a/generators/chipyard/src/main/scala/config/TracegenConfigs.scala b/generators/chipyard/src/main/scala/config/TracegenConfigs.scala index 47d567fb3b..28bc5dcdc4 100644 --- a/generators/chipyard/src/main/scala/config/TracegenConfigs.scala +++ b/generators/chipyard/src/main/scala/config/TracegenConfigs.scala @@ -4,8 +4,10 @@ import freechips.rocketchip.config.{Config} import freechips.rocketchip.rocket.{DCacheParams} class TraceGenConfig extends Config( - new chipyard.iobinders.WithBlackBoxSimMem ++ - new chipyard.iobinders.WithTraceGenSuccessBinder ++ + new chipyard.harness.WithBlackBoxSimMem ++ + new chipyard.harness.WithTraceGenSuccess ++ + new chipyard.iobinders.WithAXI4MemPunchthrough ++ + new chipyard.iobinders.WithTraceGenSuccessPunchthrough ++ new chipyard.config.WithTracegenSystem ++ new chipyard.config.WithNoSubsystemDrivenClocks ++ new tracegen.WithTraceGen()(List.fill(2) { DCacheParams(nMSHRs = 0, nSets = 16, nWays = 2) }) ++ @@ -13,8 +15,10 @@ class TraceGenConfig extends Config( new freechips.rocketchip.groundtest.GroundTestBaseConfig) class NonBlockingTraceGenConfig extends Config( - new chipyard.iobinders.WithBlackBoxSimMem ++ - new chipyard.iobinders.WithTraceGenSuccessBinder ++ + new chipyard.harness.WithBlackBoxSimMem ++ + new chipyard.harness.WithTraceGenSuccess ++ + new chipyard.iobinders.WithAXI4MemPunchthrough ++ + new chipyard.iobinders.WithTraceGenSuccessPunchthrough ++ new chipyard.config.WithTracegenSystem ++ new chipyard.config.WithNoSubsystemDrivenClocks ++ new tracegen.WithTraceGen()(List.fill(2) { DCacheParams(nMSHRs = 2, nSets = 16, nWays = 2) }) ++ @@ -22,8 +26,10 @@ class NonBlockingTraceGenConfig extends Config( new freechips.rocketchip.groundtest.GroundTestBaseConfig) class BoomTraceGenConfig extends Config( - new chipyard.iobinders.WithBlackBoxSimMem ++ - new chipyard.iobinders.WithTraceGenSuccessBinder ++ + new chipyard.harness.WithBlackBoxSimMem ++ + new chipyard.harness.WithTraceGenSuccess ++ + new chipyard.iobinders.WithAXI4MemPunchthrough ++ + new chipyard.iobinders.WithTraceGenSuccessPunchthrough ++ new chipyard.config.WithTracegenSystem ++ new chipyard.config.WithNoSubsystemDrivenClocks ++ new tracegen.WithBoomTraceGen()(List.fill(2) { DCacheParams(nMSHRs = 8, nSets = 16, nWays = 2) }) ++ @@ -32,8 +38,10 @@ class BoomTraceGenConfig extends Config( new freechips.rocketchip.groundtest.GroundTestBaseConfig) class NonBlockingTraceGenL2Config extends Config( - new chipyard.iobinders.WithBlackBoxSimMem ++ - new chipyard.iobinders.WithTraceGenSuccessBinder ++ + new chipyard.harness.WithBlackBoxSimMem ++ + new chipyard.harness.WithTraceGenSuccess ++ + new chipyard.iobinders.WithAXI4MemPunchthrough ++ + new chipyard.iobinders.WithTraceGenSuccessPunchthrough ++ new chipyard.config.WithTracegenSystem ++ new chipyard.config.WithNoSubsystemDrivenClocks ++ new tracegen.WithL2TraceGen()(List.fill(2)(DCacheParams(nMSHRs = 2, nSets = 16, nWays = 4))) ++ @@ -42,8 +50,10 @@ class NonBlockingTraceGenL2Config extends Config( new freechips.rocketchip.groundtest.GroundTestBaseConfig) class NonBlockingTraceGenL2RingConfig extends Config( - new chipyard.iobinders.WithBlackBoxSimMem ++ - new chipyard.iobinders.WithTraceGenSuccessBinder ++ + new chipyard.harness.WithBlackBoxSimMem ++ + new chipyard.harness.WithTraceGenSuccess ++ + new chipyard.iobinders.WithAXI4MemPunchthrough ++ + new chipyard.iobinders.WithTraceGenSuccessPunchthrough ++ new chipyard.config.WithTracegenSystem ++ new chipyard.config.WithNoSubsystemDrivenClocks ++ new tracegen.WithL2TraceGen()(List.fill(2)(DCacheParams(nMSHRs = 2, nSets = 16, nWays = 4))) ++ diff --git a/generators/chipyard/src/main/scala/config/TutorialConfigs.scala b/generators/chipyard/src/main/scala/config/TutorialConfigs.scala index d501b6c0a8..e7adbdc154 100644 --- a/generators/chipyard/src/main/scala/config/TutorialConfigs.scala +++ b/generators/chipyard/src/main/scala/config/TutorialConfigs.scala @@ -12,27 +12,16 @@ import freechips.rocketchip.config.{Config} // This file was originally developed for the cancelled ASPLOS-2020 // Chipyard tutorial. While the configs here work, the corresponding -// slideware has not yet been created +// slideware has not yet been created. // NOTE: Configs should be read bottom-up, since they are applied bottom-up +// NOTE: The TutorialConfigs build off of the AbstractConfig defined in AbstractConfig.scala +// Users should try to understand the functionality of the AbstractConfig before proceeding +// with the TutorialConfigs below + // Tutorial Phase 1: Configure the cores, caches class TutorialStarterConfig extends Config( - // IOBinders specify how to connect to IOs in our TestHarness - // These config fragments do not affect - new chipyard.iobinders.WithUARTAdapter ++ // Connect a SimUART adapter to display UART on stdout - new chipyard.iobinders.WithBlackBoxSimMem ++ // Connect simulated external memory - new chipyard.iobinders.WithTieOffInterrupts ++ // Do not simulate external interrupts - new chipyard.iobinders.WithSimDebug ++ // Connect SimJTAG (or SimDTM) widgets to debug ios - new chipyard.iobinders.WithSimSerial ++ // Connect external SimSerial widget to drive TSI - - // Config fragments below this line affect hardware generation - // of the Top - new testchipip.WithTSI ++ // Add a TSI (Test Serial Interface) widget to bring-up the core - new chipyard.config.WithBootROM ++ // Use the Chipyard BootROM - new chipyard.config.WithUART ++ // Add a UART - new chipyard.config.WithNoSubsystemDrivenClocks ++ // Don't drive the subsystem clocks from within the subsystem - // CUSTOMIZE THE CORE // Uncomment out one (or multiple) of the lines below, and choose // how many cores you want. @@ -43,36 +32,11 @@ class TutorialStarterConfig extends Config( // Uncomment this line, and specify a size if you want to have a L2 // new freechips.rocketchip.subsystem.WithInclusiveCache(nBanks=1, nWays=4, capacityKB=128) ++ - // Set the debug module to expose an external JTAG port - new freechips.rocketchip.subsystem.WithJtagDTM ++ - - // For simpler designs, we want to minimize IOs on - // our Top. These config fragments remove unnecessary - // ports - new freechips.rocketchip.subsystem.WithNoMMIOPort ++ - new freechips.rocketchip.subsystem.WithNoSlavePort ++ - new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++ - - // Use the standard hierarchical bus topology including mbus+l2 - new freechips.rocketchip.subsystem.WithCoherentBusTopology ++ - - // BaseConfig configures "bare" rocketchip system - new freechips.rocketchip.system.BaseConfig + new chipyard.config.AbstractConfig ) - // Tutorial Phase 2: Integrate a TileLink or AXI4 MMIO device class TutorialMMIOConfig extends Config( - new chipyard.iobinders.WithUARTAdapter ++ - new chipyard.iobinders.WithBlackBoxSimMem ++ - new chipyard.iobinders.WithTieOffInterrupts ++ - new chipyard.iobinders.WithSimDebug ++ - new chipyard.iobinders.WithSimSerial ++ - - new testchipip.WithTSI ++ - new chipyard.config.WithBootROM ++ - new chipyard.config.WithUART ++ - new chipyard.config.WithNoSubsystemDrivenClocks ++ // Attach either a TileLink or AXI4 version of GCD // Uncomment one of the below lines @@ -81,66 +45,26 @@ class TutorialMMIOConfig extends Config( // For this demonstration we assume the base system is a single-core Rocket, for fast elaboration new freechips.rocketchip.subsystem.WithNBigCores(1) ++ - new freechips.rocketchip.subsystem.WithInclusiveCache ++ - new freechips.rocketchip.subsystem.WithJtagDTM ++ - new freechips.rocketchip.subsystem.WithNoMMIOPort ++ - new freechips.rocketchip.subsystem.WithNoSlavePort ++ - new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++ - new freechips.rocketchip.subsystem.WithCoherentBusTopology ++ - new freechips.rocketchip.system.BaseConfig + new chipyard.config.AbstractConfig ) -// Tutorial Phase 3: Integrate a SHA3 RoCC accelerator +// // Tutorial Phase 3: Integrate a SHA3 RoCC accelerator class TutorialSha3Config extends Config( - new chipyard.iobinders.WithUARTAdapter ++ - new chipyard.iobinders.WithBlackBoxSimMem ++ - new chipyard.iobinders.WithTieOffInterrupts ++ - new chipyard.iobinders.WithSimDebug ++ - new chipyard.iobinders.WithSimSerial ++ - - new testchipip.WithTSI ++ - new chipyard.config.WithBootROM ++ - new chipyard.config.WithUART ++ - new chipyard.config.WithNoSubsystemDrivenClocks ++ - // Uncomment this line once you added SHA3 to the build.sbt, and cloned the SHA3 repo // new sha3.WithSha3Accel ++ // For this demonstration we assume the base system is a single-core Rocket, for fast elaboration new freechips.rocketchip.subsystem.WithNBigCores(1) ++ - new freechips.rocketchip.subsystem.WithJtagDTM ++ - new freechips.rocketchip.subsystem.WithInclusiveCache ++ - new freechips.rocketchip.subsystem.WithNoMMIOPort ++ - new freechips.rocketchip.subsystem.WithNoSlavePort ++ - new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++ - new freechips.rocketchip.subsystem.WithCoherentBusTopology ++ - new freechips.rocketchip.system.BaseConfig + new chipyard.config.AbstractConfig ) // Tutorial Phase 4: Integrate a Black-box verilog version of the SHA3 RoCC accelerator class TutorialSha3BlackBoxConfig extends Config( - new chipyard.iobinders.WithUARTAdapter ++ - new chipyard.iobinders.WithBlackBoxSimMem ++ - new chipyard.iobinders.WithTieOffInterrupts ++ - new chipyard.iobinders.WithSimDebug ++ - new chipyard.iobinders.WithSimSerial ++ - - new testchipip.WithTSI ++ - new chipyard.config.WithBootROM ++ - new chipyard.config.WithUART ++ - new chipyard.config.WithNoSubsystemDrivenClocks ++ - // Uncomment these lines once SHA3 is integrated // new sha3.WithSha3BlackBox ++ // Specify we want the Black-box verilog version of Sha3 Ctrl // new sha3.WithSha3Accel ++ // For this demonstration we assume the base system is a single-core Rocket, for fast elaboration new freechips.rocketchip.subsystem.WithNBigCores(1) ++ - new freechips.rocketchip.subsystem.WithJtagDTM ++ - new freechips.rocketchip.subsystem.WithInclusiveCache ++ - new freechips.rocketchip.subsystem.WithNoMMIOPort ++ - new freechips.rocketchip.subsystem.WithNoSlavePort ++ - new freechips.rocketchip.subsystem.WithNExtTopInterrupts(0) ++ - new freechips.rocketchip.subsystem.WithCoherentBusTopology ++ - new freechips.rocketchip.system.BaseConfig + new chipyard.config.AbstractConfig ) diff --git a/generators/firechip/src/main/scala/BridgeBinders.scala b/generators/firechip/src/main/scala/BridgeBinders.scala index b59d477d3c..0eb61a0584 100644 --- a/generators/firechip/src/main/scala/BridgeBinders.scala +++ b/generators/firechip/src/main/scala/BridgeBinders.scala @@ -8,13 +8,13 @@ import chisel3.experimental.annotate import freechips.rocketchip.config.{Field, Config, Parameters} import freechips.rocketchip.diplomacy.{LazyModule} import freechips.rocketchip.devices.debug.{Debug, HasPeripheryDebugModuleImp} +import freechips.rocketchip.amba.axi4.{AXI4Bundle} import freechips.rocketchip.subsystem.{CanHaveMasterAXI4MemPort, HasExtInterruptsModuleImp, BaseSubsystem, HasTilesModuleImp} import freechips.rocketchip.tile.{RocketTile} -import sifive.blocks.devices.uart.HasPeripheryUARTModuleImp -import sifive.blocks.devices.gpio.{HasPeripheryGPIOModuleImp} +import sifive.blocks.devices.uart._ -import testchipip.{CanHavePeripherySerialModuleImp, CanHavePeripheryBlockDeviceModuleImp} -import icenet.CanHavePeripheryIceNICModuleImp +import testchipip._ +import icenet.{CanHavePeripheryIceNICModuleImp, SimNetwork, NicLoopback, NICKey, NICIOvonly} import junctions.{NastiKey, NastiParameters} import midas.models.{FASEDBridge, AXI4EdgeSummary, CompleteConfig} @@ -25,73 +25,116 @@ import tracegen.{TraceGenSystemModuleImp} import ariane.ArianeTile import boom.common.{BoomTile} - -import chipyard.iobinders.{IOBinders, OverrideIOBinder, ComposeIOBinder, GetSystemParameters} -import testchipip.{CanHaveTraceIOModuleImp} +import barstools.iocell.chisel._ +import chipyard.iobinders.{IOBinders, OverrideIOBinder, ComposeIOBinder, GetSystemParameters, IOCellKey} +import chipyard.{HasHarnessSignalReferences} +import chipyard.harness._ object MainMemoryConsts { val regionNamePrefix = "MainMemory" def globalName = s"${regionNamePrefix}_${NodeIdx()}" } -class WithSerialBridge extends OverrideIOBinder({ - (system: CanHavePeripherySerialModuleImp) => - system.serial.foreach(s => SerialBridge(system.clock, s, MainMemoryConsts.globalName)(system.p)); Nil +trait Unsupported { + require(false, "We do not support this IOCell type") +} + +class FireSimAnalogIOCell extends RawModule with AnalogIOCell with Unsupported +class FireSimDigitalGPIOCell extends RawModule with DigitalGPIOCell with Unsupported +class FireSimDigitalInIOCell extends RawModule with DigitalInIOCell { io.i := io.pad } +class FireSimDigitalOutIOCell extends RawModule with DigitalOutIOCell { io.pad := io.o } + +case class FireSimIOCellParams() extends IOCellTypeParams { + def analog() = Module(new FireSimAnalogIOCell) + def gpio() = Module(new FireSimDigitalGPIOCell) + def input() = Module(new FireSimDigitalInIOCell) + def output() = Module(new FireSimDigitalOutIOCell) +} + +class WithFireSimIOCellModels extends Config((site, here, up) => { + case IOCellKey => FireSimIOCellParams() }) -class WithNICBridge extends OverrideIOBinder({ - (system: CanHavePeripheryIceNICModuleImp) => - system.net.foreach(n => NICBridge(system.clock, n)(system.p)); Nil +class WithSerialBridge extends OverrideHarnessBinder({ + (system: CanHavePeripherySerial, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + val clock = ports.collectFirst({case c: Clock => c}) + val p: Parameters = chipyard.iobinders.GetSystemParameters(system) + ports.filter(_.isInstanceOf[SerialIO]).map { + case s: SerialIO => withClockAndReset(clock.get, th.harnessReset) { + SerialBridge(clock.get, s, MainMemoryConsts.globalName)(p) + } + case _ => + } + Nil + } }) -class WithUARTBridge extends OverrideIOBinder({ - (system: HasPeripheryUARTModuleImp) => - system.uart.foreach(u => UARTBridge(system.clock, u)(system.p)); Nil +class WithNICBridge extends OverrideHarnessBinder({ + (system: CanHavePeripheryIceNICModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + val clock = ports.collectFirst({case c: Clock => c}) + ports.map { + case p: NICIOvonly => withClockAndReset(clock.get, th.harnessReset) { NICBridge(clock.get, p)(system.p) } + case _ => + } + Nil + } }) -class WithBlockDeviceBridge extends OverrideIOBinder({ - (system: CanHavePeripheryBlockDeviceModuleImp) => - system.bdev.foreach(b => BlockDevBridge(system.clock, b, system.reset.toBool)(system.p)); Nil +class WithUARTBridge extends OverrideHarnessBinder({ + (system: HasPeripheryUARTModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => + ports.map { case p: UARTPortIO => UARTBridge(th.harnessClock, p)(system.p) }; Nil }) +class WithBlockDeviceBridge extends OverrideHarnessBinder({ + (system: CanHavePeripheryBlockDeviceModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + val clock = ports.collectFirst({case c: Clock => c}) + ports.map { + case p: BlockDeviceIO => BlockDevBridge(clock.get, p, th.harnessReset.toBool)(system.p) + case _ => + } + Nil + } +}) -class WithFASEDBridge extends OverrideIOBinder({ - (system: CanHaveMasterAXI4MemPort) => { +class WithFASEDBridge extends OverrideHarnessBinder({ + (system: CanHaveMasterAXI4MemPort, th: HasHarnessSignalReferences, ports: Seq[Data]) => { implicit val p: Parameters = GetSystemParameters(system) - (system.mem_axi4 zip system.memAXI4Node.edges.in).foreach({ case (axi4, edge) => + val clock = ports.collectFirst({case c: Clock => c}) + val axi4_ports = ports.collect { case p: AXI4Bundle => p } + (axi4_ports zip system.memAXI4Node.edges.in).map { case (axi4: AXI4Bundle, 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(s.module.clock, axi4, s.module.reset.toBool, + case s: BaseSubsystem => FASEDBridge(clock.get, axi4, th.harnessReset.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 WithTracerVBridge extends ComposeIOBinder({ - (system: CanHaveTraceIOModuleImp) => - system.traceIO.foreach(_.traces.map(tileTrace => TracerVBridge(tileTrace)(system.p))); Nil +class WithTracerVBridge extends ComposeHarnessBinder({ + (system: CanHaveTraceIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => { + ports.map { case p: TraceOutputTop => p.traces.map(tileTrace => + withClockAndReset(tileTrace.clock, tileTrace.reset) { TracerVBridge(tileTrace)(system.p) } + )} + } }) - - -class WithDromajoBridge extends ComposeIOBinder({ - (system: CanHaveTraceIOModuleImp) => { - system.traceIO.foreach(_.traces.map(tileTrace => DromajoBridge(tileTrace)(system.p))); Nil - } +class WithDromajoBridge extends ComposeHarnessBinder({ + (system: CanHaveTraceIOModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => + ports.map { case p: TraceOutputTop => p.traces.map(tileTrace => DromajoBridge(tileTrace)(system.p)) }; Nil }) -class WithTraceGenBridge extends OverrideIOBinder({ - (system: TraceGenSystemModuleImp) => - GroundTestBridge(system.clock, system.success)(system.p); Nil +class WithTraceGenBridge extends OverrideHarnessBinder({ + (system: TraceGenSystemModuleImp, th: HasHarnessSignalReferences, ports: Seq[Data]) => + ports.map { case p: Bool => GroundTestBridge(th.harnessClock, p)(system.p) }; Nil }) class WithFireSimMultiCycleRegfile extends ComposeIOBinder({ @@ -105,52 +148,25 @@ class WithFireSimMultiCycleRegfile extends ComposeIOBinder({ val core = b.module.core core.iregfile match { case irf: boom.exu.RegisterFileSynthesizable => annotate(MemModelAnnotation(irf.regfile)) - case _ => Nil } if (core.fp_pipeline != null) core.fp_pipeline.fregfile match { case frf: boom.exu.RegisterFileSynthesizable => annotate(MemModelAnnotation(frf.regfile)) - case _ => Nil } } case _ => } - Nil - } -}) - -class WithTiedOffSystemGPIO extends OverrideIOBinder({ - (system: HasPeripheryGPIOModuleImp) => - system.gpio.foreach(_.pins.foreach(_.i.ival := false.B)); Nil -}) - -class WithTiedOffSystemDebug extends OverrideIOBinder({ - (system: HasPeripheryDebugModuleImp) => { - Debug.tieoffDebug(system.debug, system.resetctrl, Some(system.psd))(system.p) - // tieoffDebug doesn't actually tie everything off :/ - system.debug.foreach { d => - d.clockeddmi.foreach({ cdmi => cdmi.dmi.req.bits := DontCare }) - d.dmactiveAck := DontCare - } - Nil + (Nil, Nil) } }) -class WithTiedOffSystemInterrupts extends OverrideIOBinder({ - (system: HasExtInterruptsModuleImp) => - system.interrupts := 0.U; Nil -}) - - // Shorthand to register all of the provided bridges above class WithDefaultFireSimBridges extends Config( - new WithTiedOffSystemGPIO ++ - new WithTiedOffSystemDebug ++ - new WithTiedOffSystemInterrupts ++ new WithSerialBridge ++ new WithNICBridge ++ new WithUARTBridge ++ new WithBlockDeviceBridge ++ new WithFASEDBridge ++ new WithFireSimMultiCycleRegfile ++ - new WithTracerVBridge + new WithTracerVBridge ++ + new WithFireSimIOCellModels ) diff --git a/generators/firechip/src/main/scala/FireSim.scala b/generators/firechip/src/main/scala/FireSim.scala index 158674a0da..d2ef4e60b9 100644 --- a/generators/firechip/src/main/scala/FireSim.scala +++ b/generators/firechip/src/main/scala/FireSim.scala @@ -13,8 +13,9 @@ import freechips.rocketchip.util.{ResetCatchAndSync} import midas.widgets.{Bridge, PeekPokeBridge, RationalClockBridge, RationalClock} -import chipyard.{BuildSystem, BuildTop, HasHarnessSignalReferences, ChipyardSubsystem, ClockingSchemeKey, ChipTop} -import chipyard.iobinders.{IOBinders} +import chipyard._ +import chipyard.harness._ +import chipyard.iobinders._ // Determines the number of times to instantiate the DUT in the harness. // Subsumes legacy supernode support @@ -50,7 +51,7 @@ class WithFireSimSimpleClocks extends Config((site, here, up) => { chiptop.implicitClockSinkNode := implicitClockSourceNode // Drive the diplomaticclock graph of the DigitalTop (if present) - val simpleClockGroupSourceNode = chiptop.lSystem match { + val simpleClockGroupSourceNode = chiptop.lazySystem match { case l: BaseSubsystem if (p(SubsystemDriveAsyncClockGroupsKey).isEmpty) => { val n = ClockGroupSourceNode(Seq(ClockGroupSourceParameters())) l.asyncClockGroupsNode := n @@ -93,7 +94,7 @@ class WithFireSimRationalTileDomain(multiplier: Int, divisor: Int) extends Confi chiptop.implicitClockSinkNode := implicitClockSourceNode // Drive the diplomaticclock graph of the DigitalTop (if present) - val simpleClockGroupSourceNode = chiptop.lSystem match { + val simpleClockGroupSourceNode = chiptop.lazySystem match { case l: BaseSubsystem if (p(SubsystemDriveAsyncClockGroupsKey).isEmpty) => { val n = ClockGroupSourceNode(Seq(ClockGroupSourceParameters())) l.asyncClockGroupsNode := n @@ -159,8 +160,13 @@ class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessSigna case AsyncClockGroupsKey => p(AsyncClockGroupsKey).copy }))) val module = Module(lazyModule.module) - require(lazyModule.harnessFunctions.size == 1, "There should only be 1 harness function to connect clock+reset") - lazyModule.harnessFunctions.foreach(_(this)) + 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)) + ApplyHarnessBinders(this, d.lazySystem, p(HarnessBinders), d.portMap.toMap) + } + + NodeIdx.increment() } } diff --git a/generators/icenet b/generators/icenet index 705ca50690..bb23c81fcf 160000 --- a/generators/icenet +++ b/generators/icenet @@ -1 +1 @@ -Subproject commit 705ca50690383aa589dc560a5e7c152af04c46ad +Subproject commit bb23c81fcfbdfde6767c5b7daa95f8f9436fb7db diff --git a/generators/testchipip b/generators/testchipip index 1e7373f639..6f4e7ae2c9 160000 --- a/generators/testchipip +++ b/generators/testchipip @@ -1 +1 @@ -Subproject commit 1e7373f6398c198e2dee2bcf692917ec2ac21b53 +Subproject commit 6f4e7ae2c94e867f08cd0d408a106fba2f389de2 diff --git a/sims/firesim b/sims/firesim index 05edd6be8c..069c3c111d 160000 --- a/sims/firesim +++ b/sims/firesim @@ -1 +1 @@ -Subproject commit 05edd6be8c0464ea53a664a2164d3eba6a7f62aa +Subproject commit 069c3c111d46a3f3d20b4bd6f17aaa9b23487cc7 diff --git a/tools/barstools b/tools/barstools index aa1c90c4cc..ba681676f3 160000 --- a/tools/barstools +++ b/tools/barstools @@ -1 +1 @@ -Subproject commit aa1c90c4ccb73c2c379550f3296892cc81e8a195 +Subproject commit ba681676f338af158023c99b4c802009aa0b601b