Add PortAPI between IO and Harness blocks

This commit is contained in:
Jerry Zhao
2023-10-02 17:30:13 -07:00
parent 8c1319073c
commit eb3a0aecf4
32 changed files with 715 additions and 822 deletions

View File

@@ -13,7 +13,7 @@ The ``IOBinder`` functions are responsible for instantiating IO cells and IOPort
For example, the ``WithUARTIOCells`` IOBinder will, for any ``System`` that might have UART ports (``HasPeripheryUARTModuleImp``, generate ports within the ``ChipTop`` (``ports``) as well as IOCells with the appropriate type and direction (``cells2d``). This function returns a the list of generated ports, and the list of generated IOCells. The list of generated ports is passed to the ``HarnessBinders`` such that they can be connected to ``TestHarness`` devices. For example, the ``WithUARTIOCells`` IOBinder will, for any ``System`` that might have UART ports (``HasPeripheryUARTModuleImp``, generate ports within the ``ChipTop`` (``ports``) as well as IOCells with the appropriate type and direction (``cells2d``). This function returns a the list of generated ports, and the list of generated IOCells. The list of generated ports is passed to the ``HarnessBinders`` such that they can be connected to ``TestHarness`` devices.
.. literalinclude:: ../../generators/chipyard/src/main/scala/IOBinders.scala .. literalinclude:: ../../generators/chipyard/src/main/scala/iobinders/IOBinders.scala
:language: scala :language: scala
:start-after: DOC include start: WithUARTIOCells :start-after: DOC include start: WithUARTIOCells
:end-before: DOC include end: WithUARTIOCells :end-before: DOC include end: WithUARTIOCells

View File

@@ -17,7 +17,8 @@ import chipyard.{BuildSystem}
// DOC include start: AbstractArty and Rocket // DOC include start: AbstractArty and Rocket
class WithArtyTweaks extends Config( class WithArtyTweaks extends Config(
new WithArtyResetHarnessBinder ++ new WithArtyDebugResetHarnessBinder ++
new WithArtyJTAGResetHarnessBinder ++
new WithArtyJTAGHarnessBinder ++ new WithArtyJTAGHarnessBinder ++
new WithArtyUARTHarnessBinder ++ new WithArtyUARTHarnessBinder ++
new WithDebugResetPassthrough ++ new WithDebugResetPassthrough ++

View File

@@ -11,68 +11,61 @@ import sifive.blocks.devices.pinctrl.{BasePin}
import sifive.fpgashells.ip.xilinx.{IBUFG, IOBUF, PULLUP, PowerOnResetFPGAOnly} import sifive.fpgashells.ip.xilinx.{IBUFG, IOBUF, PULLUP, PowerOnResetFPGAOnly}
import chipyard.harness.{ComposeHarnessBinder, OverrideHarnessBinder} import chipyard.harness.{HarnessBinder}
import chipyard.iobinders.JTAGChipIO import chipyard.iobinders._
class WithArtyResetHarnessBinder extends ComposeHarnessBinder({ class WithArtyDebugResetHarnessBinder extends HarnessBinder({
(system: HasPeripheryDebug, th: ArtyFPGATestHarness, ports: Seq[Data]) => { case (th: ArtyFPGATestHarness, port: DebugResetPort) => {
val resetPorts = ports.collect { case b: Bool => b } th.dut_ndreset := port.io // Debug module reset
require(resetPorts.size == 2) }
})
class WithArtyJTAGResetHarnessBinder extends HarnessBinder({
case (th: ArtyFPGATestHarness, port: JTAGResetPort) => {
port.io := PowerOnResetFPGAOnly(th.clock_32MHz) // JTAG module reset
}
})
class WithArtyJTAGHarnessBinder extends HarnessBinder({
case (th: ArtyFPGATestHarness, port: JTAGPort) => {
val jtag_wire = Wire(new JTAGIO)
jtag_wire.TDO.data := port.io.TDO
jtag_wire.TDO.driven := true.B
port.io.TCK := jtag_wire.TCK
port.io.TMS := jtag_wire.TMS
port.io.TDI := jtag_wire.TDI
val io_jtag = Wire(new JTAGPins(() => new BasePin(), false)).suggestName("jtag")
JTAGPinsFromPort(io_jtag, jtag_wire)
io_jtag.TCK.i.ival := IBUFG(IOBUF(th.jd_2).asClock).asBool
IOBUF(th.jd_5, io_jtag.TMS)
PULLUP(th.jd_5)
IOBUF(th.jd_4, io_jtag.TDI)
PULLUP(th.jd_4)
IOBUF(th.jd_0, io_jtag.TDO)
// mimic putting a pullup on this line (part of reset vote)
th.SRST_n := IOBUF(th.jd_6)
PULLUP(th.jd_6)
// ignore the po input
io_jtag.TCK.i.po.map(_ := DontCare)
io_jtag.TDI.i.po.map(_ := DontCare)
io_jtag.TMS.i.po.map(_ := DontCare)
io_jtag.TDO.i.po.map(_ := DontCare)
}
})
class WithArtyUARTHarnessBinder extends HarnessBinder({
case (th: ArtyFPGATestHarness, port: UARTPort) => {
withClockAndReset(th.clock_32MHz, th.ck_rst) { withClockAndReset(th.clock_32MHz, th.ck_rst) {
// Debug module reset IOBUF(th.uart_rxd_out, port.io.txd)
th.dut_ndreset := resetPorts(0) port.io.rxd := IOBUF(th.uart_txd_in)
// JTAG reset
resetPorts(1) := PowerOnResetFPGAOnly(th.clock_32MHz)
}
}
})
class WithArtyJTAGHarnessBinder extends OverrideHarnessBinder({
(system: HasPeripheryDebug, th: ArtyFPGATestHarness, ports: Seq[Data]) => {
ports.map {
case j: JTAGChipIO => {
val jtag_wire = Wire(new JTAGIO)
jtag_wire.TDO.data := j.TDO
jtag_wire.TDO.driven := true.B
j.TCK := jtag_wire.TCK
j.TMS := jtag_wire.TMS
j.TDI := jtag_wire.TDI
val io_jtag = Wire(new JTAGPins(() => new BasePin(), false)).suggestName("jtag")
JTAGPinsFromPort(io_jtag, jtag_wire)
io_jtag.TCK.i.ival := IBUFG(IOBUF(th.jd_2).asClock).asBool
IOBUF(th.jd_5, io_jtag.TMS)
PULLUP(th.jd_5)
IOBUF(th.jd_4, io_jtag.TDI)
PULLUP(th.jd_4)
IOBUF(th.jd_0, io_jtag.TDO)
// mimic putting a pullup on this line (part of reset vote)
th.SRST_n := IOBUF(th.jd_6)
PULLUP(th.jd_6)
// ignore the po input
io_jtag.TCK.i.po.map(_ := DontCare)
io_jtag.TDI.i.po.map(_ := DontCare)
io_jtag.TMS.i.po.map(_ := DontCare)
io_jtag.TDO.i.po.map(_ := DontCare)
}
case b: Bool =>
}
}
})
class WithArtyUARTHarnessBinder extends OverrideHarnessBinder({
(system: HasPeripheryUARTModuleImp, th: ArtyFPGATestHarness, ports: Seq[UARTPortIO]) => {
withClockAndReset(th.clock_32MHz, th.ck_rst) {
IOBUF(th.uart_rxd_out, ports.head.txd)
ports.head.rxd := IOBUF(th.uart_txd_in)
} }
} }
}) })

View File

@@ -5,7 +5,7 @@ import chisel3.experimental.{IO}
import freechips.rocketchip.devices.debug.{HasPeripheryDebug} import freechips.rocketchip.devices.debug.{HasPeripheryDebug}
import chipyard.iobinders.{ComposeIOBinder} import chipyard.iobinders.{ComposeIOBinder, DebugResetPort, JTAGResetPort}
class WithDebugResetPassthrough extends ComposeIOBinder({ class WithDebugResetPassthrough extends ComposeIOBinder({
(system: HasPeripheryDebug) => { (system: HasPeripheryDebug) => {
@@ -18,6 +18,6 @@ class WithDebugResetPassthrough extends ComposeIOBinder({
val io_sjtag_reset: Bool = IO(Input(Bool())).suggestName("sjtag_reset") val io_sjtag_reset: Bool = IO(Input(Bool())).suggestName("sjtag_reset")
sjtag.reset := io_sjtag_reset sjtag.reset := io_sjtag_reset
(Seq(io_ndreset, io_sjtag_reset), Nil) (Seq(DebugResetPort(io_ndreset), JTAGResetPort(io_sjtag_reset)), Nil)
} }
}) })

View File

@@ -16,33 +16,28 @@ import sifive.fpgashells.ip.xilinx.{IBUFG, IOBUF, PULLUP, PowerOnResetFPGAOnly}
import chipyard._ import chipyard._
import chipyard.harness._ import chipyard.harness._
import chipyard.iobinders.JTAGChipIO import chipyard.iobinders._
import testchipip._ import testchipip._
class WithArty100TUARTTSI(uartBaudRate: BigInt = 115200) extends OverrideHarnessBinder({ class WithArty100TUARTTSI(uartBaudRate: BigInt = 115200) extends HarnessBinder({
(system: CanHavePeripheryUARTTSI, th: HasHarnessInstantiators, ports: Seq[UARTTSIIO]) => { case (th: HasHarnessInstantiators, port: UARTTSIPort) => {
implicit val p = chipyard.iobinders.GetSystemParameters(system)
require(ports.size <= 1)
val ath = th.asInstanceOf[LazyRawModuleImp].wrapper.asInstanceOf[Arty100THarness] val ath = th.asInstanceOf[LazyRawModuleImp].wrapper.asInstanceOf[Arty100THarness]
ports.map({ port => ath.io_uart_bb.bundle <> port.io.uart
ath.io_uart_bb.bundle <> port.uart ath.other_leds(1) := port.io.dropped
ath.other_leds(1) := port.dropped ath.other_leds(9) := port.io.tsi2tl_state(0)
ath.other_leds(9) := port.tsi2tl_state(0) ath.other_leds(10) := port.io.tsi2tl_state(1)
ath.other_leds(10) := port.tsi2tl_state(1) ath.other_leds(11) := port.io.tsi2tl_state(2)
ath.other_leds(11) := port.tsi2tl_state(2) ath.other_leds(12) := port.io.tsi2tl_state(3)
ath.other_leds(12) := port.tsi2tl_state(3)
})
} }
}) })
class WithArty100TDDRTL extends OverrideHarnessBinder({ class WithArty100TDDRTL extends HarnessBinder({
(system: CanHaveMasterTLMemPort, th: HasHarnessInstantiators, ports: Seq[HeterogeneousBag[TLBundle]]) => { case (th: HasHarnessInstantiators, port: TLMemPort) => {
require(ports.size == 1)
val artyTh = th.asInstanceOf[LazyRawModuleImp].wrapper.asInstanceOf[Arty100THarness] val artyTh = th.asInstanceOf[LazyRawModuleImp].wrapper.asInstanceOf[Arty100THarness]
val bundles = artyTh.ddrClient.out.map(_._1) val bundles = artyTh.ddrClient.out.map(_._1)
val ddrClientBundle = Wire(new HeterogeneousBag(bundles.map(_.cloneType))) val ddrClientBundle = Wire(new HeterogeneousBag(bundles.map(_.cloneType)))
bundles.zip(ddrClientBundle).foreach { case (bundle, io) => bundle <> io } bundles.zip(ddrClientBundle).foreach { case (bundle, io) => bundle <> io }
ddrClientBundle <> ports.head ddrClientBundle <> port.io
} }
}) })

View File

@@ -53,10 +53,6 @@ class WithVC707Tweaks extends Config (
new WithVC707UARTHarnessBinder ++ new WithVC707UARTHarnessBinder ++
new WithVC707SPISDCardHarnessBinder ++ new WithVC707SPISDCardHarnessBinder ++
new WithVC707DDRMemHarnessBinder ++ new WithVC707DDRMemHarnessBinder ++
// io binders
new WithUARTIOPassthrough ++
new WithSPIIOPassthrough ++
new WithTLIOPassthrough ++
// other configuration // other configuration
new WithDefaultPeripherals ++ new WithDefaultPeripherals ++
new chipyard.config.WithTLBackingMemory ++ // use TL backing memory new chipyard.config.WithTLBackingMemory ++ // use TL backing memory

View File

@@ -11,36 +11,29 @@ import sifive.blocks.devices.spi.{HasPeripherySPI, SPIPortIO}
import sifive.fpgashells.devices.xilinx.xilinxvc707pciex1.{HasSystemXilinxVC707PCIeX1ModuleImp, XilinxVC707PCIeX1IO} import sifive.fpgashells.devices.xilinx.xilinxvc707pciex1.{HasSystemXilinxVC707PCIeX1ModuleImp, XilinxVC707PCIeX1IO}
import chipyard.{CanHaveMasterTLMemPort} import chipyard.{CanHaveMasterTLMemPort}
import chipyard.harness.{OverrideHarnessBinder} import chipyard.harness.{HarnessBinder}
import chipyard.iobinders._
/*** UART ***/ /*** UART ***/
class WithVC707UARTHarnessBinder extends OverrideHarnessBinder({ class WithVC707UARTHarnessBinder extends HarnessBinder({
(system: HasPeripheryUARTModuleImp, th: BaseModule, ports: Seq[UARTPortIO]) => { case (th: VC707FPGATestHarnessImp, port: UARTPort) => {
th match { case vc707th: VC707FPGATestHarnessImp => { th.vc707Outer.io_uart_bb.bundle <> port.io
vc707th.vc707Outer.io_uart_bb.bundle <> ports.head
}}
} }
}) })
/*** SPI ***/ /*** SPI ***/
class WithVC707SPISDCardHarnessBinder extends OverrideHarnessBinder({ class WithVC707SPISDCardHarnessBinder extends HarnessBinder({
(system: HasPeripherySPI, th: BaseModule, ports: Seq[SPIPortIO]) => { case (th: VC707FPGATestHarnessImp, port: SPIPort) => {
th match { case vc707th: VC707FPGATestHarnessImp => { th.vc707Outer.io_spi_bb.bundle <> port.io
vc707th.vc707Outer.io_spi_bb.bundle <> ports.head
}}
} }
}) })
/*** Experimental DDR ***/ /*** Experimental DDR ***/
class WithVC707DDRMemHarnessBinder extends OverrideHarnessBinder({ class WithVC707DDRMemHarnessBinder extends HarnessBinder({
(system: CanHaveMasterTLMemPort, th: BaseModule, ports: Seq[HeterogeneousBag[TLBundle]]) => { case (th: VC707FPGATestHarnessImp, port: TLMemPort) => {
th match { case vc707th: VC707FPGATestHarnessImp => { val bundles = th.vc707Outer.ddrClient.out.map(_._1)
require(ports.size == 1) val ddrClientBundle = Wire(new HeterogeneousBag(bundles.map(_.cloneType)))
bundles.zip(ddrClientBundle).foreach { case (bundle, io) => bundle <> io }
val bundles = vc707th.vc707Outer.ddrClient.out.map(_._1) ddrClientBundle <> port.io
val ddrClientBundle = Wire(new HeterogeneousBag(bundles.map(_.cloneType)))
bundles.zip(ddrClientBundle).foreach { case (bundle, io) => bundle <> io }
ddrClientBundle <> ports.head
}}
} }
}) })

View File

@@ -1,53 +0,0 @@
package chipyard.fpga.vc707
import chisel3._
import chisel3.experimental.{IO, DataMirror}
import freechips.rocketchip.diplomacy.{ResourceBinding, Resource, ResourceAddress, InModuleBody}
import freechips.rocketchip.subsystem.{BaseSubsystem}
import freechips.rocketchip.util.{HeterogeneousBag}
import freechips.rocketchip.tilelink.{TLBundle}
import sifive.blocks.devices.uart.{HasPeripheryUARTModuleImp}
import sifive.blocks.devices.spi.{HasPeripherySPI, HasPeripherySPIModuleImp, MMCDevice}
import sifive.fpgashells.devices.xilinx.xilinxvc707pciex1.{HasSystemXilinxVC707PCIeX1ModuleImp}
import chipyard.{CanHaveMasterTLMemPort}
import chipyard.iobinders.{OverrideIOBinder, OverrideLazyIOBinder}
class WithUARTIOPassthrough extends OverrideIOBinder({
(system: HasPeripheryUARTModuleImp) => {
val io_uart_pins_temp = system.uart.zipWithIndex.map { case (dio, i) => IO(dio.cloneType).suggestName(s"uart_$i") }
(io_uart_pins_temp zip system.uart).map { case (io, sysio) =>
io <> sysio
}
(io_uart_pins_temp, Nil)
}
})
class WithSPIIOPassthrough extends OverrideLazyIOBinder({
(system: HasPeripherySPI) => {
// attach resource to 1st SPI
ResourceBinding {
Resource(new MMCDevice(system.tlSpiNodes.head.device, 1), "reg").bind(ResourceAddress(0))
}
InModuleBody {
system.asInstanceOf[BaseSubsystem].module match { case system: HasPeripherySPIModuleImp => {
val io_spi_pins_temp = system.spi.zipWithIndex.map { case (dio, i) => IO(dio.cloneType).suggestName(s"spi_$i") }
(io_spi_pins_temp zip system.spi).map { case (io, sysio) =>
io <> sysio
}
(io_spi_pins_temp, Nil)
} }
}
}
})
class WithTLIOPassthrough extends OverrideIOBinder({
(system: CanHaveMasterTLMemPort) => {
val io_tl_mem_pins_temp = IO(DataMirror.internal.chiselTypeClone[HeterogeneousBag[TLBundle]](system.mem_tl)).suggestName("tl_slave")
io_tl_mem_pins_temp <> system.mem_tl
(Seq(io_tl_mem_pins_temp), Nil)
}
})

View File

@@ -52,9 +52,6 @@ class WithVCU118Tweaks extends Config(
new WithUART ++ new WithUART ++
new WithSPISDCard ++ new WithSPISDCard ++
new WithDDRMem ++ new WithDDRMem ++
// io binders
new WithUARTIOPassthrough ++
new WithSPIIOPassthrough ++
// other configuration // other configuration
new WithDefaultPeripherals ++ new WithDefaultPeripherals ++
new chipyard.config.WithTLBackingMemory ++ // use TL backing memory new chipyard.config.WithTLBackingMemory ++ // use TL backing memory

View File

@@ -11,35 +11,28 @@ import sifive.blocks.devices.spi.{HasPeripherySPI, SPIPortIO}
import chipyard._ import chipyard._
import chipyard.harness._ import chipyard.harness._
import chipyard.iobinders._
/*** UART ***/ /*** UART ***/
class WithUART extends OverrideHarnessBinder({ class WithUART extends HarnessBinder({
(system: HasPeripheryUARTModuleImp, th: BaseModule with HasHarnessInstantiators, ports: Seq[UARTPortIO]) => { case (th: VCU118FPGATestHarnessImp, port: UARTPort) => {
th match { case vcu118th: VCU118FPGATestHarnessImp => { th.vcu118Outer.io_uart_bb.bundle <> port.io
vcu118th.vcu118Outer.io_uart_bb.bundle <> ports.head
} }
} }
}) })
/*** SPI ***/ /*** SPI ***/
class WithSPISDCard extends OverrideHarnessBinder({ class WithSPISDCard extends HarnessBinder({
(system: HasPeripherySPI, th: BaseModule with HasHarnessInstantiators, ports: Seq[SPIPortIO]) => { case (th: VCU118FPGATestHarnessImp, port: SPIPort) => {
th match { case vcu118th: VCU118FPGATestHarnessImp => { th.vcu118Outer.io_spi_bb.bundle <> port.io
vcu118th.vcu118Outer.io_spi_bb.bundle <> ports.head
} }
} }
}) })
/*** Experimental DDR ***/ /*** Experimental DDR ***/
class WithDDRMem extends OverrideHarnessBinder({ class WithDDRMem extends HarnessBinder({
(system: CanHaveMasterTLMemPort, th: BaseModule with HasHarnessInstantiators, ports: Seq[HeterogeneousBag[TLBundle]]) => { case (th: VCU118FPGATestHarnessImp, port: TLMemPort) => {
th match { case vcu118th: VCU118FPGATestHarnessImp => { val bundles = th.vcu118Outer.ddrClient.out.map(_._1)
require(ports.size == 1) val ddrClientBundle = Wire(new HeterogeneousBag(bundles.map(_.cloneType)))
bundles.zip(ddrClientBundle).foreach { case (bundle, io) => bundle <> io }
val bundles = vcu118th.vcu118Outer.ddrClient.out.map(_._1) ddrClientBundle <> port.io
val ddrClientBundle = Wire(new HeterogeneousBag(bundles.map(_.cloneType)))
bundles.zip(ddrClientBundle).foreach { case (bundle, io) => bundle <> io }
ddrClientBundle <> ports.head
} }
} }
}) })

View File

@@ -1,44 +0,0 @@
package chipyard.fpga.vcu118
import chisel3._
import chisel3.experimental.{IO, DataMirror}
import freechips.rocketchip.diplomacy.{ResourceBinding, Resource, ResourceAddress, InModuleBody}
import freechips.rocketchip.subsystem.{BaseSubsystem}
import freechips.rocketchip.util.{HeterogeneousBag}
import freechips.rocketchip.tilelink.{TLBundle}
import sifive.blocks.devices.uart.{HasPeripheryUARTModuleImp}
import sifive.blocks.devices.spi.{HasPeripherySPI, HasPeripherySPIModuleImp, MMCDevice}
import chipyard.{CanHaveMasterTLMemPort}
import chipyard.iobinders.{OverrideIOBinder, OverrideLazyIOBinder}
class WithUARTIOPassthrough extends OverrideIOBinder({
(system: HasPeripheryUARTModuleImp) => {
val io_uart_pins_temp = system.uart.zipWithIndex.map { case (dio, i) => IO(dio.cloneType).suggestName(s"uart_$i") }
(io_uart_pins_temp zip system.uart).map { case (io, sysio) =>
io <> sysio
}
(io_uart_pins_temp, Nil)
}
})
class WithSPIIOPassthrough extends OverrideLazyIOBinder({
(system: HasPeripherySPI) => {
// attach resource to 1st SPI
ResourceBinding {
Resource(new MMCDevice(system.tlSpiNodes.head.device, 1), "reg").bind(ResourceAddress(0))
}
InModuleBody {
system.asInstanceOf[BaseSubsystem].module match { case system: HasPeripherySPIModuleImp => {
val io_spi_pins_temp = system.spi.zipWithIndex.map { case (dio, i) => IO(dio.cloneType).suggestName(s"spi_$i") }
(io_spi_pins_temp zip system.spi).map { case (io, sysio) =>
io <> sysio
}
(io_spi_pins_temp, Nil)
} }
}
}
})

View File

@@ -20,6 +20,7 @@ import testchipip.{PeripheryTSIHostKey, TSIHostParams, TSIHostSerdesParams}
import chipyard.{BuildSystem} import chipyard.{BuildSystem}
import chipyard.fpga.vcu118.{WithVCU118Tweaks, WithFPGAFrequency, VCU118DDR2Size} import chipyard.fpga.vcu118.{WithVCU118Tweaks, WithFPGAFrequency, VCU118DDR2Size}
import chipyard.iobinders.{WithGPIOPunchthrough}
class WithBringupPeripherals extends Config((site, here, up) => { class WithBringupPeripherals extends Config((site, here, up) => {
case PeripheryUARTKey => up(PeripheryUARTKey, site) ++ List(UARTParams(address = BigInt(0x64003000L))) case PeripheryUARTKey => up(PeripheryUARTKey, site) ++ List(UARTParams(address = BigInt(0x64003000L)))
@@ -80,8 +81,7 @@ class WithBringupAdditions extends Config(
new WithBringupGPIO ++ new WithBringupGPIO ++
new WithBringupTSIHost ++ new WithBringupTSIHost ++
new WithTSITLIOPassthrough ++ new WithTSITLIOPassthrough ++
new WithI2CIOPassthrough ++ new WithGPIOPunchthrough ++
new WithGPIOIOPassthrough ++
new WithBringupPeripherals ++ new WithBringupPeripherals ++
new WithBringupVCU118System) new WithBringupVCU118System)

View File

@@ -14,56 +14,38 @@ import sifive.blocks.devices.gpio.{HasPeripheryGPIOModuleImp, GPIOPortIO}
import testchipip.{HasPeripheryTSIHostWidget, TSIHostWidgetIO} import testchipip.{HasPeripheryTSIHostWidget, TSIHostWidgetIO}
import chipyard.harness._ import chipyard.harness._
import chipyard.iobinders._
/*** UART ***/ /*** UART ***/
class WithBringupUART extends ComposeHarnessBinder({ class WithBringupUART extends HarnessBinder({
(system: HasPeripheryUARTModuleImp, th: BaseModule with HasHarnessInstantiators, ports: Seq[UARTPortIO]) => { case (th: BringupVCU118FPGATestHarnessImp, port: UARTPort) => {
th match { case vcu118th: BringupVCU118FPGATestHarnessImp => { th.bringupOuter.io_fmc_uart_bb.bundle <> port.io
require(ports.size == 2)
vcu118th.bringupOuter.io_fmc_uart_bb.bundle <> ports.last
} }
} }
}) })
/*** I2C ***/ /*** I2C ***/
class WithBringupI2C extends OverrideHarnessBinder({ class WithBringupI2C extends HarnessBinder({
(system: HasPeripheryI2CModuleImp, th: BaseModule with HasHarnessInstantiators, ports: Seq[I2CPort]) => { case (th: BringupVCU118FPGATestHarnessImp, port: chipyard.iobinders.I2CPort) => {
th match { case vcu118th: BringupVCU118FPGATestHarnessImp => { th.bringupOuter.io_i2c_bb.bundle <> port.io
require(ports.size == 1)
vcu118th.bringupOuter.io_i2c_bb.bundle <> ports.head
} }
} }
}) })
/*** GPIO ***/ /*** GPIO ***/
class WithBringupGPIO extends OverrideHarnessBinder({ class WithBringupGPIO extends HarnessBinder({
(system: HasPeripheryGPIOModuleImp, th: BaseModule with HasHarnessInstantiators, ports: Seq[GPIOPortIO]) => { case (th: BringupVCU118FPGATestHarnessImp, port: GPIOPort) => {
th match { case vcu118th: BringupVCU118FPGATestHarnessImp => { th.bringupOuter.io_gpio_bb(port.pinId).bundle <> port.io
(vcu118th.bringupOuter.io_gpio_bb zip ports).map { case (bb_io, dut_io) =>
bb_io.bundle <> dut_io
}
} }
} }
}) })
/*** TSI Host Widget ***/ /*** TSI Host Widget ***/
class WithBringupTSIHost extends OverrideHarnessBinder({ class WithBringupTSIHost extends HarnessBinder({
(system: HasPeripheryTSIHostWidget, th: BaseModule with HasHarnessInstantiators, ports: Seq[Data]) => { case (th: BringupVCU118FPGATestHarnessImp, port: TLMemPort) => {
th match { case vcu118th: BringupVCU118FPGATestHarnessImp => { val tsiBundles = th.bringupOuter.tsiDdrClient.out.map(_._1)
require(ports.size == 2) // 1st goes to the TL mem, 2nd goes to the serial link val tsiDdrClientBundle = Wire(new HeterogeneousBag(tsiBundles.map(_.cloneType)))
tsiBundles.zip(tsiDdrClientBundle).foreach { case (bundle, io) => bundle <> io }
ports.head match { case tlPort: HeterogeneousBag[TLBundle] => tsiDdrClientBundle <> port.io
val tsiBundles = vcu118th.bringupOuter.tsiDdrClient.out.map(_._1) }
val tsiDdrClientBundle = Wire(new HeterogeneousBag(tsiBundles.map(_.cloneType))) case (th: BringupVCU118FPGATestHarnessImp, port: TSIHostWidgetPort) => {
tsiBundles.zip(tsiDdrClientBundle).foreach { case (bundle, io) => bundle <> io } th.bringupOuter.io_tsi_serial_bb.bundle <> port.io
tsiDdrClientBundle <> tlPort
}
ports.last match { case serialPort: TSIHostWidgetIO =>
vcu118th.bringupOuter.io_tsi_serial_bb.bundle <> serialPort
}
} }
} }
}) })

View File

@@ -11,27 +11,10 @@ import sifive.blocks.devices.i2c.{HasPeripheryI2CModuleImp}
import testchipip.{HasPeripheryTSIHostWidget, TSIHostWidgetIO} import testchipip.{HasPeripheryTSIHostWidget, TSIHostWidgetIO}
import chipyard.iobinders.{OverrideIOBinder} import chipyard.iobinders.{OverrideIOBinder, Port, TLMemPort}
class WithGPIOIOPassthrough extends OverrideIOBinder({ case class TSIHostWidgetPort(val io: TSIHostWidgetIO)
(system: HasPeripheryGPIOModuleImp) => { extends Port[TSIHostWidgetIO]
val io_gpio_pins_temp = system.gpio.zipWithIndex.map { case (dio, i) => IO(dio.cloneType).suggestName(s"gpio_$i") }
(io_gpio_pins_temp zip system.gpio).map { case (io, sysio) =>
io <> sysio
}
(io_gpio_pins_temp, Nil)
}
})
class WithI2CIOPassthrough extends OverrideIOBinder({
(system: HasPeripheryI2CModuleImp) => {
val io_i2c_pins_temp = system.i2c.zipWithIndex.map { case (dio, i) => IO(dio.cloneType).suggestName(s"i2c_$i") }
(io_i2c_pins_temp zip system.i2c).map { case (io, sysio) =>
io <> sysio
}
(io_i2c_pins_temp, Nil)
}
})
class WithTSITLIOPassthrough extends OverrideIOBinder({ class WithTSITLIOPassthrough extends OverrideIOBinder({
(system: HasPeripheryTSIHostWidget) => { (system: HasPeripheryTSIHostWidget) => {
@@ -42,6 +25,6 @@ class WithTSITLIOPassthrough extends OverrideIOBinder({
require(system.tsiSerial.size == 1) require(system.tsiSerial.size == 1)
val io_tsi_serial_pins_temp = IO(DataMirror.internal.chiselTypeClone[TSIHostWidgetIO](system.tsiSerial.head)).suggestName("tsi_serial") val io_tsi_serial_pins_temp = IO(DataMirror.internal.chiselTypeClone[TSIHostWidgetIO](system.tsiSerial.head)).suggestName("tsi_serial")
io_tsi_serial_pins_temp <> system.tsiSerial.head io_tsi_serial_pins_temp <> system.tsiSerial.head
(Seq(io_tsi_tl_mem_pins_temp, io_tsi_serial_pins_temp), Nil) (Seq(TLMemPort(io_tsi_tl_mem_pins_temp), TSIHostWidgetPort(io_tsi_serial_pins_temp)), Nil)
} }
}) })

View File

@@ -2,17 +2,13 @@ package chipyard.clocking
import chisel3._ import chisel3._
import chisel3.util._ import chisel3.util._
import chipyard.iobinders.{OverrideLazyIOBinder, GetSystemParameters, IOCellKey} import chipyard.iobinders.{OverrideLazyIOBinder, GetSystemParameters, IOCellKey, ClockPort, ResetPort}
import freechips.rocketchip.prci._ import freechips.rocketchip.prci._
import freechips.rocketchip.diplomacy._ import freechips.rocketchip.diplomacy._
import freechips.rocketchip.subsystem._ import freechips.rocketchip.subsystem._
import freechips.rocketchip.tilelink._ import freechips.rocketchip.tilelink._
import barstools.iocell.chisel._ import barstools.iocell.chisel._
class ClockWithFreq(val freqMHz: Double) extends Bundle {
val clock = Clock()
}
// This uses the FakePLL, which uses a ClockAtFreq Verilog blackbox to generate // This uses the FakePLL, which uses a ClockAtFreq Verilog blackbox to generate
// the requested clocks. This also adds TileLink ClockDivider and ClockSelector // the requested clocks. This also adds TileLink ClockDivider and ClockSelector
// blocks, which allow memory-mapped control of clock division, and clock muxing // blocks, which allow memory-mapped control of clock division, and clock muxing
@@ -58,13 +54,13 @@ class WithPLLSelectorDividerClockGenerator extends OverrideLazyIOBinder({
pllCtrlSink := pllCtrl.ctrlNode pllCtrlSink := pllCtrl.ctrlNode
InModuleBody { InModuleBody {
val clock_wire = Wire(Input(new ClockWithFreq(100))) val clock_wire = Wire(Input(Clock()))
val reset_wire = Wire(Input(AsyncReset())) val reset_wire = Wire(Input(AsyncReset()))
val (clock_io, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, "clock", p(IOCellKey)) val (clock_io, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, "clock", p(IOCellKey))
val (reset_io, resetIOCell) = IOCell.generateIOFromSignal(reset_wire, "reset", p(IOCellKey)) val (reset_io, resetIOCell) = IOCell.generateIOFromSignal(reset_wire, "reset", p(IOCellKey))
slowClockSource.out.unzip._1.map { o => slowClockSource.out.unzip._1.map { o =>
o.clock := clock_wire.clock o.clock := clock_wire
o.reset := reset_wire o.reset := reset_wire
} }
@@ -79,7 +75,7 @@ class WithPLLSelectorDividerClockGenerator extends OverrideLazyIOBinder({
o.reset := reset_wire o.reset := reset_wire
} }
(Seq(clock_io, reset_io), clockIOCell ++ resetIOCell) (Seq(ClockPort(clock_io, 100), ResetPort(reset_io)), clockIOCell ++ resetIOCell)
} }
} }
}) })
@@ -114,12 +110,12 @@ class WithPassthroughClockGenerator extends OverrideLazyIOBinder({
require(m.take.isDefined, s"""Clock ${m.name.get} has no requested frequency require(m.take.isDefined, s"""Clock ${m.name.get} has no requested frequency
|Clocks: ${edge.sink.members.map(_.name.get)}""".stripMargin) |Clocks: ${edge.sink.members.map(_.name.get)}""".stripMargin)
val freq = m.take.get.freqMHz val freq = m.take.get.freqMHz
val clock_io = IO(Input(new ClockWithFreq(freq))).suggestName(s"clock_${m.name.get}") val clock_io = IO(Input(Clock())).suggestName(s"clock_${m.name.get}")
b.clock := clock_io.clock b.clock := clock_io
b.reset := reset_io b.reset := reset_io
clock_io ClockPort(clock_io, freq)
}.toSeq }.toSeq
((clock_ios :+ reset_io), Nil) ((clock_ios :+ ResetPort(reset_io)), Nil)
} }
} }
}) })

View File

@@ -51,7 +51,7 @@ object FrequencyUtils {
require(!requestedOutputs.contains(0.0)) require(!requestedOutputs.contains(0.0))
val requestedFreqs = requestedOutputs.map(_.freqMHz) val requestedFreqs = requestedOutputs.map(_.freqMHz)
val fastestFreq = requestedFreqs.max val fastestFreq = requestedFreqs.max
require(fastestFreq <= maximumAllowableFreqMHz) require(fastestFreq <= maximumAllowableFreqMHz, s"Fastest Freq $fastestFreq > Max Freq $maximumAllowableFreqMHz")
val candidateFreqs = val candidateFreqs =
Seq.tabulate(Math.ceil(maximumAllowableFreqMHz / fastestFreq).toInt)(i => (i + 1) * fastestFreq) Seq.tabulate(Math.ceil(maximumAllowableFreqMHz / fastestFreq).toInt)(i => (i + 1) * fastestFreq)

View File

@@ -15,7 +15,8 @@ class AbstractConfig extends Config(
new chipyard.harness.WithUARTAdapter ++ // add UART adapter to display UART on stdout, if uart is present 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.WithBlackBoxSimMem ++ // add SimDRAM DRAM model for axi4 backing memory, if axi4 mem is enabled
new chipyard.harness.WithSimTSIOverSerialTL ++ // add external serial-adapter and RAM new chipyard.harness.WithSimTSIOverSerialTL ++ // add external serial-adapter and RAM
new chipyard.harness.WithSimDebug ++ // add SimJTAG or SimDTM adapters if debug module is enabled new chipyard.harness.WithSimJTAGDebug ++ // add SimJTAG if JTAG for debug exposed
new chipyard.harness.WithSimDMI ++ // add SimJTAG if DMI exposed
new chipyard.harness.WithGPIOTiedOff ++ // tie-off chiptop GPIOs, if GPIOs are 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.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.WithSimAXIMMIO ++ // add SimAXIMem for axi4 mmio port, if enabled
@@ -23,7 +24,8 @@ class AbstractConfig extends Config(
new chipyard.harness.WithTieOffL2FBusAXI ++ // tie-off external AXI4 master, if present new chipyard.harness.WithTieOffL2FBusAXI ++ // tie-off external AXI4 master, if present
new chipyard.harness.WithCustomBootPinPlusArg ++ // drive custom-boot pin with a plusarg, if custom-boot-pin is present new chipyard.harness.WithCustomBootPinPlusArg ++ // drive custom-boot pin with a plusarg, if custom-boot-pin is present
new chipyard.harness.WithSimUARTToUARTTSI ++ // connect a SimUART to the UART-TSI port new chipyard.harness.WithSimUARTToUARTTSI ++ // connect a SimUART to the UART-TSI port
new chipyard.harness.WithClockAndResetFromHarness ++ // all Clock/Reset I/O in ChipTop should be driven by harnessClockInstantiator new chipyard.harness.WithClockFromHarness ++ // all Clock I/O in ChipTop should be driven by harnessClockInstantiator
new chipyard.harness.WithResetFromHarness ++ // reset controlled by harness
new chipyard.harness.WithAbsoluteFreqHarnessClockInstantiator ++ // generate clocks in harness with unsynthesizable ClockSourceAtFreqMHz new chipyard.harness.WithAbsoluteFreqHarnessClockInstantiator ++ // generate clocks in harness with unsynthesizable ClockSourceAtFreqMHz
// The IOBinders instantiate ChipTop IOs to match desired digital IOs // The IOBinders instantiate ChipTop IOs to match desired digital IOs
@@ -32,11 +34,13 @@ class AbstractConfig extends Config(
new chipyard.iobinders.WithDebugIOCells ++ new chipyard.iobinders.WithDebugIOCells ++
new chipyard.iobinders.WithUARTIOCells ++ new chipyard.iobinders.WithUARTIOCells ++
new chipyard.iobinders.WithGPIOCells ++ new chipyard.iobinders.WithGPIOCells ++
new chipyard.iobinders.WithSPIIOCells ++ new chipyard.iobinders.WithSPIFlashIOCells ++
new chipyard.iobinders.WithExtInterruptIOCells ++ new chipyard.iobinders.WithExtInterruptIOCells ++
new chipyard.iobinders.WithCustomBootPin ++ new chipyard.iobinders.WithCustomBootPin ++
// The "punchthrough" IOBInders below don't generate IOCells, as these interfaces shouldn't really be mapped to ASIC IO // The "punchthrough" IOBInders below don't generate IOCells, as these interfaces shouldn't really be mapped to ASIC IO
// Instead, they directly pass through the DigitalTop ports to ports in the ChipTop // Instead, they directly pass through the DigitalTop ports to ports in the ChipTop
new chipyard.iobinders.WithI2CPunchthrough ++
new chipyard.iobinders.WithSPIIOPunchthrough ++
new chipyard.iobinders.WithAXI4MemPunchthrough ++ new chipyard.iobinders.WithAXI4MemPunchthrough ++
new chipyard.iobinders.WithAXI4MMIOPunchthrough ++ new chipyard.iobinders.WithAXI4MMIOPunchthrough ++
new chipyard.iobinders.WithTLMemPunchthrough ++ new chipyard.iobinders.WithTLMemPunchthrough ++

View File

@@ -7,7 +7,8 @@ class AbstractTraceGenConfig extends Config(
new chipyard.harness.WithAbsoluteFreqHarnessClockInstantiator ++ new chipyard.harness.WithAbsoluteFreqHarnessClockInstantiator ++
new chipyard.harness.WithBlackBoxSimMem ++ new chipyard.harness.WithBlackBoxSimMem ++
new chipyard.harness.WithTraceGenSuccess ++ new chipyard.harness.WithTraceGenSuccess ++
new chipyard.harness.WithClockAndResetFromHarness ++ new chipyard.harness.WithClockFromHarness ++
new chipyard.harness.WithResetFromHarness ++
new chipyard.iobinders.WithAXI4MemPunchthrough ++ new chipyard.iobinders.WithAXI4MemPunchthrough ++
new chipyard.iobinders.WithTraceGenSuccessPunchthrough ++ new chipyard.iobinders.WithTraceGenSuccessPunchthrough ++
new chipyard.clocking.WithPassthroughClockGenerator ++ new chipyard.clocking.WithPassthroughClockGenerator ++

View File

@@ -68,13 +68,13 @@ class FlatChipTop(implicit p: Parameters) extends LazyModule {
l.reset := implicit_reset l.reset := implicit_reset
}} }}
val clock_wire = Wire(Input(new ClockWithFreq(80))) val clock_wire = Wire(Input(Clock()))
val reset_wire = Wire(Input(AsyncReset())) val reset_wire = Wire(Input(AsyncReset()))
val (clock_pad, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, "clock", p(IOCellKey)) val (clock_pad, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, "clock", p(IOCellKey))
val (reset_pad, resetIOCell) = IOCell.generateIOFromSignal(reset_wire, "reset", p(IOCellKey)) val (reset_pad, resetIOCell) = IOCell.generateIOFromSignal(reset_wire, "reset", p(IOCellKey))
slowClockSource.out.unzip._1.map { o => slowClockSource.out.unzip._1.map { o =>
o.clock := clock_wire.clock o.clock := clock_wire
o.reset := reset_wire o.reset := reset_wire
} }

View File

@@ -30,7 +30,7 @@ class FlatTestHarness(implicit val p: Parameters) extends Module {
val clock_source = Module(new ClockSourceAtFreqFromPlusArg("slow_clk_freq_mhz")) val clock_source = Module(new ClockSourceAtFreqFromPlusArg("slow_clk_freq_mhz"))
clock_source.io.power := true.B clock_source.io.power := true.B
clock_source.io.gate := false.B clock_source.io.gate := false.B
dut.clock_pad.clock := clock_source.io.clk dut.clock_pad := clock_source.io.clk
// Reset // Reset
dut.reset_pad := reset.asAsyncReset dut.reset_pad := reset.asAsyncReset

View File

@@ -6,355 +6,284 @@ import chisel3.experimental.{Analog, BaseModule, DataMirror, Direction}
import org.chipsalliance.cde.config.{Field, Config, Parameters} import org.chipsalliance.cde.config.{Field, Config, Parameters}
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImpLike} 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.system.{SimAXIMem}
import freechips.rocketchip.subsystem._ import freechips.rocketchip.subsystem._
import freechips.rocketchip.util._ import freechips.rocketchip.util._
import freechips.rocketchip.jtag.{JTAGIO}
import sifive.blocks.devices.gpio._ import freechips.rocketchip.devices.debug.{SimJTAG}
import sifive.blocks.devices.uart._
import sifive.blocks.devices.spi._
import barstools.iocell.chisel._ import barstools.iocell.chisel._
import testchipip._ import testchipip._
import icenet.{NicLoopback, SimNetwork}
import chipyard._ import chipyard._
import chipyard.clocking.{HasChipyardPRCI, ClockWithFreq} import chipyard.clocking.{HasChipyardPRCI}
import chipyard.iobinders.{GetSystemParameters, JTAGChipIO} import chipyard.iobinders._
import tracegen.{TraceGenSystemModuleImp} case object HarnessBinders extends Field[HarnessBinderFunction]({case _ => })
import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvonly}
import scala.reflect.{ClassTag}
case object HarnessBinders extends Field[HarnessBinderMap](HarnessBinderMapDefault)
object ApplyHarnessBinders { object ApplyHarnessBinders {
def apply(th: HasHarnessInstantiators, sys: LazyModule, portMap: Map[String, Seq[Data]])(implicit p: Parameters): Unit = { def apply(th: HasHarnessInstantiators, ports: Seq[Port[_]])(implicit p: Parameters): Unit = {
val pm = portMap.withDefaultValue(Nil) ports.foreach(port => p(HarnessBinders)(th, port))
p(HarnessBinders).foreach { case (s, f) =>
f(sys, th, pm(s))
f(sys.module, th, pm(s))
}
} }
} }
// The ClassTags here are necessary to overcome issues arising from type erasure class HarnessBinder[T <: HasHarnessInstantiators, S <: Port[_]](
class HarnessBinder[T, S <: HasHarnessInstantiators, U <: Data](composer: ((T, S, Seq[U]) => Unit) => (T, S, Seq[U]) => Unit)(implicit systemTag: ClassTag[T], harnessTag: ClassTag[S], portTag: ClassTag[U]) extends Config((site, here, up) => { fn: => HarnessBinderFunction
case HarnessBinders => up(HarnessBinders, site) + (systemTag.runtimeClass.toString -> ) extends Config((site, here, up) => {
((t: Any, th: HasHarnessInstantiators, ports: Seq[Data]) => { case HarnessBinders => fn orElse up(HarnessBinders)
val pts = ports.collect({case p: U => p})
require (pts.length == ports.length, s"Port type mismatch between IOBinder and HarnessBinder: ${portTag}")
val upfn = up(HarnessBinders, site)(systemTag.runtimeClass.toString)
(th, t) match {
case (th: S, system: T) => composer(upfn)(system, th, pts)
case _ =>
}
})
)
}) })
class OverrideHarnessBinder[T, S <: HasHarnessInstantiators, U <: Data](fn: => (T, S, Seq[U]) => Unit)
(implicit tag: ClassTag[T], thtag: ClassTag[S], ptag: ClassTag[U])
extends HarnessBinder[T, S, U]((upfn: (T, S, Seq[U]) => Unit) => fn)
class ComposeHarnessBinder[T, S <: HasHarnessInstantiators, U <: Data](fn: => (T, S, Seq[U]) => Unit) class WithGPIOTiedOff extends HarnessBinder({
(implicit tag: ClassTag[T], thtag: ClassTag[S], ptag: ClassTag[U]) case (th: HasHarnessInstantiators, port: GPIOPort) => {
extends HarnessBinder[T, S, U]((upfn: (T, S, Seq[U]) => Unit) => (t, th, p) => { port.io <> AnalogConst(0)
upfn(t, th, p)
fn(t, th, p)
})
class WithGPIOTiedOff extends OverrideHarnessBinder({
(system: HasPeripheryGPIOModuleImp, th: HasHarnessInstantiators, ports: Seq[Analog]) => {
ports.foreach { _ <> AnalogConst(0) }
} }
}) })
// DOC include start: WithUARTAdapter // DOC include start: WithUARTAdapter
class WithUARTAdapter extends OverrideHarnessBinder({ class WithUARTAdapter extends HarnessBinder({
(system: HasPeripheryUARTModuleImp, th: HasHarnessInstantiators, ports: Seq[UARTPortIO]) => { case (th: HasHarnessInstantiators, port: UARTPort) => {
UARTAdapter.connect(ports)(system.p) val div = (th.getHarnessBinderClockFreqMHz / port.io.c.initBaudRate.toDouble).toInt
val uart_sim = Module(new UARTAdapter(port.uartNo, div, false)).suggestName(s"uart_sim_uartno${port.uartNo}")
uart_sim.io.uart.txd := port.io.txd
port.io.rxd := uart_sim.io.uart.rxd
} }
}) })
// DOC include end: WithUARTAdapter // DOC include end: WithUARTAdapter
class WithSimSPIFlashModel(rdOnly: Boolean = true) extends OverrideHarnessBinder({ class WithSimSPIFlashModel(rdOnly: Boolean = true) extends HarnessBinder({
(system: HasPeripherySPIFlashModuleImp, th: HasHarnessInstantiators, ports: Seq[SPIChipIO]) => { case (th: HasHarnessInstantiators, port: SPIFlashPort) => {
SimSPIFlashModel.connect(ports, th.harnessBinderReset, rdOnly)(system.p) val spi_mem = Module(new SimSPIFlashModel(port.params.fSize, port.spiId, rdOnly)).suggestName(s"spi_mem${port.spiId}")
spi_mem.io.sck := port.io.sck
require(port.params.csWidth == 1, "I don't know what to do with your extra CS bits. Fix me please.")
spi_mem.io.cs(0) := port.io.cs(0)
spi_mem.io.dq.zip(port.io.dq).foreach { case (x, y) => x <> y }
spi_mem.io.reset := th.harnessBinderReset
} }
}) })
class WithSimBlockDevice extends OverrideHarnessBinder({ class WithSimBlockDevice extends HarnessBinder({
(system: CanHavePeripheryBlockDevice, th: HasHarnessInstantiators, ports: Seq[ClockedIO[BlockDeviceIO]]) => { case (th: HasHarnessInstantiators, port: BlockDevicePort) => {
implicit val p: Parameters = GetSystemParameters(system) val sim_blkdev = Module(new SimBlockDevice(port.params))
ports.map { b => SimBlockDevice.connect(b.clock, th.harnessBinderReset.asBool, Some(b.bits)) } sim_blkdev.io.bdev <> port.io.bits
sim_blkdev.io.clock := port.io.clock
sim_blkdev.io.reset := th.harnessBinderReset
} }
}) })
class WithBlockDeviceModel extends OverrideHarnessBinder({ class WithBlockDeviceModel extends HarnessBinder({
(system: CanHavePeripheryBlockDevice, th: HasHarnessInstantiators, ports: Seq[ClockedIO[BlockDeviceIO]]) => { case (th: HasHarnessInstantiators, port: BlockDevicePort) => {
implicit val p: Parameters = GetSystemParameters(system) val blkdev_model = Module(new BlockDeviceModel(16, port.params))
ports.map { b => BlockDeviceModel.connect(Some(b.bits)) } blkdev_model.io <> port.io.bits
blkdev_model.clock := port.io.clock
blkdev_model.reset := th.harnessBinderReset
} }
}) })
class WithLoopbackNIC extends OverrideHarnessBinder({ class WithLoopbackNIC extends HarnessBinder({
(system: CanHavePeripheryIceNIC, th: HasHarnessInstantiators, ports: Seq[ClockedIO[NICIOvonly]]) => { case (th: HasHarnessInstantiators, port: NICPort) => {
implicit val p: Parameters = GetSystemParameters(system) withClock(port.io.clock) { NicLoopback.connect(port.io.bits, port.params) }
ports.map { n => NicLoopback.connect(Some(n.bits), p(NICKey)) }
} }
}) })
class WithSimNetwork extends OverrideHarnessBinder({ class WithSimNetwork extends HarnessBinder({
(system: CanHavePeripheryIceNIC, th: BaseModule with HasHarnessInstantiators, ports: Seq[ClockedIO[NICIOvonly]]) => { case (th: HasHarnessInstantiators, port: NICPort) => {
implicit val p: Parameters = GetSystemParameters(system) withClock(port.io.clock) { SimNetwork.connect(Some(port.io.bits), port.io.clock, th.harnessBinderReset.asBool) }
ports.map { n => SimNetwork.connect(Some(n.bits), n.clock, th.harnessBinderReset.asBool) }
} }
}) })
class WithSimAXIMem extends OverrideHarnessBinder({ class WithSimAXIMem extends HarnessBinder({
(system: CanHaveMasterAXI4MemPort, th: HasHarnessInstantiators, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => { case (th: HasHarnessInstantiators, port: AXI4MemPort) => {
val p: Parameters = chipyard.iobinders.GetSystemParameters(system) val mem = LazyModule(new SimAXIMem(port.edge, size=port.params.master.size)(Parameters.empty))
(ports zip system.memAXI4Node.edges.in).map { case (port, edge) => withClock(port.io.clock) { Module(mem.module) }
val mem = LazyModule(new SimAXIMem(edge, size=p(ExtMem).get.master.size)(p)) mem.io_axi4.head <> port.io
Module(mem.module).suggestName("mem") }
mem.io_axi4.head <> port.bits })
class WithBlackBoxSimMem(additionalLatency: Int = 0) extends HarnessBinder({
case (th: HasHarnessInstantiators, port: AXI4MemPort) => {
// TODO FIX: This currently makes each SimDRAM contain the entire memory space
val memSize = port.params.master.size
val memBase = port.params.master.base
val lineSize = 64 // cache block size
val clockFreq = port.clockFreqMHz
val mem = Module(new SimDRAM(memSize, lineSize, clockFreq, memBase, port.edge.bundle)).suggestName("simdram")
mem.io.clock := port.io.clock
mem.io.reset := th.harnessBinderReset.asAsyncReset
mem.io.axi <> port.io.bits
// Bug in Chisel implementation. See https://github.com/chipsalliance/chisel3/pull/1781
def Decoupled[T <: Data](irr: IrrevocableIO[T]): DecoupledIO[T] = {
require(DataMirror.directionOf(irr.bits) == Direction.Output, "Only safe to cast produced Irrevocable bits to Decoupled.")
val d = Wire(new DecoupledIO(chiselTypeOf(irr.bits)))
d.bits := irr.bits
d.valid := irr.valid
irr.ready := d.ready
d
}
if (additionalLatency > 0) {
withClock (port.io.clock) {
mem.io.axi.aw <> (0 until additionalLatency).foldLeft(Decoupled(port.io.bits.aw))((t, _) => Queue(t, 1, pipe=true))
mem.io.axi.w <> (0 until additionalLatency).foldLeft(Decoupled(port.io.bits.w ))((t, _) => Queue(t, 1, pipe=true))
port.io.bits.b <> (0 until additionalLatency).foldLeft(Decoupled(mem.io.axi.b ))((t, _) => Queue(t, 1, pipe=true))
mem.io.axi.ar <> (0 until additionalLatency).foldLeft(Decoupled(port.io.bits.ar))((t, _) => Queue(t, 1, pipe=true))
port.io.bits.r <> (0 until additionalLatency).foldLeft(Decoupled(mem.io.axi.r ))((t, _) => Queue(t, 1, pipe=true))
}
} }
} }
}) })
class WithBlackBoxSimMem(additionalLatency: Int = 0) extends OverrideHarnessBinder({ class WithSimAXIMMIO extends HarnessBinder({
(system: CanHaveMasterAXI4MemPort, th: HasHarnessInstantiators, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => { case (th: HasHarnessInstantiators, port: AXI4MMIOPort) => {
val p: Parameters = chipyard.iobinders.GetSystemParameters(system) val mmio_mem = LazyModule(new SimAXIMem(port.edge, size = port.params.size)(Parameters.empty))
(ports zip system.memAXI4Node.edges.in).map { case (port, edge) => withClock(port.io.clock) { Module(mmio_mem.module) }
// TODO FIX: This currently makes each SimDRAM contain the entire memory space mmio_mem.io_axi4.head <> port.io.bits
val memSize = p(ExtMem).get.master.size }
val memBase = p(ExtMem).get.master.base })
val lineSize = p(CacheBlockBytes)
val clockFreq = p(MemoryBusKey).dtsFrequency.get class WithTieOffInterrupts extends HarnessBinder({
val mem = Module(new SimDRAM(memSize, lineSize, clockFreq, memBase, edge.bundle)).suggestName("simdram") case (th: HasHarnessInstantiators, port: ExtIntPort) => {
mem.io.axi <> port.bits port.io := 0.U
// Bug in Chisel implementation. See https://github.com/chipsalliance/chisel3/pull/1781 }
def Decoupled[T <: Data](irr: IrrevocableIO[T]): DecoupledIO[T] = { })
require(DataMirror.directionOf(irr.bits) == Direction.Output, "Only safe to cast produced Irrevocable bits to Decoupled.")
val d = Wire(new DecoupledIO(chiselTypeOf(irr.bits))) class WithTieOffL2FBusAXI extends HarnessBinder({
d.bits := irr.bits case (th: HasHarnessInstantiators, port: AXI4InPort) => {
d.valid := irr.valid port.io := DontCare
irr.ready := d.ready port.io.bits.aw.valid := false.B
d port.io.bits.w.valid := false.B
} port.io.bits.b.ready := false.B
if (additionalLatency > 0) { port.io.bits.ar.valid := false.B
withClockAndReset (port.clock, port.reset) { port.io.bits.r.ready := false.B
mem.io.axi.aw <> (0 until additionalLatency).foldLeft(Decoupled(port.bits.aw))((t, _) => Queue(t, 1, pipe=true)) }
mem.io.axi.w <> (0 until additionalLatency).foldLeft(Decoupled(port.bits.w ))((t, _) => Queue(t, 1, pipe=true)) })
port.bits.b <> (0 until additionalLatency).foldLeft(Decoupled(mem.io.axi.b))((t, _) => Queue(t, 1, pipe=true))
mem.io.axi.ar <> (0 until additionalLatency).foldLeft(Decoupled(port.bits.ar))((t, _) => Queue(t, 1, pipe=true)) class WithSimJTAGDebug extends HarnessBinder({
port.bits.r <> (0 until additionalLatency).foldLeft(Decoupled(mem.io.axi.r))((t, _) => Queue(t, 1, pipe=true)) case (th: HasHarnessInstantiators, port: JTAGPort) => {
} val dtm_success = WireInit(false.B)
} when (dtm_success) { th.success := true.B }
mem.io.clock := port.clock val jtag_wire = Wire(new JTAGIO)
mem.io.reset := port.reset jtag_wire.TDO.data := port.io.TDO
jtag_wire.TDO.driven := true.B
port.io.TCK := jtag_wire.TCK
port.io.TMS := jtag_wire.TMS
port.io.TDI := jtag_wire.TDI
val jtag = Module(new SimJTAG(tickDelay=3))
jtag.connect(jtag_wire, th.harnessBinderClock, th.harnessBinderReset.asBool, ~(th.harnessBinderReset.asBool), dtm_success)
}
})
class WithSimDMI extends HarnessBinder({
case (th: HasHarnessInstantiators, port: DMIPort) => {
val dtm_success = WireInit(false.B)
when (dtm_success) { th.success := true.B }
val dtm = Module(new TestchipSimDTM()(Parameters.empty)).connect(th.harnessBinderClock, th.harnessBinderReset.asBool, port.io, dtm_success)
}
})
class WithTiedOffJTAG extends HarnessBinder({
case (th: HasHarnessInstantiators, port: JTAGPort) => {
port.io.TCK := true.B.asClock
port.io.TMS := true.B
port.io.TDI := true.B
}
})
class WithTiedOffDMI extends HarnessBinder({
case (th: HasHarnessInstantiators, port: DMIPort) => {
port.io.dmi.req.valid := false.B
port.io.dmi.req.bits := DontCare
port.io.dmi.resp.ready := true.B
port.io.dmiClock := false.B.asClock
port.io.dmiReset := true.B
}
})
class WithSerialTLTiedOff extends HarnessBinder({
case (th: HasHarnessInstantiators, port: SerialTLPort) => {
if (DataMirror.directionOf(port.io.clock) == Direction.Input) {
port.io.clock := false.B.asClock
} }
port.io.bits.out.ready := false.B
port.io.bits.in.valid := false.B
port.io.bits.in.bits := DontCare
} }
}) })
class WithSimAXIMMIO extends OverrideHarnessBinder({ class WithSimTSIOverSerialTL extends HarnessBinder({
(system: CanHaveMasterAXI4MMIOPort, th: HasHarnessInstantiators, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => { case (th: HasHarnessInstantiators, port: SerialTLPort) => {
val p: Parameters = chipyard.iobinders.GetSystemParameters(system) val bits = port.io.bits
(ports zip system.mmioAXI4Node.edges.in).map { case (port, edge) => if (DataMirror.directionOf(port.io.clock) == Direction.Input) {
val mmio_mem = LazyModule(new SimAXIMem(edge, size = p(ExtBus).get.size)(p)) port.io.clock := th.harnessBinderClock
withClockAndReset(port.clock, port.reset) {
Module(mmio_mem.module).suggestName("mmio_mem")
}
mmio_mem.io_axi4.head <> port.bits
} }
val ram = LazyModule(new SerialRAM(port.serdesser)(port.serdesser.p))
Module(ram.module)
ram.module.io.ser <> port.io.bits
val tsi = Module(new SimTSI)
tsi.io.clock := th.harnessBinderClock
tsi.io.reset := th.harnessBinderReset
tsi.io.tsi <> ram.module.io.tsi
val exit = tsi.io.exit
val success = exit === 1.U
val error = exit >= 2.U
assert(!error, "*** FAILED *** (exit code = %d)\n", exit >> 1.U)
when (success) { th.success := true.B }
} }
}) })
class WithTieOffInterrupts extends OverrideHarnessBinder({ class WithSimUARTToUARTTSI extends HarnessBinder({
(system: HasExtInterruptsModuleImp, th: HasHarnessInstantiators, ports: Seq[UInt]) => { case (th: HasHarnessInstantiators, port: UARTPort) => {
ports.foreach { _ := 0.U } UARTAdapter.connect(Seq(port.io),
baudrate=port.io.c.initBaudRate,
clockFrequency=th.getHarnessBinderClockFreqHz.toInt,
forcePty=true)
} }
}) })
class WithTieOffL2FBusAXI extends OverrideHarnessBinder({ class WithSimTSIToUARTTSI extends HarnessBinder({
(system: CanHaveSlaveAXI4Port, th: HasHarnessInstantiators, ports: Seq[ClockedIO[AXI4Bundle]]) => { case (th: HasHarnessInstantiators, port: UARTTSIPort) => {
ports.foreach({ p => val freq = th.getHarnessBinderClockFreqHz.toInt
p.bits := DontCare val uart_to_serial = Module(new UARTToSerial(freq, port.io.uart.c))
p.bits.aw.valid := false.B val serial_width_adapter = Module(new SerialWidthAdapter(8, TSI.WIDTH))
p.bits.w.valid := false.B val success = SimTSI.connect(Some(TSIIO(serial_width_adapter.io.wide)), th.harnessBinderClock, th.harnessBinderReset)
p.bits.b.ready := false.B when (success) { th.success := true.B }
p.bits.ar.valid := false.B assert(!uart_to_serial.io.dropped)
p.bits.r.ready := false.B serial_width_adapter.io.narrow.flipConnect(uart_to_serial.io.serial)
}) uart_to_serial.io.uart.rxd := port.io.uart.txd
port.io.uart.rxd := uart_to_serial.io.uart.txd
} }
}) })
class WithSimDebug extends OverrideHarnessBinder({ class WithTraceGenSuccess extends HarnessBinder({
(system: HasPeripheryDebug, th: HasHarnessInstantiators, ports: Seq[Data]) => { case (th: HasHarnessInstantiators, port: SuccessPort) => {
implicit val p: Parameters = GetSystemParameters(system) when (port.io) { th.success := true.B }
ports.map {
case d: ClockedDMIIO =>
val dtm_success = WireInit(false.B)
when (dtm_success) { th.success := true.B }
val dtm = Module(new TestchipSimDTM).connect(th.harnessBinderClock, th.harnessBinderReset.asBool, d, dtm_success)
case j: JTAGChipIO =>
val dtm_success = WireInit(false.B)
when (dtm_success) { th.success := true.B }
val jtag_wire = Wire(new JTAGIO)
jtag_wire.TDO.data := j.TDO
jtag_wire.TDO.driven := true.B
j.TCK := jtag_wire.TCK
j.TMS := jtag_wire.TMS
j.TDI := jtag_wire.TDI
val jtag = Module(new SimJTAG(tickDelay=3))
jtag.connect(jtag_wire, th.harnessBinderClock, th.harnessBinderReset.asBool, ~(th.harnessBinderReset.asBool), dtm_success)
}
} }
}) })
class WithTiedOffDebug extends OverrideHarnessBinder({ class WithCospike extends HarnessBinder({
(system: HasPeripheryDebug, th: HasHarnessInstantiators, ports: Seq[Data]) => { case (th: HasHarnessInstantiators, port: TracePort) => {
ports.map { port.io.traces.zipWithIndex.map(t => SpikeCosim(t._1, t._2, port.cosimCfg))
case j: JTAGChipIO =>
j.TCK := true.B.asClock
j.TMS := true.B
j.TDI := true.B
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 a: ClockedAPBBundle =>
a.pready := false.B
a.pslverr := false.B
a.prdata := 0.U
a.pduser := DontCare
a.clock := false.B.asClock
a.reset := true.B.asAsyncReset
a.psel := false.B
a.penable := false.B
}
} }
}) })
class WithSerialTLTiedOff extends OverrideHarnessBinder({ class WithCustomBootPinPlusArg extends HarnessBinder({
(system: CanHavePeripheryTLSerial, th: HasHarnessInstantiators, ports: Seq[ClockedIO[SerialIO]]) => { case (th: HasHarnessInstantiators, port: CustomBootPort) => {
implicit val p = chipyard.iobinders.GetSystemParameters(system)
ports.map({ port =>
val bits = port.bits
if (DataMirror.directionOf(port.clock) == Direction.Input) {
port.clock := false.B.asClock
}
port.bits.out.ready := false.B
port.bits.in.valid := false.B
port.bits.in.bits := DontCare
})
}
})
class WithSimTSIOverSerialTL extends OverrideHarnessBinder({
(system: CanHavePeripheryTLSerial, th: HasHarnessInstantiators, ports: Seq[ClockedIO[SerialIO]]) => {
implicit val p = chipyard.iobinders.GetSystemParameters(system)
ports.map({ port =>
val bits = port.bits
if (DataMirror.directionOf(port.clock) == Direction.Input) {
port.clock := th.harnessBinderClock
}
val ram = TSIHarness.connectRAM(system.serdesser.get, bits, th.harnessBinderReset)
val success = SimTSI.connect(Some(ram.module.io.tsi), th.harnessBinderClock, th.harnessBinderReset.asBool)
when (success) { th.success := true.B }
})
}
})
class WithSimUARTToUARTTSI extends OverrideHarnessBinder({
(system: CanHavePeripheryUARTTSI, th: HasHarnessInstantiators, ports: Seq[UARTTSIIO]) => {
implicit val p = chipyard.iobinders.GetSystemParameters(system)
require(ports.size <= 1)
ports.map { port => {
UARTAdapter.connect(Seq(port.uart),
baudrate=port.uartParams.initBaudRate,
clockFrequency=th.getHarnessBinderClockFreqHz.toInt,
forcePty=true)
assert(!port.dropped)
}}
}
})
class WithSimTSIToUARTTSI extends OverrideHarnessBinder({
(system: CanHavePeripheryUARTTSI, th: HasHarnessInstantiators, ports: Seq[UARTTSIIO]) => {
implicit val p = chipyard.iobinders.GetSystemParameters(system)
require(ports.size <= 1)
ports.map({ port =>
val freq = th.getHarnessBinderClockFreqHz.toInt
val uart_to_serial = Module(new UARTToSerial(freq, port.uartParams))
val serial_width_adapter = Module(new SerialWidthAdapter(8, TSI.WIDTH))
val success = SimTSI.connect(Some(TSIIO(serial_width_adapter.io.wide)), th.harnessBinderClock, th.harnessBinderReset)
when (success) { th.success := true.B }
assert(!uart_to_serial.io.dropped)
serial_width_adapter.io.narrow.flipConnect(uart_to_serial.io.serial)
uart_to_serial.io.uart.rxd := port.uart.txd
port.uart.rxd := uart_to_serial.io.uart.txd
})
}
})
class WithTraceGenSuccess extends OverrideHarnessBinder({
(system: TraceGenSystemModuleImp, th: HasHarnessInstantiators, ports: Seq[Bool]) => {
ports.map { p => when (p) { th.success := true.B } }
}
})
class WithCospike extends ComposeHarnessBinder({
(system: CanHaveTraceIOModuleImp, th: HasHarnessInstantiators, ports: Seq[TraceOutputTop]) => {
implicit val p = chipyard.iobinders.GetSystemParameters(system)
val chipyardSystem = system.asInstanceOf[ChipyardSystemModule[_]].outer.asInstanceOf[ChipyardSystem]
val tiles = chipyardSystem.tiles
val cfg = SpikeCosimConfig(
isa = tiles.headOption.map(_.isaDTS).getOrElse(""),
vlen = tiles.headOption.map(_.tileParams.core.vLen).getOrElse(0),
priv = tiles.headOption.map(t => if (t.usingUser) "MSU" else if (t.usingSupervisor) "MS" else "M").getOrElse(""),
mem0_base = p(ExtMem).map(_.master.base).getOrElse(BigInt(0)),
mem0_size = p(ExtMem).map(_.master.size).getOrElse(BigInt(0)),
pmpregions = tiles.headOption.map(_.tileParams.core.nPMPs).getOrElse(0),
nharts = tiles.size,
bootrom = chipyardSystem.bootROM.map(_.module.contents.toArray.mkString(" ")).getOrElse(""),
has_dtm = p(ExportDebug).protocols.contains(DMI) // assume that exposing clockeddmi means we will connect SimDTM
)
ports.map { p => p.traces.zipWithIndex.map(t => SpikeCosim(t._1, t._2, cfg)) }
}
})
class WithCustomBootPinPlusArg extends OverrideHarnessBinder({
(system: CanHavePeripheryCustomBootPin, th: HasHarnessInstantiators, ports: Seq[Bool]) => {
val pin = PlusArg("custom_boot_pin", width=1) val pin = PlusArg("custom_boot_pin", width=1)
ports.foreach(_ := pin) port.io := pin
} }
}) })
class WithClockFromHarness extends HarnessBinder({
class WithClockAndResetFromHarness extends OverrideHarnessBinder({ case (th: HasHarnessInstantiators, port: ClockPort) => {
(system: HasChipyardPRCI, th: HasHarnessInstantiators, ports: Seq[Data]) => {
implicit val p = GetSystemParameters(system)
val clocks = ports.collect { case c: ClockWithFreq => c }
// DOC include start: HarnessClockInstantiatorEx // DOC include start: HarnessClockInstantiatorEx
ports.map ({ port.io := th.harnessClockInstantiator.requestClockMHz(s"clock_${port.freqMHz}MHz", port.freqMHz)
case c: ClockWithFreq => {
val clock = th.harnessClockInstantiator.requestClockMHz(s"clock_${c.freqMHz.toInt}MHz", c.freqMHz)
c.clock := clock
}
case r: AsyncReset => r := th.referenceReset.asAsyncReset
})
// DOC include end: HarnessClockInstantiatorEx // DOC include end: HarnessClockInstantiatorEx
} }
}) })
class WithResetFromHarness extends HarnessBinder({
case (th: HasHarnessInstantiators, port: ResetPort) => {
port.io := th.referenceReset.asAsyncReset
}
})

View File

@@ -83,7 +83,7 @@ trait HasHarnessInstantiators {
withClockAndReset (harnessBinderClock, harnessBinderReset) { withClockAndReset (harnessBinderClock, harnessBinderReset) {
lazyDuts.zipWithIndex.foreach { lazyDuts.zipWithIndex.foreach {
case (d: HasIOBinders, i: Int) => ApplyHarnessBinders(this, d.lazySystem, d.portMap)(chipParameters(i)) case (d: HasIOBinders, i: Int) => ApplyHarnessBinders(this, d.portMap.values.flatten.toSeq)(chipParameters(i))
case _ => case _ =>
} }
ApplyMultiHarnessBinders(this, lazyDuts) ApplyMultiHarnessBinders(this, lazyDuts)

View File

@@ -2,6 +2,7 @@ package chipyard.harness
import chisel3._ import chisel3._
import chisel3.util._ import chisel3.util._
import chisel3.experimental.{DataMirror, Direction}
import org.chipsalliance.cde.config.{Field, Config, Parameters} import org.chipsalliance.cde.config.{Field, Config, Parameters}
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImpLike} import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImpLike}
@@ -12,67 +13,58 @@ import freechips.rocketchip.util._
import testchipip._ import testchipip._
import chipyard._ import chipyard._
import chipyard.clocking.{HasChipyardPRCI, ClockWithFreq} import chipyard.iobinders.{GetSystemParameters, JTAGChipIO, HasIOBinders, Port, SerialTLPort}
import chipyard.iobinders.{GetSystemParameters, JTAGChipIO, HasIOBinders}
import scala.reflect.{ClassTag} import scala.reflect.{ClassTag}
case class MultiHarnessBinders(c0: Int, c1: Int) extends Field[MultiHarnessBinderMap](MultiHarnessBinderMapDefault) case class MultiHarnessBinders(chip0: Int, chip1: Int) extends Field[Seq[MultiHarnessBinderFunction]](Nil)
class MultiHarnessBinder[T0, T1, S <: HasHarnessInstantiators, U0 <: Data, U1 <: Data]
(chip0: Int, chip1: Int, fn: => (T0, T1, S, Seq[U0], Seq[U1]) => Unit)
(implicit tag0: ClassTag[T0], tag1: ClassTag[T1], thtag: ClassTag[S], ptag0: ClassTag[U0], ptag1: ClassTag[U1])
extends Config((site, here, up) => {
// Override any HarnessBinders for chip0/chip1
case MultiChipParameters(`chip0`) => new Config(
new OverrideHarnessBinder[T0, S, U0]((system: T0, th: S, ports: Seq[U0]) => Nil) ++
up(MultiChipParameters(chip0))
)
case MultiChipParameters(`chip1`) => new Config(
new OverrideHarnessBinder[T1, S, U1]((system: T1, th: S, ports: Seq[U1]) => Nil) ++
up(MultiChipParameters(chip1))
)
// Set the multiharnessbinder key
case MultiHarnessBinders(`chip0`, `chip1`) => up(MultiHarnessBinders(chip0, chip1)) +
((tag0.runtimeClass.toString, tag1.runtimeClass.toString) ->
((c0: Any, c1: Any, th: HasHarnessInstantiators, ports0: Seq[Data], ports1: Seq[Data]) => {
val pts0 = ports0.map(_.asInstanceOf[U0])
val pts1 = ports1.map(_.asInstanceOf[U1])
require(pts0.size == pts1.size)
(c0, c1, th) match {
case (c0: T0, c1: T1, th: S) => fn(c0, c1, th, pts0, pts1)
case _ =>
}
})
)
})
object ApplyMultiHarnessBinders { object ApplyMultiHarnessBinders {
def apply(th: HasHarnessInstantiators, chips: Seq[LazyModule])(implicit p: Parameters): Unit = { def apply(th: HasHarnessInstantiators, chips: Seq[LazyModule])(implicit p: Parameters): Unit = {
Seq.tabulate(chips.size, chips.size) { case (i, j) => if (i != j) { Seq.tabulate(chips.size, chips.size) { case (i, j) => if (i != j) {
(chips(i), chips(j)) match { (chips(i), chips(j)) match {
case (l0: HasIOBinders, l1: HasIOBinders) => p(MultiHarnessBinders(i, j)).foreach { case (l0: HasIOBinders, l1: HasIOBinders) => p(MultiHarnessBinders(i, j)).foreach { f =>
case ((s0, s1), f) => { f(l0.portMap.values.flatten.toSeq, l1.portMap.values.flatten.toSeq)
f(l0.lazySystem , l1.lazySystem , th, l0.portMap(s0), l1.portMap(s1))
f(l0.lazySystem.module, l1.lazySystem.module, th, l0.portMap(s0), l1.portMap(s1))
}
} }
case _ =>
} }
}} }}
} }
} }
class WithMultiChipSerialTL(chip0: Int, chip1: Int) extends MultiHarnessBinder(chip0, chip1, ( class MultiHarnessBinder[T <: Port[_]](
(system0: CanHavePeripheryTLSerial, system1: CanHavePeripheryTLSerial, chip0: Int, chip1: Int,
th: HasHarnessInstantiators, chip0portFn: T => Boolean, chip1portFn: T => Boolean,
ports0: Seq[ClockedIO[SerialIO]], ports1: Seq[ClockedIO[SerialIO]] connectFn: (T, T) => Unit
) => { )(implicit tag: ClassTag[T]) extends Config((site, here, up) => {
require(ports0.size == ports1.size) // Override any HarnessBinders for chip0/chip1
(ports0 zip ports1).map { case (l, r) => case MultiChipParameters(`chip0`) => new Config(
l.clock <> r.clock new HarnessBinder({case (th, port: T) if chip0portFn(port) => }) ++ up(MultiChipParameters(chip0))
require(l.bits.w == r.bits.w) )
l.bits.flipConnect(r.bits) case MultiChipParameters(`chip1`) => new Config(
new HarnessBinder({case (th, port: T) if chip1portFn(port) => }) ++ up(MultiChipParameters(chip1))
)
// Set the multiharnessbinder key
case MultiHarnessBinders(`chip0`, `chip1`) => up(MultiHarnessBinders(chip0, chip1)) :+ {
((chip0Ports: Seq[Port[_]], chip1Ports: Seq[Port[_]]) => {
val chip0Port: Seq[T] = chip0Ports.collect { case (p: T) if chip0portFn(p) => p }
val chip1Port: Seq[T] = chip1Ports.collect { case (p: T) if chip1portFn(p) => p }
require(chip0Port.size == 1 && chip1Port.size == 1)
connectFn(chip0Port(0), chip1Port(0))
})
} }
})
class WithMultiChipSerialTL(chip0: Int, chip1: Int, chip0portId: Int = 0, chip1portId: Int = 0) extends MultiHarnessBinder[SerialTLPort](
chip0, chip1,
(p0: SerialTLPort) => p0.portId == chip0portId,
(p1: SerialTLPort) => p1.portId == chip1portId,
(p0: SerialTLPort, p1: SerialTLPort) => {
(DataMirror.directionOf(p0.io.clock), DataMirror.directionOf(p1.io.clock)) match {
case (Direction.Input, Direction.Output) => p0.io.clock := p1.io.clock
case (Direction.Output, Direction.Input) => p1.io.clock := p0.io.clock
}
p0.io.bits.in <> p1.io.bits.out
p1.io.bits.in <> p0.io.bits.out
} }
)) )

View File

@@ -5,13 +5,7 @@ import scala.collection.immutable.ListMap
package object harness package object harness
{ {
type HarnessBinderFunction = (Any, HasHarnessInstantiators, Seq[Data]) => Unit import chipyard.iobinders.Port
type HarnessBinderMap = Map[String, HarnessBinderFunction] type HarnessBinderFunction = PartialFunction[(HasHarnessInstantiators, Port[_]), Unit]
def HarnessBinderMapDefault: HarnessBinderMap = (new ListMap[String, HarnessBinderFunction]) type MultiHarnessBinderFunction = (Seq[Port[_]], Seq[Port[_]]) => Unit
.withDefaultValue((t: Any, th: HasHarnessInstantiators, d: Seq[Data]) => ())
type MultiHarnessBinderFunction = (Any, Any, HasHarnessInstantiators, Seq[Data], Seq[Data]) => Unit
type MultiHarnessBinderMap = Map[(String, String), MultiHarnessBinderFunction]
def MultiHarnessBinderMapDefault: MultiHarnessBinderMap = (new ListMap[(String, String), MultiHarnessBinderFunction])
.withDefaultValue((_: Any, _: Any, _: HasHarnessInstantiators, _: Seq[Data], _: Seq[Data]) => ())
} }

View File

@@ -18,18 +18,19 @@ import freechips.rocketchip.tilelink.{TLBundle}
import sifive.blocks.devices.gpio._ import sifive.blocks.devices.gpio._
import sifive.blocks.devices.uart._ import sifive.blocks.devices.uart._
import sifive.blocks.devices.spi._ import sifive.blocks.devices.spi._
import sifive.blocks.devices.i2c._
import tracegen.{TraceGenSystemModuleImp} import tracegen.{TraceGenSystemModuleImp}
import barstools.iocell.chisel._ import barstools.iocell.chisel._
import testchipip._ import testchipip._
import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvonly} import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvonly}
import chipyard.{CanHaveMasterTLMemPort} import chipyard.{CanHaveMasterTLMemPort, ChipyardSystem, ChipyardSystemModule}
import scala.reflect.{ClassTag} import scala.reflect.{ClassTag}
object IOBinderTypes { object IOBinderTypes {
type IOBinderTuple = (Seq[Data], Seq[IOCell]) type IOBinderTuple = (Seq[Port[_]], Seq[IOCell])
type IOBinderFunction = (Boolean, => Any) => ModuleValue[IOBinderTuple] type IOBinderFunction = (Boolean, => Any) => ModuleValue[IOBinderTuple]
} }
import IOBinderTypes._ import IOBinderTypes._
@@ -82,7 +83,7 @@ abstract trait HasIOBinders { this: LazyModule =>
InModuleBody { InModuleBody {
if (p(DontTouchIOBindersPorts)) { if (p(DontTouchIOBindersPorts)) {
portMap.values.foreach(_.foreach(dontTouch(_))) portMap.values.flatten.foreach { case (port: Port[Data]) => dontTouch(port.io) }
} }
println("IOCells generated by IOBinders:") println("IOCells generated by IOBinders:")
@@ -171,29 +172,72 @@ class WithGPIOCells extends OverrideIOBinder({
iocell.io.ie := pin.o.ie iocell.io.ie := pin.o.ie
pin.i.ival := iocell.io.i pin.i.ival := iocell.io.i
iocell.io.pad <> g iocell.io.pad <> g
(g, iocell) (GPIOPort(g, i, j), iocell)
}).unzip }).unzip
}).unzip }).unzip
val ports: Seq[Analog] = ports2d.flatten (ports2d.flatten, cells2d.flatten)
(ports, cells2d.flatten) }
})
class WithGPIOPunchthrough extends OverrideIOBinder({
(system: HasPeripheryGPIOModuleImp) => {
val ports = system.gpio.zipWithIndex.map { case (gpio, i) =>
val io_gpio = IO(gpio.cloneType).suggestName(s"gpio_$i")
io_gpio <> gpio
GPIOPinsPort(io_gpio, i)
}
(ports, Nil)
}
})
class WithI2CPunchthrough extends OverrideIOBinder({
(system: HasPeripheryI2CModuleImp) => {
val ports = system.i2c.zipWithIndex.map { case (i2c, i) =>
val io_i2c = IO(i2c.cloneType).suggestName(s"i2c_$i")
io_i2c <> i2c
I2CPort(i2c)
}
(ports, Nil)
} }
}) })
// DOC include start: WithUARTIOCells // DOC include start: WithUARTIOCells
class WithUARTIOCells extends OverrideIOBinder({ class WithUARTIOCells extends OverrideIOBinder({
(system: HasPeripheryUARTModuleImp) => { (system: HasPeripheryUARTModuleImp) => {
val (ports: Seq[UARTPortIO], cells2d) = system.uart.zipWithIndex.map({ case (u, i) => val (ports: Seq[UARTPort], cells2d) = system.uart.zipWithIndex.map({ case (u, i) =>
val (port, ios) = IOCell.generateIOFromSignal(u, s"uart_${i}", system.p(IOCellKey), abstractResetAsAsync = true) val (port, ios) = IOCell.generateIOFromSignal(u, s"uart_${i}", system.p(IOCellKey), abstractResetAsAsync = true)
(port, ios) val where = PBUS // TODO fix
val bus = system.outer.asInstanceOf[HasTileLinkLocations].locateTLBusWrapper(where)
val freqMHz = bus.dtsFrequency.get.toInt / 1000000000
(UARTPort(port, i, freqMHz), ios)
}).unzip }).unzip
(ports, cells2d.flatten) (ports, cells2d.flatten)
} }
}) })
// DOC include end: WithUARTIOCells // DOC include end: WithUARTIOCells
class WithSPIIOCells extends OverrideIOBinder({ class WithSPIIOPunchthrough extends OverrideLazyIOBinder({
(system: HasPeripherySPI) => {
// attach resource to 1st SPI
if (system.tlSpiNodes.size > 0) ResourceBinding {
Resource(new MMCDevice(system.tlSpiNodes.head.device, 1), "reg").bind(ResourceAddress(0))
}
InModuleBody {
val spi = system.asInstanceOf[BaseSubsystem].module.asInstanceOf[HasPeripherySPIBundle].spi
val ports = spi.zipWithIndex.map({ case (s, i) =>
val io_spi = IO(s.cloneType).suggestName(s"spi_$i")
io_spi <> s
SPIPort(io_spi)
})
(ports, Nil)
}
}
})
class WithSPIFlashIOCells extends OverrideIOBinder({
(system: HasPeripherySPIFlashModuleImp) => { (system: HasPeripherySPIFlashModuleImp) => {
val (ports: Seq[SPIChipIO], cells2d) = system.qspi.zipWithIndex.map({ case (s, i) => val (ports: Seq[SPIFlashPort], cells2d) = system.qspi.zipWithIndex.map({ case (s, i) =>
val name = s"spi_${i}" val name = s"spi_${i}"
val port = IO(new SPIChipIO(s.c.csWidth)).suggestName(name) val port = IO(new SPIChipIO(s.c.csWidth)).suggestName(name)
val iocellBase = s"iocell_${name}" val iocellBase = s"iocell_${name}"
@@ -213,7 +257,7 @@ class WithSPIIOCells extends OverrideIOBinder({
iocell iocell
} }
(port, dqIOs ++ csIOs ++ sckIOs) (SPIFlashPort(port, system.p(PeripherySPIFlashKey)(i), i), dqIOs ++ csIOs ++ sckIOs)
}).unzip }).unzip
(ports, cells2d.flatten) (ports, cells2d.flatten)
} }
@@ -223,7 +267,7 @@ class WithExtInterruptIOCells extends OverrideIOBinder({
(system: HasExtInterruptsModuleImp) => { (system: HasExtInterruptsModuleImp) => {
if (system.outer.nExtInterrupts > 0) { if (system.outer.nExtInterrupts > 0) {
val (port: UInt, cells) = IOCell.generateIOFromSignal(system.interrupts, "ext_interrupts", system.p(IOCellKey), abstractResetAsAsync = true) val (port: UInt, cells) = IOCell.generateIOFromSignal(system.interrupts, "ext_interrupts", system.p(IOCellKey), abstractResetAsAsync = true)
(Seq(port), cells) (Seq(ExtIntPort(port)), cells)
} else { } else {
system.interrupts := DontCare // why do I have to drive this 0-wide wire??? system.interrupts := DontCare // why do I have to drive this 0-wide wire???
(Nil, Nil) (Nil, Nil)
@@ -273,7 +317,8 @@ class WithDebugIOCells extends OverrideLazyIOBinder({
// Add IOCells for the DMI/JTAG/APB ports // Add IOCells for the DMI/JTAG/APB ports
val dmiTuple = debug.clockeddmi.map { d => val dmiTuple = debug.clockeddmi.map { d =>
IOCell.generateIOFromSignal(d, "dmi", p(IOCellKey), abstractResetAsAsync = true) val (port, cells) = IOCell.generateIOFromSignal(d, "dmi", p(IOCellKey), abstractResetAsAsync = true)
(DMIPort(port), cells)
} }
val jtagTuple = debug.systemjtag.map { j => val jtagTuple = debug.systemjtag.map { j =>
@@ -282,14 +327,13 @@ class WithDebugIOCells extends OverrideLazyIOBinder({
j.jtag.TMS := jtag_wire.TMS j.jtag.TMS := jtag_wire.TMS
j.jtag.TDI := jtag_wire.TDI j.jtag.TDI := jtag_wire.TDI
jtag_wire.TDO := j.jtag.TDO.data jtag_wire.TDO := j.jtag.TDO.data
IOCell.generateIOFromSignal(jtag_wire, "jtag", p(IOCellKey), abstractResetAsAsync = true) val (port, cells) = IOCell.generateIOFromSignal(jtag_wire, "jtag", p(IOCellKey), abstractResetAsAsync = true)
(JTAGPort(port), cells)
} }
val apbTuple = debug.apb.map { a => require(!debug.apb.isDefined)
IOCell.generateIOFromSignal(a, "apb", p(IOCellKey), abstractResetAsAsync = true)
}
val allTuples = (dmiTuple ++ jtagTuple ++ apbTuple).toSeq val allTuples = (dmiTuple ++ jtagTuple).toSeq
(allTuples.map(_._1).toSeq, allTuples.flatMap(_._2).toSeq) (allTuples.map(_._1).toSeq, allTuples.flatMap(_._2).toSeq)
}).getOrElse((Nil, Nil)) }).getOrElse((Nil, Nil))
}}} }}}
@@ -297,20 +341,26 @@ class WithDebugIOCells extends OverrideLazyIOBinder({
}) })
class WithSerialTLIOCells extends OverrideIOBinder({ class WithSerialTLIOCells extends OverrideIOBinder({
(system: CanHavePeripheryTLSerial) => system.serial_tl.map({ s => (system: CanHavePeripheryTLSerial) => {
val sys = system.asInstanceOf[BaseSubsystem] val (ports, cells) = system.serial_tl.zipWithIndex.map({ case (s, id) =>
val (port, cells) = IOCell.generateIOFromSignal(s.getWrappedValue, "serial_tl", sys.p(IOCellKey), abstractResetAsAsync = true) val sys = system.asInstanceOf[BaseSubsystem]
(Seq(port), cells) val (port, cells) = IOCell.generateIOFromSignal(s.getWrappedValue, "serial_tl", sys.p(IOCellKey), abstractResetAsAsync = true)
}).getOrElse((Nil, Nil)) (SerialTLPort(port, sys.p(SerialTLKey).get, system.serdesser.get, id), cells)
}).unzip
(ports.toSeq, cells.flatten.toSeq)
}
}) })
class WithSerialTLPunchthrough extends OverrideIOBinder({ class WithSerialTLPunchthrough extends OverrideIOBinder({
(system: CanHavePeripheryTLSerial) => system.serial_tl.map({ s => (system: CanHavePeripheryTLSerial) => {
val sys = system.asInstanceOf[BaseSubsystem] val (ports, cells) = system.serial_tl.zipWithIndex.map({ case (s, id) =>
val port = IO(s.getWrappedValue.cloneType) val sys = system.asInstanceOf[BaseSubsystem]
port <> s.getWrappedValue val port = IO(s.getWrappedValue.cloneType)
(Seq(port), Nil) port <> s.getWrappedValue
}).getOrElse((Nil, Nil)) (SerialTLPort(port, sys.p(SerialTLKey).get, system.serdesser.get, id), Nil)
}).unzip
(ports.toSeq, cells.flatten.toSeq)
}
}) })
class WithAXI4MemPunchthrough extends OverrideLazyIOBinder({ class WithAXI4MemPunchthrough extends OverrideLazyIOBinder({
@@ -321,12 +371,11 @@ class WithAXI4MemPunchthrough extends OverrideLazyIOBinder({
def clockBundle = clockSinkNode.get.in.head._1 def clockBundle = clockSinkNode.get.in.head._1
InModuleBody { InModuleBody {
val ports: Seq[ClockedAndResetIO[AXI4Bundle]] = system.mem_axi4.zipWithIndex.map({ case (m, i) => val ports: Seq[AXI4MemPort] = system.mem_axi4.zipWithIndex.map({ case (m, i) =>
val p = IO(new ClockedAndResetIO(DataMirror.internal.chiselTypeClone[AXI4Bundle](m))).suggestName(s"axi4_mem_${i}") val port = IO(new ClockedIO(DataMirror.internal.chiselTypeClone[AXI4Bundle](m))).suggestName(s"axi4_mem_${i}")
p.bits <> m port.bits <> m
p.clock := clockBundle.clock port.clock := clockBundle.clock
p.reset := clockBundle.reset AXI4MemPort(port, p(ExtMem).get, system.memAXI4Node.edges.in(i), p(MemoryBusKey).dtsFrequency.get.toInt)
p
}).toSeq }).toSeq
(ports, Nil) (ports, Nil)
} }
@@ -341,12 +390,11 @@ class WithAXI4MMIOPunchthrough extends OverrideLazyIOBinder({
def clockBundle = clockSinkNode.get.in.head._1 def clockBundle = clockSinkNode.get.in.head._1
InModuleBody { InModuleBody {
val ports: Seq[ClockedAndResetIO[AXI4Bundle]] = system.mmio_axi4.zipWithIndex.map({ case (m, i) => val ports: Seq[AXI4MMIOPort] = system.mmio_axi4.zipWithIndex.map({ case (m, i) =>
val p = IO(new ClockedAndResetIO(DataMirror.internal.chiselTypeClone[AXI4Bundle](m))).suggestName(s"axi4_mmio_${i}") val port = IO(new ClockedIO(DataMirror.internal.chiselTypeClone[AXI4Bundle](m))).suggestName(s"axi4_mmio_${i}")
p.bits <> m port.bits <> m
p.clock := clockBundle.clock port.clock := clockBundle.clock
p.reset := clockBundle.reset AXI4MMIOPort(port, p(ExtBus).get, system.mmioAXI4Node.edges.in(i))
p
}).toSeq }).toSeq
(ports, Nil) (ports, Nil)
} }
@@ -361,11 +409,11 @@ class WithL2FBusAXI4Punchthrough extends OverrideLazyIOBinder({
def clockBundle = clockSinkNode.get.in.head._1 def clockBundle = clockSinkNode.get.in.head._1
InModuleBody { InModuleBody {
val ports: Seq[ClockedIO[AXI4Bundle]] = system.l2_frontend_bus_axi4.zipWithIndex.map({ case (m, i) => val ports: Seq[AXI4InPort] = system.l2_frontend_bus_axi4.zipWithIndex.map({ case (m, i) =>
val p = IO(new ClockedIO(Flipped(DataMirror.internal.chiselTypeClone[AXI4Bundle](m)))).suggestName(s"axi4_fbus_${i}") val port = IO(new ClockedIO(Flipped(DataMirror.internal.chiselTypeClone[AXI4Bundle](m)))).suggestName(s"axi4_fbus_${i}")
m <> p.bits m <> port.bits
p.clock := clockBundle.clock port.clock := clockBundle.clock
p AXI4InPort(port, p(ExtIn).get)
}).toSeq }).toSeq
(ports, Nil) (ports, Nil)
} }
@@ -374,10 +422,12 @@ class WithL2FBusAXI4Punchthrough extends OverrideLazyIOBinder({
class WithBlockDeviceIOPunchthrough extends OverrideIOBinder({ class WithBlockDeviceIOPunchthrough extends OverrideIOBinder({
(system: CanHavePeripheryBlockDevice) => { (system: CanHavePeripheryBlockDevice) => {
val ports: Seq[ClockedIO[BlockDeviceIO]] = system.bdev.map({ bdev => val ports: Seq[BlockDevicePort] = system.bdev.map({ bdev =>
val p = IO(new ClockedIO(new BlockDeviceIO()(GetSystemParameters(system)))).suggestName("blockdev") val p = GetSystemParameters(system)
p <> bdev val bdParams = p(BlockDeviceKey).get
p val port = IO(new ClockedIO(new BlockDeviceIO(bdParams))).suggestName("blockdev")
port <> bdev
BlockDevicePort(port, bdParams)
}).toSeq }).toSeq
(ports, Nil) (ports, Nil)
} }
@@ -385,10 +435,11 @@ class WithBlockDeviceIOPunchthrough extends OverrideIOBinder({
class WithNICIOPunchthrough extends OverrideIOBinder({ class WithNICIOPunchthrough extends OverrideIOBinder({
(system: CanHavePeripheryIceNIC) => { (system: CanHavePeripheryIceNIC) => {
val ports: Seq[ClockedIO[NICIOvonly]] = system.icenicOpt.map({ n => val ports: Seq[NICPort] = system.icenicOpt.map({ n =>
val p = IO(new ClockedIO(new NICIOvonly)).suggestName("nic") val p = GetSystemParameters(system)
p <> n val port = IO(new ClockedIO(new NICIOvonly)).suggestName("nic")
p port <> n
NICPort(port, p(NICKey).get)
}).toSeq }).toSeq
(ports, Nil) (ports, Nil)
} }
@@ -398,16 +449,30 @@ class WithTraceGenSuccessPunchthrough extends OverrideIOBinder({
(system: TraceGenSystemModuleImp) => { (system: TraceGenSystemModuleImp) => {
val success: Bool = IO(Output(Bool())).suggestName("success") val success: Bool = IO(Output(Bool())).suggestName("success")
success := system.success success := system.success
(Seq(success), Nil) (Seq(SuccessPort(success)), Nil)
} }
}) })
class WithTraceIOPunchthrough extends OverrideIOBinder({ class WithTraceIOPunchthrough extends OverrideIOBinder({
(system: CanHaveTraceIOModuleImp) => { (system: CanHaveTraceIOModuleImp) => {
val ports: Option[TraceOutputTop] = system.traceIO.map { t => val ports: Option[TracePort] = system.traceIO.map { t =>
val trace = IO(DataMirror.internal.chiselTypeClone[TraceOutputTop](t)).suggestName("trace") val trace = IO(DataMirror.internal.chiselTypeClone[TraceOutputTop](t)).suggestName("trace")
trace <> t trace <> t
trace val p = GetSystemParameters(system)
val chipyardSystem = system.asInstanceOf[ChipyardSystemModule[_]].outer.asInstanceOf[ChipyardSystem]
val tiles = chipyardSystem.tiles
val cfg = SpikeCosimConfig(
isa = tiles.headOption.map(_.isaDTS).getOrElse(""),
vlen = tiles.headOption.map(_.tileParams.core.vLen).getOrElse(0),
priv = tiles.headOption.map(t => if (t.usingUser) "MSU" else if (t.usingSupervisor) "MS" else "M").getOrElse(""),
mem0_base = p(ExtMem).map(_.master.base).getOrElse(BigInt(0)),
mem0_size = p(ExtMem).map(_.master.size).getOrElse(BigInt(0)),
pmpregions = tiles.headOption.map(_.tileParams.core.nPMPs).getOrElse(0),
nharts = tiles.size,
bootrom = chipyardSystem.bootROM.map(_.module.contents.toArray.mkString(" ")).getOrElse(""),
has_dtm = p(ExportDebug).protocols.contains(DMI) // assume that exposing clockeddmi means we will connect SimDTM
)
TracePort(trace, cfg)
} }
(ports.toSeq, Nil) (ports.toSeq, Nil)
} }
@@ -417,7 +482,7 @@ class WithCustomBootPin extends OverrideIOBinder({
(system: CanHavePeripheryCustomBootPin) => system.custom_boot_pin.map({ p => (system: CanHavePeripheryCustomBootPin) => system.custom_boot_pin.map({ p =>
val sys = system.asInstanceOf[BaseSubsystem] val sys = system.asInstanceOf[BaseSubsystem]
val (port, cells) = IOCell.generateIOFromSignal(p.getWrappedValue, "custom_boot", sys.p(IOCellKey), abstractResetAsAsync = true) val (port, cells) = IOCell.generateIOFromSignal(p.getWrappedValue, "custom_boot", sys.p(IOCellKey), abstractResetAsAsync = true)
(Seq(port), cells) (Seq(CustomBootPort(port)), cells)
}).getOrElse((Nil, Nil)) }).getOrElse((Nil, Nil))
}) })
@@ -426,7 +491,7 @@ class WithUARTTSIPunchthrough extends OverrideIOBinder({
val sys = system.asInstanceOf[BaseSubsystem] val sys = system.asInstanceOf[BaseSubsystem]
val uart_tsi = IO(new UARTTSIIO(p.uartParams)) val uart_tsi = IO(new UARTTSIIO(p.uartParams))
uart_tsi <> p uart_tsi <> p
(Seq(uart_tsi), Nil) (Seq(UARTTSIPort(uart_tsi)), Nil)
}).getOrElse((Nil, Nil)) }).getOrElse((Nil, Nil))
}) })
@@ -434,7 +499,7 @@ class WithTLMemPunchthrough extends OverrideIOBinder({
(system: CanHaveMasterTLMemPort) => { (system: CanHaveMasterTLMemPort) => {
val io_tl_mem_pins_temp = IO(DataMirror.internal.chiselTypeClone[HeterogeneousBag[TLBundle]](system.mem_tl)).suggestName("tl_slave") val io_tl_mem_pins_temp = IO(DataMirror.internal.chiselTypeClone[HeterogeneousBag[TLBundle]](system.mem_tl)).suggestName("tl_slave")
io_tl_mem_pins_temp <> system.mem_tl io_tl_mem_pins_temp <> system.mem_tl
(Seq(io_tl_mem_pins_temp), Nil) (Seq(TLMemPort(io_tl_mem_pins_temp)), Nil)
} }
}) })

View File

@@ -0,0 +1,94 @@
package chipyard.iobinders
import chisel3._
import chisel3.experimental.{Analog}
import sifive.blocks.devices.uart.{UARTPortIO}
import sifive.blocks.devices.spi.{SPIFlashParams, SPIPortIO}
import sifive.blocks.devices.i2c.{I2CPort}
import sifive.blocks.devices.gpio.{GPIOPortIO}
import testchipip._
import icenet.{NICIOvonly, NICConfig}
import org.chipsalliance.cde.config.{Parameters}
import freechips.rocketchip.amba.axi4.{AXI4Bundle, AXI4EdgeParameters}
import freechips.rocketchip.subsystem.{MemoryPortParams, MasterPortParams, SlavePortParams}
import freechips.rocketchip.devices.debug.{ClockedDMIIO}
import freechips.rocketchip.util.{HeterogeneousBag}
import freechips.rocketchip.tilelink.{TLBundle}
trait Port[T <: Data] {
val io: T
}
// These case classes are generated by IOBinders, and interpreted by HarnessBinders
case class GPIOPort (val io: Analog, val gpioId: Int, val pinId: Int)
extends Port[Analog]
case class GPIOPinsPort (val io: GPIOPortIO, val gpioId: Int)
extends Port[GPIOPortIO]
case class I2CPort (val io: sifive.blocks.devices.i2c.I2CPort)
extends Port[sifive.blocks.devices.i2c.I2CPort]
case class UARTPort (val io: UARTPortIO, val uartNo: Int, val freqMHz: Int)
extends Port[UARTPortIO]
case class SPIFlashPort (val io: SPIChipIO, val params: SPIFlashParams, val spiId: Int)
extends Port[SPIChipIO]
case class SPIPort (val io: SPIPortIO)
extends Port[SPIPortIO]
case class BlockDevicePort (val io: ClockedIO[BlockDeviceIO], val params: BlockDeviceConfig)
extends Port[ClockedIO[BlockDeviceIO]]
case class NICPort (val io: ClockedIO[NICIOvonly], val params: NICConfig)
extends Port[ClockedIO[NICIOvonly]]
case class AXI4MemPort (val io: ClockedIO[AXI4Bundle], val params: MemoryPortParams, val edge: AXI4EdgeParameters, val clockFreqMHz: Int)
extends Port[ClockedIO[AXI4Bundle]]
case class AXI4MMIOPort (val io: ClockedIO[AXI4Bundle], val params: MasterPortParams, val edge: AXI4EdgeParameters)
extends Port[ClockedIO[AXI4Bundle]]
case class AXI4InPort (val io: ClockedIO[AXI4Bundle], val params: SlavePortParams)
extends Port[ClockedIO[AXI4Bundle]]
case class ExtIntPort (val io: UInt)
extends Port[UInt]
case class DMIPort (val io: ClockedDMIIO)
extends Port[ClockedDMIIO]
case class JTAGPort (val io: JTAGChipIO)
extends Port[JTAGChipIO]
case class SerialTLPort (val io: ClockedIO[SerialIO], val params: SerialTLParams, val serdesser: TLSerdesser, val portId: Int)
extends Port[ClockedIO[SerialIO]]
case class UARTTSIPort (val io: UARTTSIIO)
extends Port[UARTTSIIO]
case class SuccessPort (val io: Bool)
extends Port[Bool]
case class TracePort (val io: TraceOutputTop, val cosimCfg: SpikeCosimConfig)
extends Port[TraceOutputTop]
case class CustomBootPort (val io: Bool)
extends Port[Bool]
case class ClockPort (val io: Clock, val freqMHz: Double)
extends Port[Clock]
case class ResetPort (val io: AsyncReset)
extends Port[Reset]
case class DebugResetPort (val io: Reset)
extends Port[Reset]
case class JTAGResetPort (val io: Reset)
extends Port[Reset]
case class TLMemPort (val io: HeterogeneousBag[TLBundle])
extends Port[HeterogeneousBag[TLBundle]]

View File

@@ -3,7 +3,6 @@
package firesim.firesim package firesim.firesim
import chisel3._ import chisel3._
import chisel3.experimental.annotate
import chisel3.experimental.{DataMirror, Direction} import chisel3.experimental.{DataMirror, Direction}
import chisel3.util.experimental.BoringUtils import chisel3.util.experimental.BoringUtils
@@ -12,7 +11,6 @@ import freechips.rocketchip.diplomacy.{LazyModule}
import freechips.rocketchip.devices.debug.{Debug, HasPeripheryDebug, ExportDebug, DMI} import freechips.rocketchip.devices.debug.{Debug, HasPeripheryDebug, ExportDebug, DMI}
import freechips.rocketchip.amba.axi4.{AXI4Bundle} import freechips.rocketchip.amba.axi4.{AXI4Bundle}
import freechips.rocketchip.subsystem._ import freechips.rocketchip.subsystem._
import freechips.rocketchip.tile.{RocketTile}
import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters} import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters}
import freechips.rocketchip.util.{ResetCatchAndSync} import freechips.rocketchip.util.{ResetCatchAndSync}
import sifive.blocks.devices.uart._ import sifive.blocks.devices.uart._
@@ -22,21 +20,19 @@ import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvon
import junctions.{NastiKey, NastiParameters} import junctions.{NastiKey, NastiParameters}
import midas.models.{FASEDBridge, AXI4EdgeSummary, CompleteConfig} import midas.models.{FASEDBridge, AXI4EdgeSummary, CompleteConfig}
import midas.targetutils.{MemModelAnnotation, EnableModelMultiThreadingAnnotation}
import firesim.bridges._ import firesim.bridges._
import firesim.configs.MemModelKey import firesim.configs.MemModelKey
import tracegen.{TraceGenSystemModuleImp} import tracegen.{TraceGenSystemModuleImp}
import cva6.CVA6Tile import cva6.CVA6Tile
import boom.common.{BoomTile}
import barstools.iocell.chisel._ import barstools.iocell.chisel._
import chipyard.iobinders.{IOBinders, OverrideIOBinder, ComposeIOBinder, GetSystemParameters, IOCellKey} import chipyard.iobinders._
import chipyard._ import chipyard._
import chipyard.harness._ import chipyard.harness._
object MainMemoryConsts { object MainMemoryConsts {
val regionNamePrefix = "MainMemory" val regionNamePrefix = "MainMemory"
def globalName()(implicit p: Parameters) = s"${regionNamePrefix}_${p(MultiChipIdx)}" def globalName(chipId: Int) = s"${regionNamePrefix}_$chipId"
} }
trait Unsupported { trait Unsupported {
@@ -69,130 +65,65 @@ class WithFireSimIOCellModels extends Config((site, here, up) => {
case IOCellKey => FireSimIOCellParams() case IOCellKey => FireSimIOCellParams()
}) })
class WithTSIBridgeAndHarnessRAMOverSerialTL extends OverrideHarnessBinder({ class WithTSIBridgeAndHarnessRAMOverSerialTL extends HarnessBinder({
(system: CanHavePeripheryTLSerial, th: FireSim, ports: Seq[ClockedIO[SerialIO]]) => { case (th: FireSim, port: SerialTLPort) => {
ports.map { port => val bits = port.io.bits
implicit val p = GetSystemParameters(system) port.io.clock := th.harnessBinderClock
val bits = port.bits val ram = LazyModule(new SerialRAM(port.serdesser)(Parameters.empty))
port.clock := th.harnessBinderClock Module(ram.module)
val ram = TSIHarness.connectRAM(system.serdesser.get, bits, th.harnessBinderReset) ram.module.io.ser <> port.io.bits
TSIBridge(th.harnessBinderClock, ram.module.io.tsi, p(ExtMem).map(_ => MainMemoryConsts.globalName), th.harnessBinderReset.asBool) TSIBridge(th.harnessBinderClock, ram.module.io.tsi,
} port.params.serialTLManagerParams.map(_ => MainMemoryConsts.globalName(th.p(MultiChipIdx))), th.harnessBinderReset.asBool)(th.p)
Nil
} }
}) })
class WithNICBridge extends OverrideHarnessBinder({ class WithNICBridge extends HarnessBinder({
(system: CanHavePeripheryIceNIC, th: FireSim, ports: Seq[ClockedIO[NICIOvonly]]) => { case (th: FireSim, port: NICPort) => {
val p: Parameters = GetSystemParameters(system) NICBridge(port.io.clock, port.io.bits)(th.p)
ports.map { n => NICBridge(n.clock, n.bits)(p) }
Nil
} }
}) })
class WithUARTBridge extends OverrideHarnessBinder({ class WithUARTBridge extends HarnessBinder({
(system: HasPeripheryUARTModuleImp, th: FireSim, ports: Seq[UARTPortIO]) => case (th: FireSim, port: UARTPort) =>
val uartSyncClock = Wire(Clock()) val uartSyncClock = th.harnessClockInstantiator.requestClockMHz("uart_clock", port.freqMHz)
uartSyncClock := false.B.asClock UARTBridge(uartSyncClock, port.io, th.harnessBinderReset.asBool)(th.p)
val pbusClockNode = system.outer.asInstanceOf[HasTileLinkLocations].locateTLBusWrapper(PBUS).fixedClockNode
val pbusClock = pbusClockNode.in.head._1.clock
BoringUtils.bore(pbusClock, Seq(uartSyncClock))
ports.map { p => UARTBridge(uartSyncClock, p, th.harnessBinderReset.asBool)(system.p) }; Nil
}) })
class WithBlockDeviceBridge extends OverrideHarnessBinder({ class WithBlockDeviceBridge extends HarnessBinder({
(system: CanHavePeripheryBlockDevice, th: FireSim, ports: Seq[ClockedIO[BlockDeviceIO]]) => { case (th: FireSim, port: BlockDevicePort) => {
implicit val p: Parameters = GetSystemParameters(system) BlockDevBridge(port.io.clock, port.io.bits, th.harnessBinderReset.asBool)
ports.map { b => BlockDevBridge(b.clock, b.bits, th.harnessBinderReset.asBool) }
Nil
} }
}) })
class WithFASEDBridge extends OverrideHarnessBinder({ class WithFASEDBridge extends HarnessBinder({
(system: CanHaveMasterAXI4MemPort, th: FireSim, ports: Seq[ClockedAndResetIO[AXI4Bundle]]) => { case (th: FireSim, port: AXI4MemPort) => {
implicit val p: Parameters = GetSystemParameters(system) val nastiKey = NastiParameters(port.io.bits.r.bits.data.getWidth,
(ports zip system.memAXI4Node.edges.in).map { case (axi4, edge) => port.io.bits.ar.bits.addr.getWidth,
val nastiKey = NastiParameters(axi4.bits.r.bits.data.getWidth, port.io.bits.ar.bits.id.getWidth)
axi4.bits.ar.bits.addr.getWidth, FASEDBridge(port.io.clock, port.io.bits, th.harnessBinderReset.asBool,
axi4.bits.ar.bits.id.getWidth) CompleteConfig(th.p(firesim.configs.MemModelKey),
system match { nastiKey,
case s: BaseSubsystem => FASEDBridge(axi4.clock, axi4.bits, axi4.reset.asBool, Some(AXI4EdgeSummary(port.edge)),
CompleteConfig(p(firesim.configs.MemModelKey), Some(MainMemoryConsts.globalName(th.p(MultiChipIdx)))))(th.p)
nastiKey,
Some(AXI4EdgeSummary(edge)),
Some(MainMemoryConsts.globalName)))
case _ => throw new Exception("Attempting to attach FASED Bridge to misconfigured design")
}
}
Nil
} }
}) })
class WithTracerVBridge extends ComposeHarnessBinder({ class WithTracerVBridge extends HarnessBinder({
(system: CanHaveTraceIOModuleImp, th: FireSim, ports: Seq[TraceOutputTop]) => { case (th: FireSim, port: TracePort) => {
ports.map { p => p.traces.map(tileTrace => TracerVBridge(tileTrace)(system.p)) } port.io.traces.map(tileTrace => TracerVBridge(tileTrace)(th.p))
Nil
} }
}) })
class WithCospikeBridge extends ComposeHarnessBinder({ class WithCospikeBridge extends HarnessBinder({
(system: CanHaveTraceIOModuleImp, th: FireSim, ports: Seq[TraceOutputTop]) => { case (th: FireSim, port: TracePort) => {
implicit val p = chipyard.iobinders.GetSystemParameters(system) port.io.traces.zipWithIndex.map(t => CospikeBridge(t._1, t._2, port.cosimCfg))
val chipyardSystem = system.asInstanceOf[ChipyardSystemModule[_]].outer.asInstanceOf[ChipyardSystem]
val tiles = chipyardSystem.tiles
val cfg = SpikeCosimConfig(
isa = tiles.headOption.map(_.isaDTS).getOrElse(""),
vlen = tiles.headOption.map(_.tileParams.core.vLen).getOrElse(0),
priv = tiles.headOption.map(t => if (t.usingUser) "MSU" else if (t.usingSupervisor) "MS" else "M").getOrElse(""),
mem0_base = p(ExtMem).map(_.master.base).getOrElse(BigInt(0)),
mem0_size = p(ExtMem).map(_.master.size).getOrElse(BigInt(0)),
pmpregions = tiles.headOption.map(_.tileParams.core.nPMPs).getOrElse(0),
nharts = tiles.size,
bootrom = chipyardSystem.bootROM.map(_.module.contents.toArray.mkString(" ")).getOrElse(""),
has_dtm = p(ExportDebug).protocols.contains(DMI) // assume that exposing clockeddmi means we will connect SimDTM
)
ports.map { p => p.traces.zipWithIndex.map(t => CospikeBridge(t._1, t._2, cfg)) }
} }
}) })
class WithTraceGenBridge extends OverrideHarnessBinder({ class WithSuccessBridge extends HarnessBinder({
(system: TraceGenSystemModuleImp, th: FireSim, ports: Seq[Bool]) => case (th: FireSim, port: SuccessPort) => {
ports.map { p => GroundTestBridge(th.harnessBinderClock, p)(system.p) }; Nil GroundTestBridge(th.harnessBinderClock, port.io)(th.p)
})
class WithFireSimMultiCycleRegfile extends ComposeIOBinder({
(system: HasTilesModuleImp) => {
system.outer.tiles.map {
case r: RocketTile => {
annotate(MemModelAnnotation(r.module.core.rocketImpl.rf.rf))
r.module.fpuOpt.foreach(fpu => annotate(MemModelAnnotation(fpu.fpuImpl.regfile)))
}
case b: BoomTile => {
val core = b.module.core
core.iregfile match {
case irf: boom.exu.RegisterFileSynthesizable => annotate(MemModelAnnotation(irf.regfile))
}
if (core.fp_pipeline != null) core.fp_pipeline.fregfile match {
case frf: boom.exu.RegisterFileSynthesizable => annotate(MemModelAnnotation(frf.regfile))
}
}
case _ =>
}
(Nil, Nil)
}
})
class WithFireSimFAME5 extends ComposeIOBinder({
(system: HasTilesModuleImp) => {
system.outer.tiles.map {
case b: BoomTile =>
annotate(EnableModelMultiThreadingAnnotation(b.module))
case r: RocketTile =>
annotate(EnableModelMultiThreadingAnnotation(r.module))
case _ => Nil
}
(Nil, Nil)
} }
}) })

View File

@@ -5,21 +5,26 @@ package firesim.firesim
import scala.collection.mutable.{LinkedHashMap} import scala.collection.mutable.{LinkedHashMap}
import chisel3._ import chisel3._
import chisel3.experimental.{IO} import chisel3.experimental.{IO, annotate}
import freechips.rocketchip.prci._ import freechips.rocketchip.prci._
import freechips.rocketchip.subsystem.{BaseSubsystem, SubsystemDriveAsyncClockGroupsKey} import freechips.rocketchip.subsystem.{BaseSubsystem, SubsystemDriveAsyncClockGroupsKey, HasTiles}
import org.chipsalliance.cde.config.{Field, Config, Parameters} import org.chipsalliance.cde.config.{Field, Config, Parameters}
import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, InModuleBody, ValName} import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp, InModuleBody, ValName}
import freechips.rocketchip.util.{ResetCatchAndSync, RecordMap} import freechips.rocketchip.util.{ResetCatchAndSync, RecordMap}
import freechips.rocketchip.tile.{RocketTile}
import boom.common.{BoomTile}
import midas.widgets.{Bridge, PeekPokeBridge, RationalClockBridge, RationalClock, ResetPulseBridge, ResetPulseBridgeParameters} import midas.widgets.{Bridge, PeekPokeBridge, RationalClockBridge, RationalClock, ResetPulseBridge, ResetPulseBridgeParameters}
import midas.targetutils.{MemModelAnnotation, EnableModelMultiThreadingAnnotation}
import chipyard._ import chipyard._
import chipyard.harness._ import chipyard.harness._
import chipyard.iobinders._ import chipyard.iobinders._
import chipyard.clocking._ import chipyard.clocking._
case object FireSimMultiCycleRegFile extends Field[Boolean](false)
case object FireSimFAME5 extends Field[Boolean](false)
/** /**
* Under FireSim's current multiclock implementation there can be only a * Under FireSim's current multiclock implementation there can be only a
* single clock bridge. This requires, therefore, that it be instantiated in * single clock bridge. This requires, therefore, that it be instantiated in
@@ -85,11 +90,46 @@ class FireSim(implicit val p: Parameters) extends RawModule with HasHarnessInsta
override val supportsMultiChip = true override val supportsMultiChip = true
instantiateChipTops() val chiptops = instantiateChipTops()
// Ensures FireSim-synthesized assertions and instrumentation is disabled // Ensures FireSim-synthesized assertions and instrumentation is disabled
// while resetBridge.io.reset is asserted. This ensures assertions do not fire at // while resetBridge.io.reset is asserted. This ensures assertions do not fire at
// time zero in the event their local reset is delayed (typically because it // time zero in the event their local reset is delayed (typically because it
// has been pipelined) // has been pipelined)
midas.targetutils.GlobalResetCondition(resetBridge.io.reset) midas.targetutils.GlobalResetCondition(resetBridge.io.reset)
// FireSim multi-cycle regfile optimization
// FireSim ModelMultithreading
chiptops.foreach {
case c: ChipTop => c.lazySystem match {
case ls: HasTiles => {
if (p(FireSimMultiCycleRegFile)) ls.tiles.map {
case r: RocketTile => {
annotate(MemModelAnnotation(r.module.core.rocketImpl.rf.rf))
r.module.fpuOpt.foreach(fpu => annotate(MemModelAnnotation(fpu.fpuImpl.regfile)))
}
case b: BoomTile => {
val core = b.module.core
core.iregfile match {
case irf: boom.exu.RegisterFileSynthesizable => annotate(MemModelAnnotation(irf.regfile))
}
if (core.fp_pipeline != null) core.fp_pipeline.fregfile match {
case frf: boom.exu.RegisterFileSynthesizable => annotate(MemModelAnnotation(frf.regfile))
}
}
case _ =>
}
if (p(FireSimFAME5)) ls.tiles.map {
case b: BoomTile =>
annotate(EnableModelMultiThreadingAnnotation(b.module))
case r: RocketTile =>
annotate(EnableModelMultiThreadingAnnotation(r.module))
case _ => Nil
}
}
case _ =>
}
case _ =>
}
} }

View File

@@ -55,6 +55,16 @@ class WithScalaTestFeatures extends Config((site, here, up) => {
case TracePortKey => up(TracePortKey, site).map(_.copy(print = true)) case TracePortKey => up(TracePortKey, site).map(_.copy(print = true))
}) })
// Multi-cycle regfile for rocket+boom
class WithFireSimMultiCycleRegfile extends Config((site, here, up) => {
case FireSimMultiCycleRegFile => true
})
// Model multithreading optimization
class WithFireSimFAME5 extends Config((site, here, up) => {
case FireSimFAME5 => true
})
// FASED Config Aliases. This to enable config generation via "_" concatenation // FASED Config Aliases. This to enable config generation via "_" concatenation
// which requires that all config classes be defined in the same package // which requires that all config classes be defined in the same package
class DDR3FCFS extends FCFS16GBQuadRank class DDR3FCFS extends FCFS16GBQuadRank
@@ -72,7 +82,8 @@ class WithMinimalFireSimDesignTweaks extends Config(
// Required*: Punch all clocks to FireSim's harness clock instantiator // Required*: Punch all clocks to FireSim's harness clock instantiator
new WithFireSimHarnessClockBridgeInstantiator ++ new WithFireSimHarnessClockBridgeInstantiator ++
new chipyard.harness.WithHarnessBinderClockFreqMHz(1000.0) ++ new chipyard.harness.WithHarnessBinderClockFreqMHz(1000.0) ++
new chipyard.harness.WithClockAndResetFromHarness ++ new chipyard.harness.WithClockFromHarness ++
new chipyard.harness.WithResetFromHarness ++
new chipyard.clocking.WithPassthroughClockGenerator ++ new chipyard.clocking.WithPassthroughClockGenerator ++
// Required*: When using FireSim-as-top to provide a correct path to the target bootrom source // Required*: When using FireSim-as-top to provide a correct path to the target bootrom source
new WithBootROM ++ new WithBootROM ++