Add examples of ChipLikeRocketConfig/FlatChipTop/FlatTestHarness

This commit is contained in:
Jerry Zhao
2023-04-05 18:37:35 -07:00
parent 70ea3b78ab
commit f1b17b533b
4 changed files with 278 additions and 3 deletions

View File

@@ -103,9 +103,14 @@ class WithPLLSelectorDividerClockGenerator extends OverrideLazyIOBinder({
// For a real chip you should replace this ClockSourceAtFreqFromPlusArg
// with a blackbox of whatever PLL is being integrated
val fakeClockSource = Module(new ClockSourceAtFreqFromPlusArg("pll_freq_mhz"))
fakeClockSource.io.power := pllCtrlSink.in(0)._1.power
fakeClockSource.io.gate := pllCtrlSink.in(0)._1.gate
val fake_pll = Module(new ClockSourceAtFreqFromPlusArg("pll_freq_mhz"))
fake_pll.io.power := pllCtrlSink.in(0)._1.power
fake_pll.io.gate := pllCtrlSink.in(0)._1.gate
pllClockSource.out.unzip._1.map { o =>
o.clock := fake_pll.io.clk
o.reset := reset_wire
}
(Seq(clock_io, reset_io), clockIOCell ++ resetIOCell)
}

View File

@@ -0,0 +1,44 @@
package chipyard
import freechips.rocketchip.config.{Config}
import freechips.rocketchip.diplomacy._
// A simple config demonstrating how to set up a basic chip in Chipyard
class ChipLikeRocketConfig extends Config(
//==================================
// Set up TestHarness
//==================================
new chipyard.WithAbsoluteFreqHarnessClockInstantiator ++ // use absolute frequencies for simulations in the harness
// NOTE: This only simulates properly in VCS
//==================================
// Set up tiles
//==================================
new freechips.rocketchip.subsystem.WithAsynchronousRocketTiles(3, 3) ++ // Add rational crossings between RocketTile and uncore
new freechips.rocketchip.subsystem.WithNBigCores(4) ++ // quad-core (4 RocketTiles)
//==================================
// Set up I/O
//==================================
new testchipip.WithSerialTLWidth(4) ++
new chipyard.harness.WithSimAXIMemOverSerialTL ++ // Attach fast SimDRAM to TestHarness
new chipyard.config.WithSerialTLBackingMemory ++ // Backing memory is over serial TL protocol
new freechips.rocketchip.subsystem.WithExtMemSize((1 << 30) * 4L) ++ // 4GB max external memory
//==================================
// Set up clock./reset
//==================================
new chipyard.clocking.WithPLLSelectorDividerClockGenerator ++ // Use a PLL-based clock selector/divider generator structure
// Create two clock groups, uncore and fbus, in addition to the tile clock groups
new chipyard.clocking.WithClockGroupsCombinedByName("uncore", "implicit", "sbus", "mbus", "cbus", "system_bus") ++
new chipyard.clocking.WithClockGroupsCombinedByName("fbus", "fbus", "pbus") ++
// Set up the crossings
new chipyard.config.WithCbusToPbusCrossingType(AsynchronousCrossing()) ++ // Add Async crossing between PBUS and CBUS
new chipyard.config.WithSbusToMbusCrossingType(AsynchronousCrossing()) ++ // Add Async crossings between backside of L2 and MBUS
new testchipip.WithAsynchronousSerialSlaveCrossing ++ // Add Async crossing between serial and MBUS. Its master-side is tied to the FBUS
new testchipip.WithSerialTLAsyncResetQueue ++ // Add Async reset queue to block ready while in reset
new chipyard.config.AbstractConfig)

View File

@@ -0,0 +1,143 @@
package chipyard.example
import chisel3._
import freechips.rocketchip.config.{Field, Parameters}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.prci._
import freechips.rocketchip.util._
import freechips.rocketchip.devices.debug.{ExportDebug, JtagDTMKey, Debug}
import freechips.rocketchip.tilelink.{TLBuffer}
import chipyard.{BuildSystem, DigitalTop}
import chipyard.clocking._
import chipyard.iobinders.{IOCellKey, JTAGChipIO}
import barstools.iocell.chisel._
// This "FlatChipTop" uses no IOBinders, so all the IO have
// to be explicitly constructed.
// This only supports the base "DigitalTop"
class FlatChipTop(implicit p: Parameters) extends LazyModule {
override lazy val desiredName = "ChipTop"
val system = LazyModule(p(BuildSystem)(p)).suggestName("system").asInstanceOf[DigitalTop]
//========================
// Diplomatic clock stuff
//========================
val implicitClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters(name = Some("implicit_clock"))))
system.connectImplicitClockSinkNode(implicitClockSinkNode)
val tlbus = system.locateTLBusWrapper(system.prciParams.slaveWhere)
val baseAddress = system.prciParams.baseAddress
val clockDivider = system.prci_ctrl_domain { LazyModule(new TLClockDivider (baseAddress + 0x20000, tlbus.beatBytes)) }
val clockSelector = system.prci_ctrl_domain { LazyModule(new TLClockSelector(baseAddress + 0x30000, tlbus.beatBytes)) }
val pllCtrl = system.prci_ctrl_domain { LazyModule(new FakePLLCtrl (baseAddress + 0x40000, tlbus.beatBytes)) }
tlbus.toVariableWidthSlave(Some("clock-div-ctrl")) { clockDivider.tlNode := TLBuffer() }
tlbus.toVariableWidthSlave(Some("clock-sel-ctrl")) { clockSelector.tlNode := TLBuffer() }
tlbus.toVariableWidthSlave(Some("pll-ctrl")) { pllCtrl.tlNode := TLBuffer() }
system.allClockGroupsNode := clockDivider.clockNode := clockSelector.clockNode
// Connect all other requested clocks
val slowClockSource = ClockSourceNode(Seq(ClockSourceParameters()))
val pllClockSource = ClockSourceNode(Seq(ClockSourceParameters()))
// The order of the connections to clockSelector.clockNode configures what
clockSelector.clockNode := slowClockSource
clockSelector.clockNode := pllClockSource
val pllCtrlSink = BundleBridgeSink[FakePLLCtrlBundle]()
pllCtrlSink := pllCtrl.ctrlNode
val debugClockSinkNode = ClockSinkNode(Seq(ClockSinkParameters()))
debugClockSinkNode := system.locateTLBusWrapper(p(ExportDebug).slaveWhere).fixedClockNode
def debugClockBundle = debugClockSinkNode.in.head._1
override lazy val module = new FlatChipTopImpl
class FlatChipTopImpl extends LazyRawModuleImp(this) {
//=========================
// Clock/reset
//=========================
val implicit_clock = implicitClockSinkNode.in.head._1.clock
val implicit_reset = implicitClockSinkNode.in.head._1.reset
system.module match { case l: LazyModuleImp => {
l.clock := implicit_clock
l.reset := implicit_reset
}}
val clock_wire = Wire(Input(new ClockWithFreq(80)))
val reset_wire = Wire(Input(AsyncReset()))
val (clock_pad, clockIOCell) = IOCell.generateIOFromSignal(clock_wire, "clock", p(IOCellKey))
val (reset_pad, resetIOCell) = IOCell.generateIOFromSignal(reset_wire, "reset", p(IOCellKey))
slowClockSource.out.unzip._1.map { o =>
o.clock := clock_wire.clock
o.reset := reset_wire
}
// For a real chip you should replace this ClockSourceAtFreqFromPlusArg
// with a blackbox of whatever PLL is being integrated
val fake_pll = Module(new ClockSourceAtFreqFromPlusArg("pll_freq_mhz"))
fake_pll.io.power := pllCtrlSink.in(0)._1.power
fake_pll.io.gate := pllCtrlSink.in(0)._1.gate
pllClockSource.out.unzip._1.map { o =>
o.clock := fake_pll.io.clk
o.reset := reset_wire
}
//=========================
// Custom Boot
//=========================
val (custom_boot_pad, customBootIOCell) = IOCell.generateIOFromSignal(system.custom_boot_pin.get.getWrappedValue, "custom_boot", p(IOCellKey))
//=========================
// Serialized TileLink
//=========================
val (serial_tl_pad, serialTLIOCells) = IOCell.generateIOFromSignal(system.serial_tl.get.getWrappedValue, "serial_tl", p(IOCellKey))
//=========================
// JTAG/Debug
//=========================
val debug = system.module.debug.get
// We never use the PSDIO, so tie it off on-chip
system.module.psd.psd.foreach { _ <> 0.U.asTypeOf(new PSDTestMode) }
system.module.resetctrl.map { rcio => rcio.hartIsInReset.map { _ := false.B } }
// Tie off extTrigger
debug.extTrigger.foreach { t =>
t.in.req := false.B
t.out.ack := t.out.req
}
// Tie off disableDebug
debug.disableDebug.foreach { d => d := false.B }
// Drive JTAG on-chip IOs
debug.systemjtag.map { j =>
j.reset := ResetCatchAndSync(j.jtag.TCK, debugClockBundle.reset.asBool)
j.mfr_id := p(JtagDTMKey).idcodeManufId.U(11.W)
j.part_number := p(JtagDTMKey).idcodePartNum.U(16.W)
j.version := p(JtagDTMKey).idcodeVersion.U(4.W)
}
Debug.connectDebugClockAndReset(Some(debug), debugClockBundle.clock)
// Add IOCells for the DMI/JTAG/APB ports
require(!debug.clockeddmi.isDefined)
require(!debug.apb.isDefined)
val (jtag_pad, jtagIOCells) = debug.systemjtag.map { j =>
val jtag_wire = Wire(new JTAGChipIO)
j.jtag.TCK := jtag_wire.TCK
j.jtag.TMS := jtag_wire.TMS
j.jtag.TDI := jtag_wire.TDI
jtag_wire.TDO := j.jtag.TDO.data
IOCell.generateIOFromSignal(jtag_wire, "jtag", p(IOCellKey), abstractResetAsAsync = true)
}.get
//==========================
// UART
//==========================
require(system.uarts.size == 1)
val (uart_pad, uartIOCells) = IOCell.generateIOFromSignal(system.module.uart.head, "uart_0", p(IOCellKey))
}
}

