//See LICENSE for license details. package firesim.firesim import chisel3._ import chisel3.experimental.{DataMirror, Direction} import chisel3.util.experimental.BoringUtils import org.chipsalliance.cde.config.{Field, Config, Parameters} import freechips.rocketchip.diplomacy.{LazyModule} import freechips.rocketchip.devices.debug.{Debug, HasPeripheryDebug, ExportDebug, DMI} import freechips.rocketchip.amba.axi4.{AXI4Bundle} import freechips.rocketchip.subsystem._ import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters} import freechips.rocketchip.util.{ResetCatchAndSync} import sifive.blocks.devices.uart._ import testchipip.serdes.{ExternalSyncPhitIO} import testchipip.tsi.{SerialRAM} import icenet.{CanHavePeripheryIceNIC, SimNetwork, NicLoopback, NICKey, NICIOvonly} import junctions.{NastiKey, NastiParameters} import midas.models.{FASEDBridge, AXI4EdgeSummary, CompleteConfig} import firesim.bridges._ import firesim.configs.MemModelKey import tracegen.{TraceGenSystemModuleImp} import cva6.CVA6Tile import barstools.iocell.chisel._ import chipyard.iobinders._ import chipyard._ import chipyard.harness._ object MainMemoryConsts { val regionNamePrefix = "MainMemory" def globalName(chipId: Int) = s"${regionNamePrefix}_$chipId" } trait Unsupported { require(false, "We do not support this IOCell type") } class FireSimAnalogIOCell extends RawModule with AnalogIOCell with Unsupported { val io = IO(new AnalogIOCellBundle) } class FireSimDigitalGPIOCell extends RawModule with DigitalGPIOCell with Unsupported { val io = IO(new DigitalGPIOCellBundle) } class FireSimDigitalInIOCell extends RawModule with DigitalInIOCell { val io = IO(new DigitalInIOCellBundle) io.i := io.pad } class FireSimDigitalOutIOCell extends RawModule with DigitalOutIOCell { val io = IO(new DigitalOutIOCellBundle) io.pad := io.o } case class FireSimIOCellParams() extends IOCellTypeParams { def analog() = Module(new FireSimAnalogIOCell) def gpio() = Module(new FireSimDigitalGPIOCell) def input() = Module(new FireSimDigitalInIOCell) def output() = Module(new FireSimDigitalOutIOCell) } class WithFireSimIOCellModels extends Config((site, here, up) => { case IOCellKey => FireSimIOCellParams() }) class WithTSIBridgeAndHarnessRAMOverSerialTL extends HarnessBinder({ case (th: FireSim, port: SerialTLPort, chipId: Int) => { port.io match { case io: ExternalSyncPhitIO => { io.clock_in := th.harnessBinderClock val ram = Module(LazyModule(new SerialRAM(port.serdesser, port.params)(port.serdesser.p)).module) ram.io.ser.in <> io.out io.in <> ram.io.ser.out // This assumes that: // If ExtMem for the target is defined, then FASED bridge will be attached // If FASED bridge is attached, loadmem widget is present val hasMainMemory = th.chipParameters(chipId)(ExtMem).isDefined val mainMemoryName = Option.when(hasMainMemory)(MainMemoryConsts.globalName(chipId)) TSIBridge(th.harnessBinderClock, ram.io.tsi.get, mainMemoryName, th.harnessBinderReset.asBool)(th.p) } } } }) class WithNICBridge extends HarnessBinder({ case (th: FireSim, port: NICPort, chipId: Int) => { NICBridge(port.io.clock, port.io.bits)(th.p) } }) class WithUARTBridge extends HarnessBinder({ case (th: FireSim, port: UARTPort, chipId: Int) => val uartSyncClock = th.harnessClockInstantiator.requestClockMHz("uart_clock", port.freqMHz) UARTBridge(uartSyncClock, port.io, th.harnessBinderReset.asBool, port.freqMHz)(th.p) }) class WithBlockDeviceBridge extends HarnessBinder({ case (th: FireSim, port: BlockDevicePort, chipId: Int) => { BlockDevBridge(port.io.clock, port.io.bits, th.harnessBinderReset.asBool) } }) class WithFASEDBridge extends HarnessBinder({ case (th: FireSim, port: AXI4MemPort, chipId: Int) => { val nastiKey = NastiParameters(port.io.bits.r.bits.data.getWidth, port.io.bits.ar.bits.addr.getWidth, port.io.bits.ar.bits.id.getWidth) FASEDBridge(port.io.clock, port.io.bits, th.harnessBinderReset.asBool, CompleteConfig(th.p(firesim.configs.MemModelKey), nastiKey, Some(AXI4EdgeSummary(port.edge)), Some(MainMemoryConsts.globalName(chipId))))(th.p) } }) class WithTracerVBridge extends HarnessBinder({ case (th: FireSim, port: TracePort, chipId: Int) => { port.io.traces.map(tileTrace => TracerVBridge(tileTrace)(th.p)) } }) class WithCospikeBridge extends HarnessBinder({ case (th: FireSim, port: TracePort, chipId: Int) => { port.io.traces.zipWithIndex.map(t => CospikeBridge(t._1, t._2, port.cosimCfg)) } }) class WithSuccessBridge extends HarnessBinder({ case (th: FireSim, port: SuccessPort, chipId: Int) => { GroundTestBridge(th.harnessBinderClock, port.io)(th.p) } }) // Shorthand to register all of the provided bridges above class WithDefaultFireSimBridges extends Config( new WithTSIBridgeAndHarnessRAMOverSerialTL ++ new WithNICBridge ++ new WithUARTBridge ++ new WithBlockDeviceBridge ++ new WithFASEDBridge ++ new WithFireSimMultiCycleRegfile ++ new WithFireSimFAME5 ++ new WithTracerVBridge ++ new WithFireSimIOCellModels ) // Shorthand to register all of the provided mmio-only bridges above class WithDefaultMMIOOnlyFireSimBridges extends Config( new WithTSIBridgeAndHarnessRAMOverSerialTL ++ new WithUARTBridge ++ new WithBlockDeviceBridge ++ new WithFASEDBridge ++ new WithFireSimMultiCycleRegfile ++ new WithFireSimFAME5 ++ new WithFireSimIOCellModels )