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
|
||||
// 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)
|
||||
}
|
||||
|
||||
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