View File

@@ -0,0 +1,83 @@
package chipyard.example
import chisel3._
import scala.collection.mutable.{ArrayBuffer, LinkedHashMap}
import freechips.rocketchip.config.{Field, Parameters}
import freechips.rocketchip.diplomacy.{LazyModule}
import freechips.rocketchip.prci.{ClockSourceAtFreqFromPlusArg, ClockBundle, ClockBundleParameters}
import freechips.rocketchip.util.{PlusArg}
import freechips.rocketchip.subsystem.{CacheBlockBytes}
import freechips.rocketchip.devices.debug.{SimJTAG}
import freechips.rocketchip.jtag.{JTAGIO}
import testchipip.{SerialTLKey, SerialAdapter, UARTAdapter, SimDRAM}
import chipyard.{BuildTop}
// A "flat" TestHarness that doesn't use IOBinders
// use with caution.
// This example is hard-coded to work only for FlatChipTop, and the ChipLikeRocketConfig
class FlatTestHarness(implicit val p: Parameters) extends Module {
val io = IO(new Bundle {
val success = Output(Bool())
})
// This only works with FlatChipTop
val lazyDut = LazyModule(new FlatChipTop).suggestName("chiptop")
val dut = Module(lazyDut.module)
// Clock
val clock_source = Module(new ClockSourceAtFreqFromPlusArg("slow_clk_freq_mhz"))
clock_source.io.power := true.B
clock_source.io.gate := false.B
dut.clock_pad.clock := clock_source.io.clk
// Reset
dut.reset_pad := reset.asAsyncReset
// Custom boot
dut.custom_boot_pad := PlusArg("custom_boot_pin", width=1)
// Serialized TL
val sVal = p(SerialTLKey).get
require(sVal.axiMemOverSerialTLParams.isDefined)
require(sVal.isMemoryDevice)
val axiDomainParams = sVal.axiMemOverSerialTLParams.get
val memFreq = axiDomainParams.getMemFrequency(lazyDut.system)
withClockAndReset(clock, reset) {
val memOverSerialTLClockBundle = Wire(new ClockBundle(ClockBundleParameters()))
memOverSerialTLClockBundle.clock := clock
memOverSerialTLClockBundle.reset := reset
val serial_bits = SerialAdapter.asyncQueue(dut.serial_tl_pad, clock, reset)
val harnessMultiClockAXIRAM = SerialAdapter.connectHarnessMultiClockAXIRAM(
lazyDut.system.serdesser.get,
serial_bits,
memOverSerialTLClockBundle,
reset)
io.success := SerialAdapter.connectSimSerial(harnessMultiClockAXIRAM.module.io.tsi_ser, clock, reset)
// connect SimDRAM from the AXI port coming from the harness multi clock axi ram
(harnessMultiClockAXIRAM.mem_axi4 zip harnessMultiClockAXIRAM.memNode.edges.in).map { case (axi_port, edge) =>
val memSize = sVal.memParams.size
val lineSize = p(CacheBlockBytes)
val mem = Module(new SimDRAM(memSize, lineSize, BigInt(memFreq.toLong), edge.bundle)).suggestName("simdram")
mem.io.axi <> axi_port.bits
mem.io.clock := axi_port.clock
mem.io.reset := axi_port.reset
}
}
// JTAG
val jtag_wire = Wire(new JTAGIO)
jtag_wire.TDO.data := dut.jtag_pad.TDO
jtag_wire.TDO.driven := true.B
dut.jtag_pad.TCK := jtag_wire.TCK
dut.jtag_pad.TMS := jtag_wire.TMS
dut.jtag_pad.TDI := jtag_wire.TDI
val dtm_success = WireInit(false.B)
val jtag = Module(new SimJTAG(tickDelay=3)).connect(jtag_wire, clock, reset.asBool, ~(reset.asBool), dtm_success)
// UART
UARTAdapter.connect(Seq(dut.uart_pad))
}