Add examples of ChipLikeRocketConfig/FlatChipTop/FlatTestHarness
This commit is contained in:
@@ -103,9 +103,14 @@ class WithPLLSelectorDividerClockGenerator extends OverrideLazyIOBinder({
|
|||||||
|
|
||||||
// For a real chip you should replace this ClockSourceAtFreqFromPlusArg
|
// For a real chip you should replace this ClockSourceAtFreqFromPlusArg
|
||||||
// with a blackbox of whatever PLL is being integrated
|
// with a blackbox of whatever PLL is being integrated
|
||||||
val fakeClockSource = Module(new ClockSourceAtFreqFromPlusArg("pll_freq_mhz"))
|
val fake_pll = Module(new ClockSourceAtFreqFromPlusArg("pll_freq_mhz"))
|
||||||
fakeClockSource.io.power := pllCtrlSink.in(0)._1.power
|
fake_pll.io.power := pllCtrlSink.in(0)._1.power
|
||||||
fakeClockSource.io.gate := pllCtrlSink.in(0)._1.gate
|
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)
|
(Seq(clock_io, reset_io), clockIOCell ++ resetIOCell)
|
||||||
}
|
}
|
||||||
|
|||||||
44
generators/chipyard/src/main/scala/config/ChipConfigs.scala
Normal file
44
generators/chipyard/src/main/scala/config/ChipConfigs.scala
Normal 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)
|
||||||
|
|
||||||
143
generators/chipyard/src/main/scala/example/FlatChipTop.scala
Normal file
143
generators/chipyard/src/main/scala/example/FlatChipTop.scala
Normal 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))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user