package chipyard

import org.chipsalliance.cde.config.{Config}

// ---------------------
// BOOM V3 Configs
// Performant, stable baseline
// ---------------------

class SmallBoomV3Config extends Config(
  new boom.v3.common.WithNSmallBooms(1) ++                          // small boom config
  new chipyard.config.AbstractConfig)

class MediumBoomV3Config extends Config(
  new boom.v3.common.WithNMediumBooms(1) ++                         // medium boom config
  new chipyard.config.AbstractConfig)

class LargeBoomV3Config extends Config(
  new boom.v3.common.WithNLargeBooms(1) ++                          // large boom config
  new chipyard.config.WithSystemBusWidth(128) ++
  new chipyard.config.AbstractConfig)

class MegaBoomV3Config extends Config(
  new boom.v3.common.WithNMegaBooms(1) ++                           // mega boom config
  new chipyard.config.WithSystemBusWidth(128) ++
  new chipyard.config.AbstractConfig)

class DualSmallBoomV3Config extends Config(
  new boom.v3.common.WithNSmallBooms(2) ++                          // 2 boom cores
  new chipyard.config.AbstractConfig)

class Cloned64MegaBoomV3Config extends Config(
  new boom.v3.common.WithCloneBoomTiles(63, 0) ++
  new boom.v3.common.WithNMegaBooms(1) ++                           // mega boom config
  new chipyard.config.WithSystemBusWidth(128) ++
  new chipyard.config.AbstractConfig)

class LoopbackNICLargeBoomV3Config extends Config(
  new chipyard.harness.WithLoopbackNIC ++                        // drive NIC IOs with loopback
  new icenet.WithIceNIC ++                                       // build a NIC
  new boom.v3.common.WithNLargeBooms(1) ++
  new chipyard.config.WithSystemBusWidth(128) ++
  new chipyard.config.AbstractConfig)

class MediumBoomV3CosimConfig extends Config(
  new chipyard.harness.WithCospike ++                            // attach spike-cosim
  new chipyard.config.WithTraceIO ++                             // enable the traceio
  new boom.v3.common.WithNMediumBooms(1) ++
  new chipyard.config.AbstractConfig)

class dmiCheckpointingMediumBoomV3Config extends Config(
  new chipyard.config.WithNPMPs(0) ++                            // remove PMPs (reduce non-core arch state)
  new chipyard.harness.WithSerialTLTiedOff ++                    // don't attach anything to serial-tl
  new chipyard.config.WithDMIDTM ++                              // have debug module expose a clocked DMI port
  new boom.v3.common.WithNMediumBooms(1) ++
  new chipyard.config.AbstractConfig)

class dmiMediumBoomV3CosimConfig extends Config(
  new chipyard.harness.WithCospike ++                            // attach spike-cosim
  new chipyard.config.WithTraceIO ++                             // enable the traceio
  new chipyard.harness.WithSerialTLTiedOff ++                    // don't attach anythint to serial-tl
  new chipyard.config.WithDMIDTM ++                              // have debug module expose a clocked DMI port
  new boom.v3.common.WithNMediumBooms(1) ++
  new chipyard.config.AbstractConfig)

class SimBlockDeviceMegaBoomV3Config extends Config(
  new chipyard.harness.WithSimBlockDevice ++                     // drive block-device IOs with SimBlockDevice
  new testchipip.iceblk.WithBlockDevice ++                       // add block-device module to peripherybus
  new boom.v3.common.WithNMegaBooms(1) ++                        // mega boom config
  new chipyard.config.WithSystemBusWidth(128) ++
  new chipyard.config.AbstractConfig)

// ---------------------
// BOOM V4 Configs
// Less stable and performant, but with more advanced micro-architecture
// Use for PD exploration
// ---------------------

class SmallBoomV4Config extends Config(
  new boom.v4.common.WithNSmallBooms(1) ++                          // small boom config
  new chipyard.config.AbstractConfig)

class MediumBoomV4Config extends Config(
  new boom.v4.common.WithNMediumBooms(1) ++                         // medium boom config
  new chipyard.config.AbstractConfig)

class LargeBoomV4Config extends Config(
  new boom.v4.common.WithNLargeBooms(1) ++                          // large boom config
  new chipyard.config.WithSystemBusWidth(128) ++
  new chipyard.config.AbstractConfig)

  new chipyard.config.AbstractConfig)

class Cloned64MegaBoomV4Config extends Config(
  new boom.v4.common.WithCloneBoomTiles(63, 0) ++
  new boom.v4.common.WithNMegaBooms(1) ++                           // mega boom config
  new chipyard.config.WithSystemBusWidth(128) ++
  new chipyard.config.AbstractConfig)

class MediumBoomV4CosimConfig extends Config(
  new chipyard.harness.WithCospike ++                            // attach spike-cosim
  new chipyard.config.WithTraceIO ++                             // enable the traceio
  new boom.v4.common.WithNMediumBooms(1) ++
  new chipyard.config.AbstractConfig)

class dmiCheckpointingMediumBoomV4Config extends Config(
  new chipyard.config.WithNPMPs(0) ++                            // remove PMPs (reduce non-core arch state)
  new chipyard.harness.WithSerialTLTiedOff ++                    // don't attach anything to serial-tl
  new chipyard.config.WithDMIDTM ++                              // have debug module expose a clocked DMI port
  new boom.v4.common.WithNMediumBooms(1) ++
  new chipyard.config.AbstractConfig)

class dmiMediumBoomV4CosimConfig extends Config(
  new chipyard.harness.WithCospike ++                            // attach spike-cosim
  new chipyard.config.WithTraceIO ++                             // enable the traceio
  new chipyard.harness.WithSerialTLTiedOff ++                    // don't attach anythint to serial-tl
  new chipyard.config.WithDMIDTM ++                              // have debug module expose a clocked DMI port
  new boom.v4.common.WithNMediumBooms(1) ++
  new chipyard.config.AbstractConfig)

class SimBlockDeviceMegaBoomV4Config extends Config(
  new chipyard.harness.WithSimBlockDevice ++                     // drive block-device IOs with SimBlockDevice
  new testchipip.iceblk.WithBlockDevice ++                       // add block-device module to peripherybus
  new boom.v4.common.WithNMegaBooms(1) ++                        // mega boom config
  new chipyard.config.WithSystemBusWidth(128) ++
  new chipyard.config.AbstractConfig)

class MegaBoomV4Config extends Config(
  new boom.v4.common.WithNMegaBooms(1) ++                           // mega boom config
  new chipyard.config.WithSystemBusWidth(128) ++
  new chipyard.config.AbstractConfig)


package chipyard.config

import chisel3._

import org.chipsalliance.cde.config.{Field, Parameters, Config}
import freechips.rocketchip.tile._
import freechips.rocketchip.diplomacy._

import chipyard.{TestSuitesKey, TestSuiteHelper}

/**
 * Map from a tileId to a particular RoCC accelerator
 */

/**
 * Config fragment to enable different RoCCs based on the tileId
 */
class WithMultiRoCC extends Config((site, here, up) => {
  case BuildRoCC => site(MultiRoCCKey).getOrElse(site(TileKey).tileId, Nil)
})

/**
 * Assigns what was previously in the BuildRoCC key to specific harts with MultiRoCCKey
 * Must be paired with WithMultiRoCC
 */
class WithMultiRoCCFromBuildRoCC(harts: Int*) extends Config((site, here, up) => {
  case BuildRoCC => Nil
  case MultiRoCCKey => up(MultiRoCCKey, site) ++ harts.distinct.map { i =>
    (i -> up(BuildRoCC, site))
  }
})

class WithAccumulatorRoCC(op: OpcodeSet = OpcodeSet.custom1) extends Config((site, here, up) => {
  case BuildRoCC => up(BuildRoCC) ++ Seq((p: Parameters) => {
    val accumulator = LazyModule(new AccumulatorExample(op, n = 4)(p))
    accumulator
  })
})

class WithCharacterCountRoCC(op: OpcodeSet = OpcodeSet.custom2) extends Config((site, here, up) => {
  case BuildRoCC => up(BuildRoCC) ++ Seq((p: Parameters) => {
    val counter = LazyModule(new CharacterCountExample(op)(p))
    counter
  })
})

case object MultiRoCCKey extends Field[Map[Int, Seq[Parameters => LazyRoCC]]](Map.empty[Int, Seq[Parameters => LazyRoCC]])


package chipyard.example

import chisel3._

import org.chipsalliance.cde.config._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.util.{DontTouch}

import chipyard._
import chipyard.harness.{BuildTop}

class EmptyChipTop(implicit p: Parameters) extends LazyModule {
  override lazy val module = new Impl

class WithEmptyChipTop extends Config((site, here, up) => {
  case BuildTop => (p: Parameters) => new EmptyChipTop()(p)
})

  class Impl extends LazyRawModuleImp(this) with DontTouch {
    // Your custom non-rocketchip-soc stuff here
  }


package chipyard.example

import chisel3._
import chisel3.util._

import org.chipsalliance.cde.config._
import freechips.rocketchip.subsystem._
import freechips.rocketchip.devices.tilelink._
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.rocket._
import freechips.rocketchip.subsystem.{RocketCrossingParams}
import freechips.rocketchip.tilelink._
import freechips.rocketchip.interrupts._
import freechips.rocketchip.util._
import freechips.rocketchip.tile._
import freechips.rocketchip.amba.axi4._
import freechips.rocketchip.prci._

// Example parameter class copied from CVA6, not included in documentation but for compile check only
// If you are here for documentation, DO NOT copy MyCoreParams and MyTileParams directly - always figure
// out what parameters you need before you write the parameter class
case class MyCoreParams(
  bootFreqHz: BigInt = BigInt(1700000000),
  rasEntries: Int = 4,
  btbEntries: Int = 16,
  bhtEntries: Int = 16,
  enableToFromHostCaching: Boolean = false,
) extends CoreParams {
  val xLen: Int = 32
  val pgLevels: Int = 2
  val useVM: Boolean = true
  val useHypervisor: Boolean = false
  val useUser: Boolean = true
  val useSupervisor: Boolean = false
  val useDebug: Boolean = true
  val useAtomics: Boolean = true
  val useAtomicsOnlyForIO: Boolean = false // copied from Rocket
  val useCompressed: Boolean = true
  override val useVector: Boolean = false
  val useSCIE: Boolean = false
  val useRVE: Boolean = false
  val mulDiv: Option[MulDivParams] = Some(MulDivParams()) // copied from Rocket
  val fpu: Option[FPUParams] = Some(FPUParams()) // copied fma latencies from Rocket
  val nLocalInterrupts: Int = 0
  val useNMI: Boolean = false
  val nPTECacheEntries: Int = 0 // TODO: Check
  val nPMPs: Int = 0 // TODO: Check
  val pmpGranularity: Int = 4 // copied from Rocket
  val nBreakpoints: Int = 0 // TODO: Check
  val useBPWatch: Boolean = false
  val mcontextWidth: Int = 0
  val scontextWidth: Int = 0
  val nPerfCounters: Int = 29
  val haveBasicCounters: Boolean = true
  val haveFSDirty: Boolean = false
  val misaWritable: Boolean = false
  val haveCFlush: Boolean = false
  val nL2TLBEntries: Int = 512 // copied from Rocket
  val nL2TLBWays: Int = 1
  val mtvecInit: Option[BigInt] = Some(BigInt(0)) // copied from Rocket
  val mtvecWritable: Boolean = true // copied from Rocket
  val instBits: Int = if (useCompressed) 16 else 32
  val lrscCycles: Int = 80 // copied from Rocket
  val decodeWidth: Int = 1 // TODO: Check
  val fetchWidth: Int = 1 // TODO: Check
  val retireWidth: Int = 2
  val traceHasWdata: Boolean = false
  val useConditionalZero = false
  val useZba: Boolean = false
  val useZbb: Boolean = false
  val useZbs: Boolean = false
}

// DOC include start: CanAttachTile
case class MyTileAttachParams(
  tileParams: MyTileParams,
  crossingParams: RocketCrossingParams
) extends CanAttachTile {
  type TileType = MyTile
  val lookup = PriorityMuxHartIdFromSeq(Seq(tileParams))
}
// DOC include end: CanAttachTile

case class MyTileParams(
  name: Option[String] = Some("my_tile"),
  tileId: Int = 0,
  trace: Boolean = false,
  val core: MyCoreParams = MyCoreParams()
) extends InstantiableTileParams[MyTile]
{
  val beuAddr: Option[BigInt] = None
  val blockerCtrlAddr: Option[BigInt] = None
  val btb: Option[BTBParams] = Some(BTBParams())
  val boundaryBuffers: Boolean = false
  val dcache: Option[DCacheParams] = Some(DCacheParams())
  val icache: Option[ICacheParams] = Some(ICacheParams())
  val clockSinkParams: ClockSinkParameters = ClockSinkParameters()
  def instantiate(crossing: HierarchicalElementCrossingParamsLike, lookup: LookupByHartIdImpl)(implicit p: Parameters): MyTile = {
    new MyTile(this, crossing, lookup)
  }
  val baseName = name.getOrElse("my_tile")
  val uniqueName = s"${baseName}_$tileId"
}

// DOC include start: Tile class
class MyTile(
  val myParams: MyTileParams,
  crossing: ClockCrossingType,
  lookup: LookupByHartIdImpl,
  q: Parameters)
  extends BaseTile(myParams, crossing, lookup, q)
  with SinksExternalInterrupts
  with SourcesExternalNotifications
{

  // Private constructor ensures altered LazyModule.p is used implicitly
  def this(params: MyTileParams, crossing: HierarchicalElementCrossingParamsLike, lookup: LookupByHartIdImpl)(implicit p: Parameters) =
    this(params, crossing.crossingType, lookup, p)

  // Require TileLink nodes
  val intOutwardNode = None
  val masterNode = visibilityNode
  val slaveNode = TLIdentityNode()

  // Implementation class (See below)
  override lazy val module = new MyTileModuleImp(this)

  // Required entry of CPU device in the device tree for interrupt purpose
  val cpuDevice: SimpleDevice = new SimpleDevice("cpu", Seq("my-organization,my-cpu", "riscv")) {

    override def describe(resources: ResourceBindings): Description = {
      val Description(name, mapping) = super.describe(resources)
      Description(name, mapping ++
                        cpuProperties ++
                        nextLevelCacheProperty ++
                        tileProperties)
    }
  }

  ResourceBinding {
    Resource(cpuDevice, "reg").bind(ResourceAddress(tileId))
  }

  // TODO: Create TileLink nodes and connections here.
  // DOC include end: Tile class

  // DOC include start: AXI4 node
  // # of bits used in TileLink ID for master node. 4 bits can support 16 master nodes, but you can have a longer ID if you need more.
  val idBits = 4
  val memAXI4Node = AXI4MasterNode(
    Seq(AXI4MasterPortParameters(
      masters = Seq(AXI4MasterParameters(
        name = "myPortName",
        id = IdRange(0, 1 << idBits))))))
  val memoryTap = TLIdentityNode() // Every bus connection should have their own tap node
  // DOC include end: AXI4 node

  // DOC include start: AXI4 convert
  (tlMasterXbar.node  // tlMasterXbar is the bus crossbar to be used when this core / tile is acting as a master; otherwise, use tlSlaveXBar
    := memoryTap
    := TLBuffer()
    := TLFIFOFixer(TLFIFOFixer.all) // fix FIFO ordering
    := TLWidthWidget(masterPortBeatBytes) // reduce size of TL
    := AXI4ToTL() // convert to TL
    := AXI4UserYanker(Some(2)) // remove user field on AXI interface. need but in reality user intf. not needed
    := AXI4Fragmenter() // deal with multi-beat xacts
    := memAXI4Node) // The custom node, see below
  // DOC include end: AXI4 convert

}

// DOC include start: Implementation class
class MyTileModuleImp(outer: MyTile) extends BaseTileModuleImp(outer){
  // TODO: Create the top module of the core and connect it with the ports in "outer"

  // If your core is in Verilog (assume your blackbox is called "MyCoreBlackbox"), instantiate it here like
  //   val core = Module(new MyCoreBlackbox(params...))
  // (as described in the blackbox tutorial) and connect appropriate signals. See the blackbox tutorial
  // (link on the top of the page) for more info.
  // You can look at https://github.com/ucb-bar/cva6-wrapper/blob/master/src/main/scala/CVA6Tile.scala
  // for a Verilog example.

  // If your core is in Chisel, you can simply instantiate the top module here like other Chisel module
  // and connect appropriate signal. You can even implement this class as your top module.
  // See https://github.com/riscv-boom/riscv-boom/blob/master/src/main/scala/common/tile.scala and
  // https://github.com/chipsalliance/rocket-chip/blob/master/src/main/scala/tile/RocketTile.scala for
  // Chisel example.

  // DOC include end: Implementation class

  // DOC include start: connect interrupt
  // For example, our core support debug interrupt and machine-level interrupt, and suppose the following two signals
  // are the interrupt inputs to the core. (DO NOT COPY this code - if your core treat each type of interrupt differently,
  // you need to connect them to different interrupt ports of your core)
  val debug_i = Wire(Bool())
  val mtip_i = Wire(Bool())
  // We create a bundle here and decode the interrupt.
  val int_bundle = new TileInterrupts()
  outer.decodeCoreInterrupts(int_bundle)
  debug_i := int_bundle.debug
  mtip_i := int_bundle.meip & int_bundle.msip & int_bundle.mtip
  // DOC include end: connect interrupt

  // DOC include start: raise interrupt
  // This is a demo. You should call these function according to your core
  // Suppose that the following signal is from the decoder indicating a WFI instruction is received.
  val wfi_o = Wire(Bool())
  outer.reportWFI(Some(wfi_o))
  // Suppose that the following signal indicate an unreconverable hardware error.
  val halt_o = Wire(Bool())
  outer.reportHalt(Some(halt_o))
  // Suppose that our core never stall for a long time / stop retiring. Use None to indicate that this interrupt never fires.
  outer.reportCease(None)
  // DOC include end: raise interrupt

  // DOC include start: AXI4 connect
  outer.memAXI4Node.out foreach { case (out, edgeOut) =>
    // Connect your module IO port to "out"
    // The type of "out" here is AXI4Bundle, which is defined in generators/rocket-chip/src/main/scala/amba/axi4/Bundles.scala
    // Please refer to this file for the definition of the ports.
    // If you are using APB, check APBBundle in generators/rocket-chip/src/main/scala/amba/apb/Bundles.scala
    // If you are using AHB, check AHBSlaveBundle or AHBMasterBundle in generators/rocket-chip/src/main/scala/amba/ahb/Bundles.scala
    // (choose one depends on the type of AHB node you create)
    // If you are using AXIS, check AXISBundle and AXISBundleBits in generators/rocket-chip/src/main/scala/amba/axis/Bundles.scala
  }
  // DOC include end: AXI4 connect

}

// DOC include start: Config fragment
class WithNMyCores(n: Int = 1) extends Config((site, here, up) => {
  case TilesLocated(InSubsystem) => {
    // Calculate the next available hart ID (since hart ID cannot be duplicated)
    val prev = up(TilesLocated(InSubsystem), site)
    val idOffset = up(NumTiles)
    // Create TileAttachParams for every core to be instantiated
    (0 until n).map { i =>
      MyTileAttachParams(
        tileParams = MyTileParams(tileId = i + idOffset),
        crossingParams = RocketCrossingParams()
      )
    } ++ prev
  }
  // Configurate # of bytes in one memory / IO transaction. For RV64, one load/store instruction can transfer 8 bytes at most.
  case SystemBusKey => up(SystemBusKey, site).copy(beatBytes = 8)
  case NumTiles => up(NumTiles) + n
})
// DOC include end: Config fragment

override def parent = Some(ResourceAnchors.cpus)


package chipyard.example

import chisel3._
import chisel3.util._
import dspblocks._
import dsptools.numbers._
import freechips.rocketchip.amba.axi4stream._
import org.chipsalliance.cde.config.Parameters
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.regmapper._
import freechips.rocketchip.tilelink._
import freechips.rocketchip.subsystem._

/**
  * The memory interface writes entries into the queue.
  * They stream out the streaming interface
  * @param depth number of entries in the queue
  * @param streamParameters parameters for the stream node
  * @param p
  */
abstract class WriteQueue[D, U, E, O, B <: Data]
(
  val depth: Int,
  val streamParameters: AXI4StreamMasterParameters = AXI4StreamMasterParameters()
)(implicit p: Parameters) extends DspBlock[D, U, E, O, B] with HasCSR {
  // stream node, output only
  val streamNode = AXI4StreamMasterNode(streamParameters)

  lazy val module = new LazyModuleImp(this) {
    require(streamNode.out.length == 1)

    // get the output bundle associated with the AXI4Stream node
    val out = streamNode.out.head._1
    // width (in bits) of the output interface
    val width = out.params.n * 8
    // instantiate a queue
    val queue = Module(new Queue(UInt(out.params.dataBits.W), depth))
    // connect queue output to streaming output
    out.valid := queue.io.deq.valid
    out.bits.data := queue.io.deq.bits
    // don't use last
    out.bits.last := false.B
    queue.io.deq.ready := out.ready

    regmap(
      // each write adds an entry to the queue
      0x0 -> Seq(RegField.w(width, queue.io.enq)),
      // read the number of entries in the queue
      (width+7)/8 -> Seq(RegField.r(width, queue.io.count)),
    )
  }
}

/**
  * TLDspBlock specialization of WriteQueue
  * @param depth number of entries in the queue
  * @param csrAddress address range for peripheral
  * @param beatBytes beatBytes of TL interface
  * @param p
  */
class TLWriteQueue (depth: Int, csrAddress: AddressSet, beatBytes: Int)
(implicit p: Parameters) extends WriteQueue[
  TLClientPortParameters, TLManagerPortParameters, TLEdgeOut, TLEdgeIn, TLBundle
](depth) with TLHasCSR {
  val devname = "tlQueueIn"
  val devcompat = Seq("ucb-art", "dsptools")
  val device = new SimpleDevice(devname, devcompat) {
    override def describe(resources: ResourceBindings): Description = {
      val Description(name, mapping) = super.describe(resources)
      Description(name, mapping)
    }
  }
  // make diplomatic TL node for regmap
  override val mem = Some(TLRegisterNode(address = Seq(csrAddress), device = device, beatBytes = beatBytes))
}

object TLWriteQueue {
  def apply(
    depth: Int = 8,
    csrAddress: AddressSet = AddressSet(0x2000, 0xff),
    beatBytes: Int = 8,
  )(implicit p: Parameters) = {
    val writeQueue = LazyModule(new TLWriteQueue(depth = depth, csrAddress = csrAddress, beatBytes = beatBytes))
    writeQueue
  }
}

/**
  * The streaming interface adds elements into the queue.
  * The memory interface can read elements out of the queue.
  * @param depth number of entries in the queue
  * @param streamParameters parameters for the stream node
  * @param p
  */
abstract class ReadQueue[D, U, E, O, B <: Data]
(
  val depth: Int,
  val streamParameters: AXI4StreamSlaveParameters = AXI4StreamSlaveParameters()
)(implicit p: Parameters) extends DspBlock[D, U, E, O, B] with HasCSR {
  val streamNode = AXI4StreamSlaveNode(streamParameters)

  lazy val module = new LazyModuleImp(this) {
    require(streamNode.in.length == 1)

    // get the input associated with the stream node
    val in = streamNode.in.head._1
    // make a Decoupled[UInt] that RegReadFn can do something with
    val out = Wire(Decoupled(UInt()))
    // get width of streaming input interface
    val width = in.params.n * 8
    // instantiate a queue
    val queue = Module(new Queue(UInt(in.params.dataBits.W), depth))
    // connect input to the streaming interface
    queue.io.enq.valid := in.valid
    queue.io.enq.bits := in.bits.data
    in.ready := queue.io.enq.ready
    // connect output to wire
    out.valid := queue.io.deq.valid
    out.bits := queue.io.deq.bits
    queue.io.deq.ready := out.ready

    regmap(
      // map the output of the queue
      0x0         -> Seq(RegField.r(width, RegReadFn(out))),
      // read the number of elements in the queue
      (width+7)/8 -> Seq(RegField.r(width, queue.io.count)),
    )
  }
}

/**
  * TLDspBlock specialization of ReadQueue
  * @param depth number of entries in the queue
  * @param csrAddress address range
  * @param beatBytes beatBytes of TL interface
  * @param p
  */
class TLReadQueue( depth: Int, csrAddress: AddressSet, beatBytes: Int)
(implicit p: Parameters) extends ReadQueue[
  TLClientPortParameters, TLManagerPortParameters, TLEdgeOut, TLEdgeIn, TLBundle
](depth) with TLHasCSR {
  val devname = "tlQueueOut"
  val devcompat = Seq("ucb-art", "dsptools")
  val device = new SimpleDevice(devname, devcompat) {

}

object TLReadQueue {
  def apply(
    depth: Int = 8,
    csrAddress: AddressSet = AddressSet(0x2100, 0xff),
    beatBytes: Int = 8)(implicit p: Parameters) = {
    val readQueue = LazyModule(new TLReadQueue(depth = depth, csrAddress = csrAddress, beatBytes = beatBytes))
    readQueue
  }
}


package chipyard.harness

import chisel3._

import scala.collection.mutable.{ArrayBuffer, LinkedHashMap}
import freechips.rocketchip.diplomacy.{LazyModule}
import org.chipsalliance.cde.config.{Field, Parameters, Config}
import freechips.rocketchip.util.{ResetCatchAndSync, DontTouch}
import freechips.rocketchip.prci.{ClockBundle, ClockBundleParameters, ClockSinkParameters, ClockParameters}
import chipyard.stage.phases.TargetDirKey

import chipyard.harness.{ApplyHarnessBinders, HarnessBinders}
import chipyard.iobinders.HasChipyardPorts
import chipyard.clocking.{SimplePllConfiguration, ClockDividerN}
import chipyard.{ChipTop}

// -------------------------------
// Chipyard Test Harness
// -------------------------------

case object MultiChipNChips extends Field[Option[Int]](None) // None means ignore MultiChipParams
case class MultiChipParameters(chipId: Int) extends Field[Parameters]
case object BuildTop extends Field[Parameters => LazyModule]((p: Parameters) => new ChipTop()(p))
case object HarnessClockInstantiatorKey extends Field[() => HarnessClockInstantiator]()

case object MultiChipIdx extends Field[Int](0)
case object DontTouchChipTopPorts extends Field[Boolean](true)

class WithMultiChip(id: Int, p: Parameters) extends Config((site, here, up) => {
  case MultiChipParameters(`id`) => p
  case MultiChipNChips => Some(up(MultiChipNChips).getOrElse(0) max (id + 1))
})

class WithHomogeneousMultiChip(n: Int, p: Parameters, idStart: Int = 0) extends Config((site, here, up) => {
  case MultiChipParameters(id) => if (id >= idStart && id < idStart + n) p else up(MultiChipParameters(id))
  case MultiChipNChips => Some(up(MultiChipNChips).getOrElse(0) max (idStart + n))
})

class WithHarnessBinderClockFreqMHz(freqMHz: Double) extends Config((site, here, up) => {
  case HarnessBinderClockFrequencyKey => freqMHz
})

class WithDontTouchChipTopPorts(b: Boolean = true) extends Config((site, here, up) => {
  case DontTouchChipTopPorts => b
})

// A TestHarness mixing this in will
// - use the HarnessClockInstantiator clock provide
trait HasHarnessInstantiators {
  implicit val p: Parameters
  // clock/reset of the chiptop reference clock (can be different than the implicit harness clock/reset)
  private val harnessBinderClockFreq: Double = p(HarnessBinderClockFrequencyKey)
  def getHarnessBinderClockFreqHz: Double = harnessBinderClockFreq * 1000000
  def getHarnessBinderClockFreqMHz: Double = harnessBinderClockFreq

  // buildtopClock takes the refClockFreq, and drives the harnessbinders
  val harnessBinderClock = Wire(Clock())
  val harnessBinderReset = Wire(Reset())

  // classes which inherit this trait should provide the below definitions
  def referenceClockFreqMHz: Double
  def referenceClock: Clock
  def referenceReset: Reset
  def success: Bool

  // This can be accessed to get new clocks from the harness
  val harnessClockInstantiator = p(HarnessClockInstantiatorKey)()

  val supportsMultiChip: Boolean = false

  val chipParameters = p(MultiChipNChips) match {
    case Some(n) => (0 until n).map { i => p(MultiChipParameters(i)).alterPartial {
      case TargetDirKey => p(TargetDirKey) // hacky fix
      case MultiChipIdx => i
    }}
    case None => Seq(p)
  }

  // This shold be called last to build the ChipTops
  def instantiateChipTops(): Seq[LazyModule] = {
    require(p(MultiChipNChips).isEmpty || supportsMultiChip,
      s"Selected Harness does not support multi-chip")

    val lazyDuts = chipParameters.zipWithIndex.map { case (q,i) =>
      LazyModule(q(BuildTop)(q)).suggestName(s"chiptop$i")
    }
    val duts = lazyDuts.map(l => Module(l.module))

    withClockAndReset (harnessBinderClock, harnessBinderReset) {
      lazyDuts.zipWithIndex.foreach {
        case (d: HasChipyardPorts, i: Int) => {
          ApplyHarnessBinders(this, d.ports, i)(chipParameters(i))
        }
        case _ =>
      }
      ApplyMultiHarnessBinders(this, lazyDuts)
    }

    if (p(DontTouchChipTopPorts)) {
      duts.map(_ match {
        case d: DontTouch => d.dontTouchPorts()
        case _ =>
      })
    }

    val harnessBinderClk = harnessClockInstantiator.requestClockMHz("harnessbinder_clock", getHarnessBinderClockFreqMHz)
    println(s"Harness binder clock is $harnessBinderClockFreq")
    harnessBinderClock := harnessBinderClk
    harnessBinderReset := ResetCatchAndSync(harnessBinderClk, referenceReset.asBool)

    harnessClockInstantiator.instantiateHarnessClocks(referenceClock, referenceClockFreqMHz)

    lazyDuts
  }
}

case object HarnessBinderClockFrequencyKey extends Field[Double](100.0) // MHz


package chipyard.unittest

import org.chipsalliance.cde.config.Parameters
import freechips.rocketchip.util.{ElaborationArtefacts, PlusArgArtefacts}

class UnitTestSuite(implicit p: Parameters) extends freechips.rocketchip.unittest.UnitTestSuite {
  ElaborationArtefacts.add("plusArgs", PlusArgArtefacts.serialize_cHeader)
}


//See LICENSE for license details.
package chipyard.clocking

import freechips.rocketchip.prci._

class SimplePllConfigurationSpec extends org.scalatest.flatspec.AnyFlatSpec {

    def genConf(freqMHz: Iterable[Double]): SimplePllConfiguration = new SimplePllConfiguration(
      "testPLL",
      freqMHz.map({ f => ClockSinkParameters(
        name = Some(s"desiredFreq_$f"),
        take = Some(ClockParameters(f))) }).toSeq,
      maximumAllowableFreqMHz = 16000.0)

    def trySuccessfulConf(requestedFreqs: Seq[Double], expected: Double): Unit = {
      val freqStr = requestedFreqs.mkString(", ")

        val conf = genConf(requestedFreqs)
        conf.emitSummaries
        assert(expected == conf.referenceFreqMHz)
      }
    }

    trySuccessfulConf(Seq(3200.0, 1600.0, 1000.0, 100.0), 16000.0)
    trySuccessfulConf(Seq(3200.0, 1600.0), 3200.0)
    trySuccessfulConf(Seq(3200.0, 1066.7), 3200.0)
    trySuccessfulConf(Seq(100, 50, 6.67), 100)
    trySuccessfulConf(Seq(1, 2, 3, 5, 7, 11, 13).map(_ * 10.0), 1560.0)
}

it should s"select a reference of ${expected} MHz for ${freqStr} MHz" in {


// See LICENSE for license details.

package firechip.bridgeinterfaces

import chisel3._

// Note: This file is heavily commented as it serves as a bridge walkthrough
// example in the FireSim docs

// Note: All code in this file must be isolated from target-side generators/classes/etc
// since this is also injected into the midas compiler.

// DOC include start: UART Bridge Target-Side Interface
class UARTPortIO extends Bundle {
  val txd = Output(Bool())
  val rxd = Input(Bool())
}

class UARTBridgeTargetIO extends Bundle {
  val clock = Input(Clock())
  val uart = Flipped(new UARTPortIO)
  // Note this reset is optional and used only to reset target-state modeled
  // in the bridge. This reset is just like any other Bool included in your target
  // interface, simply appears as another Bool in the input token.
  val reset = Input(Bool())
}
// DOC include end: UART Bridge Target-Side Interface

// DOC include start: UART Bridge Constructor Arg
// Out bridge module constructor argument. This captures all of the extra
// metadata we'd like to pass to the host-side BridgeModule. Note, we need to
// use a single case class to do so, even if it is simply to wrap a primitive
// type, as is the case for the div Int.

// DOC include end: UART Bridge Constructor Arg


// See LICENSE for license details

package firechip.bridgestubs

import chisel3._
import chisel3.util._

import org.chipsalliance.cde.config.Parameters

import firesim.lib.bridgeutils._

import firechip.bridgeinterfaces._

// Note: This file is heavily commented as it serves as a bridge walkthrough
// example in the FireSim docs

// DOC include start: UART Bridge Target-Side Module
class UARTBridge(initBaudRate: BigInt, freqMHz: Int)(implicit p: Parameters) extends BlackBox
    with Bridge[HostPortIO[UARTBridgeTargetIO]] {
  // Module portion corresponding to this bridge
  val moduleName = "firechip.goldengateimplementations.UARTBridgeModule"
  // Since we're extending BlackBox this is the port will connect to in our target's RTL
  val io = IO(new UARTBridgeTargetIO)
  // Implement the bridgeIO member of Bridge using HostPort. This indicates that
  // we want to divide io, into a bidirectional token stream with the input
  // token corresponding to all of the inputs of this BlackBox, and the output token consisting of
  // all of the outputs from the BlackBox
  val bridgeIO = HostPort(io)

  // Do some intermediate work to compute our host-side BridgeModule's constructor argument
  val div = (BigInt(freqMHz) * 1000000 / initBaudRate).toInt

  // And then implement the constructorArg member
  val constructorArg = Some(UARTKey(div))

  // Finally, and this is critical, emit the Bridge Annotations -- without
  // this, this BlackBox would appear like any other BlackBox to Golden Gate
  generateAnnotations()
}
// DOC include end: UART Bridge Target-Side Module

// DOC include start: UART Bridge Companion Object
object UARTBridge {
  def apply(clock: Clock, uart: sifive.blocks.devices.uart.UARTPortIO, reset: Bool, freqMHz: Int)(implicit p: Parameters): UARTBridge = {
    val ep = Module(new UARTBridge(uart.c.initBaudRate, freqMHz))
    ep.io.uart.txd := uart.txd
    uart.rxd := ep.io.uart.rxd
    ep.io.clock := clock
    ep.io.reset := reset

// DOC include end: UART Bridge Companion Object


// See LICENSE.SiFive for license details.

package freechips.rocketchip.amba.axi4

import chisel3._
import chisel3.util.{Cat, Queue, UIntToOH, log2Ceil, OHToUInt, Mux1H, IrrevocableIO}

import org.chipsalliance.cde.config.Parameters

import org.chipsalliance.diplomacy.lazymodule.{LazyModule, LazyModuleImp}

import freechips.rocketchip.diplomacy.{AddressDecoder, AddressSet, BufferParams}
import freechips.rocketchip.tilelink.{TLArbiter, TLXbar, TLFilter, TLFuzzer, TLToAXI4, TLRAMModel}
import freechips.rocketchip.unittest.{UnitTest, UnitTestModule}
import freechips.rocketchip.util.BundleField

/**
  * AXI4 Crossbar. It connects multiple AXI4 masters to slaves.
  *
  * @param arbitrationPolicy arbitration policy
  * @param maxFlightPerId maximum inflight transactions per id
  * @param awQueueDepth queue depth for AW channel
  */
class AXI4Xbar(
  arbitrationPolicy: TLArbiter.Policy = TLArbiter.roundRobin,
  maxFlightPerId:    Int = 7,
  awQueueDepth:      Int = 2)(implicit p: Parameters) extends LazyModule
{
  require (maxFlightPerId >= 1)
  require (awQueueDepth >= 1)

  val node = new AXI4NexusNode(
    masterFn  = { seq =>
      seq(0).copy(
        echoFields    = BundleField.union(seq.flatMap(_.echoFields)),
        requestFields = BundleField.union(seq.flatMap(_.requestFields)),
        responseKeys  = seq.flatMap(_.responseKeys).distinct,
        masters = (AXI4Xbar.mapInputIds(seq) zip seq) flatMap { case (range, port) =>
          port.masters map { master => master.copy(id = master.id.shift(range.start)) }
        }
      )
    },
    slaveFn = { seq =>
      seq(0).copy(
        responseFields = BundleField.union(seq.flatMap(_.responseFields)),
        requestKeys    = seq.flatMap(_.requestKeys).distinct,
        minLatency = seq.map(_.minLatency).min,
        slaves = seq.flatMap { port =>
          require (port.beatBytes == seq(0).beatBytes,
            s"Xbar data widths don't match: ${port.slaves.map(_.name)} has ${port.beatBytes}B vs ${seq(0).slaves.map(_.name)} has ${seq(0).beatBytes}B")
          port.slaves
        }
      )
    }
  ){
    override def circuitIdentity = outputs.size == 1 && inputs.size == 1
  }

  lazy val module = new Impl
  class Impl extends LazyModuleImp(this) {
    val (io_in, edgesIn) = node.in.unzip
    val (io_out, edgesOut) = node.out.unzip

    // Grab the port ID mapping
    val inputIdRanges = AXI4Xbar.mapInputIds(edgesIn.map(_.master))

    // Find a good mask for address decoding
    val port_addrs = edgesOut.map(_.slave.slaves.map(_.address).flatten)
    val routingMask = AddressDecoder(port_addrs)
    val route_addrs = port_addrs.map(seq => AddressSet.unify(seq.map(_.widen(~routingMask)).distinct))
    val outputPorts = route_addrs.map(seq => (addr: UInt) => seq.map(_.contains(addr)).reduce(_ || _))

    // To route W we need to record where the AWs went
    val awIn  = Seq.fill(io_in .size) { Module(new Queue(UInt(io_out.size.W), awQueueDepth, flow = true)) }
    val awOut = Seq.fill(io_out.size) { Module(new Queue(UInt(io_in .size.W), awQueueDepth, flow = true)) }

    val requestARIO = io_in.map  { i => VecInit(outputPorts.map   { o => o(i.ar.bits.addr) }) }
    val requestAWIO = io_in.map  { i => VecInit(outputPorts.map   { o => o(i.aw.bits.addr) }) }
    val requestROI  = io_out.map { o => inputIdRanges.map { i => i.contains(o.r.bits.id) } }
    val requestBOI  = io_out.map { o => inputIdRanges.map { i => i.contains(o.b.bits.id) } }

    // W follows the path dictated by the AW Q
    for (i <- 0 until io_in.size) { awIn(i).io.enq.bits := requestAWIO(i).asUInt }
    val requestWIO = awIn.map { q => if (io_out.size > 1) q.io.deq.bits.asBools else Seq(true.B) }

    // We need an intermediate size of bundle with the widest possible identifiers
    val wide_bundle = AXI4BundleParameters.union(io_in.map(_.params) ++ io_out.map(_.params))

    // Transform input bundles
    val in = Wire(Vec(io_in.size, new AXI4Bundle(wide_bundle)))
    for (i <- 0 until in.size) {
      in(i).aw.bits.user := DontCare
      in(i).aw.bits.echo := DontCare
      in(i).ar.bits.user := DontCare
      in(i).ar.bits.echo := DontCare
      in(i).w.bits.user := DontCare
      in(i).squeezeAll.waiveAll :<>= io_in(i).squeezeAll.waiveAll

      // Handle size = 1 gracefully (Chisel3 empty range is broken)
      def trim(id: UInt, size: Int) = if (size <= 1) 0.U else id(log2Ceil(size)-1, 0)
      // Manipulate the AXI IDs to differentiate masters
      val r = inputIdRanges(i)
      in(i).aw.bits.id := io_in(i).aw.bits.id | (r.start).U
      in(i).ar.bits.id := io_in(i).ar.bits.id | (r.start).U
      io_in(i).r.bits.id := trim(in(i).r.bits.id, r.size)
      io_in(i).b.bits.id := trim(in(i).b.bits.id, r.size)

      if (io_out.size > 1) {
        // Block A[RW] if we switch ports, to ensure responses stay ordered (also: beware the dining philosophers)
        val endId = edgesIn(i).master.endId
        val arFIFOMap = WireDefault(VecInit.fill(endId) { true.B })
        val awFIFOMap = WireDefault(VecInit.fill(endId) { true.B })
        val arSel = UIntToOH(io_in(i).ar.bits.id, endId)
        val awSel = UIntToOH(io_in(i).aw.bits.id, endId)
        val rSel  = UIntToOH(io_in(i).r .bits.id, endId)
        val bSel  = UIntToOH(io_in(i).b .bits.id, endId)
        val arTag = OHToUInt(requestARIO(i).asUInt, io_out.size)
        val awTag = OHToUInt(requestAWIO(i).asUInt, io_out.size)

        for (master <- edgesIn(i).master.masters) {
          def idTracker(port: UInt, req_fire: Bool, resp_fire: Bool) = {
            if (master.maxFlight == Some(0)) {
              true.B
            } else {
              val legalFlight = master.maxFlight.getOrElse(maxFlightPerId+1)
              val flight = legalFlight min maxFlightPerId
              val canOverflow = legalFlight > flight
              val count = RegInit(0.U(log2Ceil(flight+1).W))
              val last = Reg(UInt(log2Ceil(io_out.size).W))
              count := count + req_fire.asUInt - resp_fire.asUInt
              assert (!resp_fire || count =/= 0.U)
              assert (!req_fire  || count =/= flight.U)
              when (req_fire) { last := port }
              // No need to track where it went if we cap it at 1 request
              val portMatch = if (flight == 1) { true.B } else { last === port }
              (count === 0.U || portMatch) && ((!canOverflow).B || count =/= flight.U)
            }
          }

          for (id <- master.id.start until master.id.end) {
            arFIFOMap(id) := idTracker(
              arTag,
              arSel(id) && io_in(i).ar.fire,
              rSel(id) && io_in(i).r.fire && io_in(i).r.bits.last)
            awFIFOMap(id) := idTracker(
              awTag,
              awSel(id) && io_in(i).aw.fire,
              bSel(id) && io_in(i).b.fire)
          }
        }

        val allowAR = arFIFOMap(io_in(i).ar.bits.id)
        in(i).ar.valid := io_in(i).ar.valid && allowAR
        io_in(i).ar.ready := in(i).ar.ready && allowAR

        // Keep in mind that slaves may do this: awready := wvalid, wready := awvalid
        // To not cause a loop, we cannot have: wvalid := awready

        // Block AW if we cannot record the W destination
        val allowAW = awFIFOMap(io_in(i).aw.bits.id)
        val latched = RegInit(false.B) // cut awIn(i).enq.valid from awready
        in(i).aw.valid := io_in(i).aw.valid && (latched || awIn(i).io.enq.ready) && allowAW
        io_in(i).aw.ready := in(i).aw.ready && (latched || awIn(i).io.enq.ready) && allowAW
        awIn(i).io.enq.valid := io_in(i).aw.valid && !latched
        when (awIn(i).io.enq.fire) { latched := true.B }
        when (in(i).aw.fire) { latched := false.B }

        // Block W if we do not have an AW destination
        in(i).w.valid := io_in(i).w.valid && awIn(i).io.deq.valid // depends on awvalid (but not awready)
        io_in(i).w.ready := in(i).w.ready && awIn(i).io.deq.valid
        awIn(i).io.deq.ready := io_in(i).w.valid && io_in(i).w.bits.last && in(i).w.ready
      } else {
        awIn(i).io := DontCare // aw in queue is not used when outsize == 1
      }
    }

    // Transform output bundles
    val out = Wire(Vec(io_out.size, new AXI4Bundle(wide_bundle)))
    for (i <- 0 until out.size) {
      out(i).b.bits.user := DontCare
      out(i).r.bits.user := DontCare
      io_out(i).squeezeAll.waiveAll :<>= out(i).squeezeAll.waiveAll

      if (io_in.size > 1) {
        // Block AW if we cannot record the W source
        val latched = RegInit(false.B) // cut awOut(i).enq.valid from awready
        io_out(i).aw.valid := out(i).aw.valid && (latched || awOut(i).io.enq.ready)
        out(i).aw.ready := io_out(i).aw.ready && (latched || awOut(i).io.enq.ready)
        awOut(i).io.enq.valid := out(i).aw.valid && !latched
        when (awOut(i).io.enq.fire) { latched := true.B }
        when (out(i).aw.fire) { latched := false.B }

        // Block W if we do not have an AW source
        io_out(i).w.valid := out(i).w.valid && awOut(i).io.deq.valid // depends on awvalid (but not awready)
        out(i).w.ready := io_out(i).w.ready && awOut(i).io.deq.valid
        awOut(i).io.deq.ready := out(i).w.valid && out(i).w.bits.last && io_out(i).w.ready
      } else {
        awOut(i).io := DontCare // aw out queue is not used when io_in.size == 1
      }
    }

    // Fanout the input sources to the output sinks
    def transpose[T](x: Seq[Seq[T]]) = Seq.tabulate(x(0).size) { i => Seq.tabulate(x.size) { j => x(j)(i) } }
    val portsAROI = transpose((in  zip requestARIO) map { case (i, r) => AXI4Xbar.fanout(i.ar, r) })
    val portsAWOI = transpose((in  zip requestAWIO) map { case (i, r) => AXI4Xbar.fanout(i.aw, r) })
    val portsWOI  = transpose((in  zip requestWIO)  map { case (i, r) => AXI4Xbar.fanout(i.w,  r) })
    val portsRIO  = transpose((out zip requestROI)  map { case (o, r) => AXI4Xbar.fanout(o.r,  r) })
    val portsBIO  = transpose((out zip requestBOI)  map { case (o, r) => AXI4Xbar.fanout(o.b,  r) })

    // Arbitrate amongst the sources
    for (o <- 0 until out.size) {
      awOut(o).io.enq.bits := // Record who won AW arbitration to select W
        AXI4Arbiter.returnWinner(arbitrationPolicy)(out(o).aw, portsAWOI(o):_*).asUInt
      AXI4Arbiter(arbitrationPolicy)(out(o).ar, portsAROI(o):_*)
      // W arbitration is informed by the Q, not policy
      out(o).w.valid := Mux1H(awOut(o).io.deq.bits, portsWOI(o).map(_.valid))
      out(o).w.bits :<= Mux1H(awOut(o).io.deq.bits, portsWOI(o).map(_.bits))
      portsWOI(o).zipWithIndex.map { case (p, i) =>
        if (in.size > 1) {
          p.ready := out(o).w.ready && awOut(o).io.deq.bits(i)
        } else {
          p.ready := out(o).w.ready
        }
      }
    }

    for (i <- 0 until in.size) {
      AXI4Arbiter(arbitrationPolicy)(in(i).r, portsRIO(i):_*)
      AXI4Arbiter(arbitrationPolicy)(in(i).b, portsBIO(i):_*)
    }
  }
}

object AXI4Xbar
{
  def apply(
    arbitrationPolicy: TLArbiter.Policy = TLArbiter.roundRobin,
    maxFlightPerId:    Int = 7,
    awQueueDepth:      Int = 2)(implicit p: Parameters) =
  {
    val axi4xbar = LazyModule(new AXI4Xbar(arbitrationPolicy, maxFlightPerId, awQueueDepth))
    axi4xbar.node
  }

  def mapInputIds(ports: Seq[AXI4MasterPortParameters]) = TLXbar.assignRanges(ports.map(_.endId))

  // Replicate an input port to each output port
  def fanout[T <: AXI4BundleBase](input: IrrevocableIO[T], select: Seq[Bool]) = {
    val filtered = Wire(Vec(select.size, chiselTypeOf(input)))
    for (i <- 0 until select.size) {
      filtered(i).bits :<= input.bits
      filtered(i).valid := input.valid && select(i)
    }
    input.ready := Mux1H(select, filtered.map(_.ready))
    filtered
  }
}

object AXI4Arbiter
{
  def apply[T <: Data](policy: TLArbiter.Policy)(sink: IrrevocableIO[T], sources: IrrevocableIO[T]*): Unit = {
    if (sources.isEmpty) {
      sink.valid := false.B
    } else {
      returnWinner(policy)(sink, sources:_*)
    }
  }
  def returnWinner[T <: Data](policy: TLArbiter.Policy)(sink: IrrevocableIO[T], sources: IrrevocableIO[T]*) = {
    require (!sources.isEmpty)

    // The arbiter is irrevocable; when !idle, repeat last request
    val idle = RegInit(true.B)

    // Who wants access to the sink?
    val valids = sources.map(_.valid)
    val anyValid = valids.reduce(_ || _)
    // Arbitrate amongst the requests
    val readys = VecInit(policy(valids.size, Cat(valids.reverse), idle).asBools)
    // Which request wins arbitration?
    val winner = VecInit((readys zip valids) map { case (r,v) => r&&v })

    // Confirm the policy works properly
    require (readys.size == valids.size)
    // Never two winners
    val prefixOR = winner.scanLeft(false.B)(_||_).init

    // If there was any request, there is a winner
    assert (!anyValid || winner.reduce(_||_))

    // The one-hot source granted access in the previous cycle
    val state = RegInit(VecInit.fill(sources.size)(false.B))
    val muxState = Mux(idle, winner, state)
    state := muxState

    // Determine when we go idle
    when (anyValid) { idle := false.B }
    when (sink.fire) { idle := true.B }

    if (sources.size > 1) {
      val allowed = Mux(idle, readys, state)
      (sources zip allowed) foreach { case (s, r) =>
        s.ready := sink.ready && r
      }
    } else {
      sources(0).ready := sink.ready
    }

    sink.valid := Mux(idle, anyValid, Mux1H(state, valids))
    sink.bits :<= Mux1H(muxState, sources.map(_.bits))
    muxState
  }
}

class AXI4XbarFuzzTest(name: String, txns: Int, nMasters: Int, nSlaves: Int)(implicit p: Parameters) extends LazyModule
{
  val xbar = AXI4Xbar()
  val slaveSize = 0x1000
  val masterBandSize = slaveSize >> log2Ceil(nMasters)
  def filter(i: Int) = TLFilter.mSelectIntersect(AddressSet(i * masterBandSize, ~BigInt(slaveSize - masterBandSize)))

  val slaves = Seq.tabulate(nSlaves) { i => LazyModule(new AXI4RAM(AddressSet(slaveSize * i, slaveSize-1))) }
  slaves.foreach { s => (s.node
    := AXI4Fragmenter()
    := AXI4Buffer(BufferParams.flow)
    := AXI4Buffer(BufferParams.flow)
    := AXI4Delayer(0.25)
    := xbar) }

  val masters = Seq.fill(nMasters) { LazyModule(new TLFuzzer(txns, 4, nOrdered = Some(1))) }
  masters.zipWithIndex.foreach { case (m, i) => (xbar
    := AXI4Delayer(0.25)
    := AXI4Deinterleaver(4096)
    := TLToAXI4()
    := TLFilter(filter(i))
    := TLRAMModel(s"${name} Master $i")
    := m.node) }

  lazy val module = new Impl
  class Impl extends LazyModuleImp(this) with UnitTestModule {
    io.finished := masters.map(_.module.io.finished).reduce(_ || _)
  }
}

class AXI4XbarTest(txns: Int = 5000, timeout: Int = 500000)(implicit p: Parameters) extends UnitTest(timeout) {
  val dut21 = Module(LazyModule(new AXI4XbarFuzzTest("Xbar DUT21", txns, 2, 1)).module)
  val dut12 = Module(LazyModule(new AXI4XbarFuzzTest("Xbar DUT12", txns, 1, 2)).module)
  val dut22 = Module(LazyModule(new AXI4XbarFuzzTest("Xbar DUT22", txns, 2, 2)).module)
  io.finished := Seq(dut21, dut12, dut22).map(_.io.finished).reduce(_ || _)
  Seq(dut21, dut12, dut22).foreach(_.io.start := io.start)
}

assert((prefixOR zip winner) map { case (p,w) => !p || !w } reduce {_ && _})


// See LICENSE.SiFive for license details.

package freechips.rocketchip.devices.tilelink

import chisel3._

import org.chipsalliance.cde.config._
import org.chipsalliance.diplomacy._
import org.chipsalliance.diplomacy.lazymodule._

import freechips.rocketchip.diplomacy.{AddressSet, TransferSizes}
import freechips.rocketchip.tilelink.{
  LFSR64, TLBundleA, TLBundleC, TLBundleE, TLClientNode, TLCustomNode, TLFilter, TLFragmenter,
  TLFuzzer, TLMasterParameters, TLMasterPortParameters, TLPermissions, TLRAM, TLRAMModel,
  TLSlaveParameters, TLSlavePortParameters
}

class MasterMuxNode(uFn: Seq[TLMasterPortParameters] => TLMasterPortParameters)(implicit valName: ValName) extends TLCustomNode
{
  def resolveStar(iKnown: Int, oKnown: Int, iStars: Int, oStars: Int): (Int, Int) = {
    require (iStars == 0 && oStars == 0, "MasterMux node does not support :=* or :*=")
    require (iKnown == 2, "MasterMux node expects exactly two inputs")
    require (oKnown == 1, "MasterMux node expects exactly one output")
    (0, 0)
  }
  def mapParamsD(n: Int, p: Seq[TLMasterPortParameters]): Seq[TLMasterPortParameters] = { Seq(uFn(p)) }
  def mapParamsU(n: Int, p: Seq[TLSlavePortParameters]): Seq[TLSlavePortParameters] = { p ++ p }
}

class MuteMaster(name: String = "MuteMaster", maxProbe: Int = 0)(implicit p: Parameters) extends LazyModule
{
  val node = TLClientNode(Seq(TLMasterPortParameters.v1(clients = Seq(TLMasterParameters.v1(
    name = name,
    supportsProbe = if (maxProbe > 0) TransferSizes(1, maxProbe) else TransferSizes.none)))))

  lazy val module = new Impl
  class Impl extends LazyModuleImp(this) {
    val Seq((out, edgeOut)) = node.out
    out.a.valid := false.B
    out.b.ready := out.c.ready
    out.c.valid := out.b.valid
    out.d.ready := true.B
    out.e.valid := false.B

    out.c.bits := edgeOut.ProbeAck(out.b.bits, TLPermissions.NtoN)
  }
}

class MasterMux(uFn: Seq[TLMasterPortParameters] => TLMasterPortParameters)(implicit p: Parameters) extends LazyModule
{
  val node = new MasterMuxNode(uFn)

  lazy val module = new Impl
  class Impl extends LazyModuleImp(this) {
    val io = IO(new Bundle {
      val bypass = Input(Bool())
      val pending = Output(Bool())
    })

    val Seq((in0, edgeIn0), (in1, edgeIn1)) = node.in
    val Seq((out, edgeOut)) = node.out

    // We need to be locked to the given bypass direction until all transactions stop
    val bypass = RegInit(io.bypass) // synchronous reset required
    val (flight, next_flight) = edgeOut.inFlight(out)

    io.pending := (flight > 0.U)
    when (next_flight === 0.U) { bypass := io.bypass }
    val stall = (bypass =/= io.bypass) && edgeOut.first(out.a)

    in0.a.ready := !stall && out.a.ready &&  bypass
    in1.a.ready := !stall && out.a.ready && !bypass
    out.a.valid := !stall && Mux(bypass, in0.a.valid, in1.a.valid)
    def castA(x: TLBundleA) = { val ret = Wire(x.cloneType); ret <> x; ret }
    out.a.bits := Mux(bypass, castA(in0.a.bits), castA(in1.a.bits))

    out.d.ready := Mux(bypass, in0.d.ready, in1.d.ready)
    in0.d.valid := out.d.valid &&  bypass
    in1.d.valid := out.d.valid && !bypass
    in0.d.bits := out.d.bits
    in1.d.bits := out.d.bits

    if (edgeOut.manager.anySupportAcquireB && edgeOut.client.anySupportProbe) {
      out.b.ready := Mux(bypass, in0.b.ready, in1.b.ready)
      in0.b.valid := out.b.valid &&  bypass
      in1.b.valid := out.b.valid && !bypass
      in0.b.bits := out.b.bits
      in1.b.bits := out.b.bits

      in0.c.ready := out.c.ready &&  bypass
      in1.c.ready := out.c.ready && !bypass
      out.c.valid := Mux(bypass, in0.c.valid, in1.c.valid)

      out.c.bits := Mux(bypass, castC(in0.c.bits), castC(in1.c.bits))

      in0.e.ready := out.e.ready &&  bypass
      in1.e.ready := out.e.ready && !bypass
      out.e.valid := Mux(bypass, in0.e.valid, in1.e.valid)
      def castE(x: TLBundleE) = { val ret = Wire(out.e.bits); ret <> x; ret }
      out.e.bits := Mux(bypass, castE(in0.e.bits), castE(in1.e.bits))
    } else {
      in0.b.valid := false.B
      in0.c.ready := true.B
      in0.e.ready := true.B

      in1.b.valid := false.B
      in1.c.ready := true.B
      in1.e.ready := true.B

      out.b.ready := true.B
      out.c.valid := false.B
      out.e.valid := false.B
    }
  }
}

// Synthesizable unit tests
import freechips.rocketchip.unittest._

class TLMasterMuxTester(txns: Int)(implicit p: Parameters) extends LazyModule {
  val fuzz1 = LazyModule(new TLFuzzer(txns))
  val fuzz2 = LazyModule(new TLFuzzer(txns))
  val model1 = LazyModule(new TLRAMModel("MasterMux1"))
  val model2 = LazyModule(new TLRAMModel("MasterMux2"))
  val mux = LazyModule(new MasterMux(uFn = _.head))
  val ram = LazyModule(new TLRAM(AddressSet(0, 0x3ff), beatBytes = 4))
  mux.node := TLFilter(TLFilter.mSelectIntersect(AddressSet( 0, ~16))) := model1.node := fuzz1.node
  mux.node := TLFilter(TLFilter.mSelectIntersect(AddressSet(16, ~16))) := model2.node := fuzz2.node
  ram.node := TLFragmenter(4, 16) := mux.node
  // how to test probe + release?

  lazy val module = new Impl
  class Impl extends LazyModuleImp(this) with UnitTestModule {
    io.finished := fuzz1.module.io.finished && fuzz2.module.io.finished
    mux.module.io.bypass := LFSR64(true.B)(0)
  }
}

class TLMasterMuxTest(txns: Int = 5000, timeout: Int = 500000)(implicit p: Parameters) extends UnitTest(timeout) {
  val dut = Module(LazyModule(new TLMasterMuxTester(txns)).module)
  io <> dut.io
}

def castC(x: TLBundleC) = { val ret = Wire(out.c.bits); ret <> x; ret }


// See LICENSE.SiFive for license details.

package freechips.rocketchip.interrupts

import org.chipsalliance.cde.config._
import org.chipsalliance.diplomacy.lazymodule._

import freechips.rocketchip.util.BlockDuringReset

/** BlockDuringReset ensures that no interrupt is raised while reset is raised. */

{
  val intnode = IntAdapterNode()
  override def shouldBeInlined = true
  lazy val module = new Impl
  class Impl extends LazyModuleImp(this) {
    intnode.in.zip(intnode.out).foreach { case ((in, _), (out, _)) =>
      in.zip(out).foreach { case (i, o) => o := BlockDuringReset(i, stretchResetCycles) }
    }
  }
}

object IntBlockDuringReset {
  def apply(stretchResetCycles: Int = 0)(implicit p: Parameters): IntNode = {
    val block_during_reset = LazyModule(new IntBlockDuringReset(stretchResetCycles))
    block_during_reset.intnode
  }
}

class IntBlockDuringReset(stretchResetCycles: Int = 0)(implicit p: Parameters) extends LazyModule


// See LICENSE.SiFive for license details.

package freechips.rocketchip.interrupts

import org.chipsalliance.cde.config._
import org.chipsalliance.diplomacy.lazymodule._

class IntXbar()(implicit p: Parameters) extends LazyModule
{
  val intnode = new IntNexusNode(
    sinkFn         = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) },
    sourceFn       = { seq =>
      IntSourcePortParameters((seq zip seq.map(_.num).scanLeft(0)(_+_).init).map {
        case (s, o) => s.sources.map(z => z.copy(range = z.range.offset(o)))
      }.flatten)
    })
  {
    override def circuitIdentity = outputs.size == 1 && inputs.size == 1
  }

  lazy val module = new Impl
  class Impl extends LazyRawModuleImp(this) {

    val cat = intnode.in.map { case (i, e) => i.take(e.source.num) }.flatten
    intnode.out.foreach { case (o, _) => o := cat }
  }
}

class IntSyncXbar()(implicit p: Parameters) extends LazyModule
{
  val intnode = new IntSyncNexusNode(
    sinkFn         = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) },
    sourceFn       = { seq =>
      IntSourcePortParameters((seq zip seq.map(_.num).scanLeft(0)(_+_).init).map {
        case (s, o) => s.sources.map(z => z.copy(range = z.range.offset(o)))
      }.flatten)
    })
  {
    override def circuitIdentity = outputs.size == 1 && inputs.size == 1
  }

  lazy val module = new Impl
  class Impl extends LazyModuleImp(this) {
    override def desiredName = s"IntSyncXbar_i${intnode.in.size}_o${intnode.out.size}"
    val cat = intnode.in.map { case (i, e) => i.sync.take(e.source.num) }.flatten
    intnode.out.foreach { case (o, _) => o.sync := cat }
  }
}

object IntXbar {
  def apply()(implicit p: Parameters): IntNode = {
    val xbar = LazyModule(new IntXbar)
    xbar.intnode
  }
}

object IntSyncXbar {
  def apply()(implicit p: Parameters): IntSyncNode = {
    val xbar = LazyModule(new IntSyncXbar)
    xbar.intnode
  }
}

override def desiredName = s"IntXbar_i${intnode.in.size}_o${intnode.out.size}"


// See LICENSE for license details.
package freechips.rocketchip.prci

import chisel3._
import chisel3.util._
import org.chipsalliance.cde.config._
import org.chipsalliance.diplomacy.lazymodule._

import freechips.rocketchip.util.{AsyncResetReg, ResetCatchAndSync}

class ResetWrangler(debounceNs: Double = 100000)(implicit p: Parameters) extends LazyModule
{
  val node = ClockAdapterNode()

  lazy val module = new Impl
  class Impl extends LazyRawModuleImp(this) {
    val (in, _) = node.in.unzip
    val (out, _) = node.out.unzip

    val status = IO(Output(UInt(in.size.W)))
    status := Cat(in.map(_.reset.asBool).reverse)
    val causes = in.map(_.reset).foldLeft(false.B)(_.asBool || _.asBool)

    require(node.in.forall(_._2.clock.isDefined), "Cannot wrangle reset for an unspecified clock frequency")
    val (slowIn, slowEdge) = node.in.minBy(_._2.clock.get.freqMHz)
    val slowPeriodNs = 1000 / slowEdge.clock.get.freqMHz
    val slowTicks = math.ceil(debounceNs/slowPeriodNs).toInt max 7
    val slowBits = log2Ceil(slowTicks+1)

    // debounce
    val increment = Wire(Bool())
    val incremented = Wire(UInt(slowBits.W))

    val deglitched = AsyncResetReg(increment, slowIn.clock, causes, true, Some("deglitch"))

    // catch and sync increment to each domain
    (in zip out) foreach { case (i, o) =>
      o.clock := i.clock
      o.reset := ResetCatchAndSync(o.clock, deglitched)
    }
  }
}

    val debounced = withClockAndReset(slowIn.clock, causes) {
      AsyncResetReg(incremented, 0, increment, Some("debounce"))
    }


// See LICENSE.SiFive for license details.

package freechips.rocketchip.subsystem

import org.chipsalliance.cde.config._
import org.chipsalliance.diplomacy.lazymodule._

import freechips.rocketchip.devices.tilelink.{BuiltInDevices, HasBuiltInDeviceParams, BuiltInErrorDeviceParams, BuiltInZeroDeviceParams}
import freechips.rocketchip.tilelink.{
  ReplicatedRegion, HasTLBusParams, HasRegionReplicatorParams, TLBusWrapper,
  TLBusWrapperInstantiationLike, RegionReplicator, TLXbar, TLInwardNode,
  TLOutwardNode, ProbePicker, TLEdge, TLFIFOFixer
}
import freechips.rocketchip.util.Location

/** Parameterization of the memory-side bus created for each memory channel */
case class MemoryBusParams(
  beatBytes: Int,
  blockBytes: Int,
  dtsFrequency: Option[BigInt] = None,
  zeroDevice: Option[BuiltInZeroDeviceParams] = None,
  errorDevice: Option[BuiltInErrorDeviceParams] = None,
  replication: Option[ReplicatedRegion] = None)
  extends HasTLBusParams
  with HasBuiltInDeviceParams
  with HasRegionReplicatorParams
  with TLBusWrapperInstantiationLike
{
  def instantiate(context: HasTileLinkLocations, loc: Location[TLBusWrapper])(implicit p: Parameters): MemoryBus = {
    val mbus = LazyModule(new MemoryBus(this, loc.name))
    mbus.suggestName(loc.name)
    context.tlBusWrapperLocationMap += (loc -> mbus)
    mbus
  }
}

/** Wrapper for creating TL nodes from a bus connected to the back of each mem channel */
class MemoryBus(params: MemoryBusParams, name: String = "memory_bus")(implicit p: Parameters)
    extends TLBusWrapper(params, name)(p)
{
  private val replicator = params.replication.map(r => LazyModule(new RegionReplicator(r)))
  val prefixNode = replicator.map { r =>
    r.prefix := addressPrefixNexusNode
    addressPrefixNexusNode
  }

  private val xbar = LazyModule(new TLXbar(nameSuffix = Some(name))).suggestName(busName + "_xbar")
  val inwardNode: TLInwardNode =
    replicator.map(xbar.node :*=* TLFIFOFixer(TLFIFOFixer.all) :*=* _.node)
        .getOrElse(xbar.node :*=* TLFIFOFixer(TLFIFOFixer.all))

  val outwardNode: TLOutwardNode = ProbePicker() :*= xbar.node

  val builtInDevices: BuiltInDevices = BuiltInDevices.attach(params, outwardNode)
}

def busView: TLEdge = xbar.node.edges.in.head


// See LICENSE.SiFive for license details.

package freechips.rocketchip.system // TODO this should really be in a testharness package

import chisel3._

import org.chipsalliance.cde.config._
import org.chipsalliance.diplomacy.lazymodule._

import freechips.rocketchip.amba.AMBACorrupt
import freechips.rocketchip.amba.axi4.{AXI4RAM, AXI4MasterNode, AXI4EdgeParameters, AXI4Xbar, AXI4Buffer, AXI4Fragmenter}
import freechips.rocketchip.diplomacy.AddressSet
import freechips.rocketchip.subsystem.{CanHaveMasterAXI4MMIOPort, CanHaveMasterAXI4MemPort, ExtBus, ExtMem}

/** Memory with AXI port for use in elaboratable test harnesses.
 *
 * Topology: AXIRAM <-< AXI4Buffer <-< AXI4Fragmenter <-< AXI4Xbar <-< AXI4MasterNode
*/
class SimAXIMem(edge: AXI4EdgeParameters, size: BigInt, base: BigInt = 0)(implicit p: Parameters) extends SimpleLazyModule {
  val node = AXI4MasterNode(List(edge.master))
  val srams = AddressSet.misaligned(base, size).map { aSet =>
    LazyModule(new AXI4RAM(
      address = aSet,
      beatBytes = edge.bundle.dataBits/8,
      wcorrupt=edge.slave.requestKeys.contains(AMBACorrupt)))
  }
  val xbar = AXI4Xbar()
  srams.foreach{ s => s.node := AXI4Buffer() := AXI4Fragmenter() := xbar }
  xbar := node

}

/**
  * Connect Master AXI4 Mem/MMIO Port to SimAXIMem.
  */
object SimAXIMem {
  def connectMMIO(dut: CanHaveMasterAXI4MMIOPort)(implicit p: Parameters): Seq[SimAXIMem] = {
    dut.mmio_axi4.zip(dut.mmioAXI4Node.in).map { case (io, (_, edge)) =>
      // test harness size capped to 4KB (ignoring p(ExtMem).get.master.size)
      val mmio_mem = LazyModule(new SimAXIMem(edge, base = p(ExtBus).get.base, size = 4096))
      Module(mmio_mem.module).suggestName("mmio_mem")
      mmio_mem.io_axi4.head <> io
      mmio_mem
    }.toSeq
  }

  def connectMem(dut: CanHaveMasterAXI4MemPort)(implicit p: Parameters): Seq[SimAXIMem] = {
    dut.mem_axi4.zip(dut.memAXI4Node.in).map { case (io, (_, edge)) =>
      val mem = LazyModule(new SimAXIMem(edge, base = p(ExtMem).get.master.base, size = p(ExtMem).get.master.size))
      Module(mem.module).suggestName("mem")
      mem.io_axi4.head <> io
      mem
    }.toSeq
  }
}

val io_axi4 = InModuleBody { node.makeIOs() }


// See LICENSE.SiFive for license details.

package freechips.rocketchip.tilelink

import chisel3._
import chisel3.experimental.SourceInfo

import org.chipsalliance.cde.config._
import org.chipsalliance.diplomacy._
import org.chipsalliance.diplomacy.nodes._

import freechips.rocketchip.util.{AsyncQueueParams,RationalDirection}

case object TLMonitorBuilder extends Field[TLMonitorArgs => TLMonitorBase](args => new TLMonitor(args))

object TLImp extends NodeImp[TLMasterPortParameters, TLSlavePortParameters, TLEdgeOut, TLEdgeIn, TLBundle]
{
  def edgeO(pd: TLMasterPortParameters, pu: TLSlavePortParameters, p: Parameters, sourceInfo: SourceInfo) = new TLEdgeOut(pd, pu, p, sourceInfo)
  def edgeI(pd: TLMasterPortParameters, pu: TLSlavePortParameters, p: Parameters, sourceInfo: SourceInfo) = new TLEdgeIn (pd, pu, p, sourceInfo)

  def bundleO(eo: TLEdgeOut) = TLBundle(eo.bundle)
  def bundleI(ei: TLEdgeIn)  = TLBundle(ei.bundle)

  def render(ei: TLEdgeIn) = RenderedEdge(colour = "#000000" /* black */, label = (ei.manager.beatBytes * 8).toString)

  override def monitor(bundle: TLBundle, edge: TLEdgeIn): Unit = {
    val monitor = Module(edge.params(TLMonitorBuilder)(TLMonitorArgs(edge)))
    monitor.io.in :#= bundle
  }

  override def mixO(pd: TLMasterPortParameters, node: OutwardNode[TLMasterPortParameters, TLSlavePortParameters, TLBundle]): TLMasterPortParameters  =
    pd.v1copy(clients  = pd.clients.map  { c => c.v1copy (nodePath = node +: c.nodePath) })
  override def mixI(pu: TLSlavePortParameters, node: InwardNode[TLMasterPortParameters, TLSlavePortParameters, TLBundle]): TLSlavePortParameters =
    pu.v1copy(managers = pu.managers.map { m => m.v1copy (nodePath = node +: m.nodePath) })
}

trait TLFormatNode extends FormatNode[TLEdgeIn, TLEdgeOut]

case class TLClientNode(portParams: Seq[TLMasterPortParameters])(implicit valName: ValName) extends SourceNode(TLImp)(portParams) with TLFormatNode
case class TLManagerNode(portParams: Seq[TLSlavePortParameters])(implicit valName: ValName) extends SinkNode(TLImp)(portParams) with TLFormatNode

case class TLAdapterNode(
  clientFn:  TLMasterPortParameters => TLMasterPortParameters = { s => s },
  managerFn: TLSlavePortParameters  => TLSlavePortParameters  = { s => s })(
  implicit valName: ValName)
  extends AdapterNode(TLImp)(clientFn, managerFn) with TLFormatNode

case class TLJunctionNode(
  clientFn:     Seq[TLMasterPortParameters] => Seq[TLMasterPortParameters],
  managerFn:    Seq[TLSlavePortParameters]  => Seq[TLSlavePortParameters])(
  implicit valName: ValName)
  extends JunctionNode(TLImp)(clientFn, managerFn) with TLFormatNode

case class TLIdentityNode()(implicit valName: ValName) extends IdentityNode(TLImp)() with TLFormatNode

object TLNameNode {
  def apply(name: ValName) = TLIdentityNode()(name)
  def apply(name: Option[String]): TLIdentityNode = apply(ValName(name.getOrElse("with_no_name")))
  def apply(name: String): TLIdentityNode = apply(Some(name))
}

case class TLEphemeralNode()(implicit valName: ValName) extends EphemeralNode(TLImp)()

object TLTempNode {
  def apply(): TLEphemeralNode = TLEphemeralNode()(ValName("temp"))
}

case class TLNexusNode(
  clientFn:        Seq[TLMasterPortParameters] => TLMasterPortParameters,
  managerFn:       Seq[TLSlavePortParameters]  => TLSlavePortParameters)(
  implicit valName: ValName)
  extends NexusNode(TLImp)(clientFn, managerFn) with TLFormatNode

abstract class TLCustomNode(implicit valName: ValName)
  extends CustomNode(TLImp) with TLFormatNode

// Asynchronous crossings

trait TLAsyncFormatNode extends FormatNode[TLAsyncEdgeParameters, TLAsyncEdgeParameters]

object TLAsyncImp extends SimpleNodeImp[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncEdgeParameters, TLAsyncBundle]
{
  def edge(pd: TLAsyncClientPortParameters, pu: TLAsyncManagerPortParameters, p: Parameters, sourceInfo: SourceInfo) = TLAsyncEdgeParameters(pd, pu, p, sourceInfo)
  def bundle(e: TLAsyncEdgeParameters) = new TLAsyncBundle(e.bundle)
  def render(e: TLAsyncEdgeParameters) = RenderedEdge(colour = "#ff0000" /* red */, label = e.manager.async.depth.toString)

  override def mixO(pd: TLAsyncClientPortParameters, node: OutwardNode[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]): TLAsyncClientPortParameters  =
   pd.copy(base = pd.base.v1copy(clients  = pd.base.clients.map  { c => c.v1copy (nodePath = node +: c.nodePath) }))
  override def mixI(pu: TLAsyncManagerPortParameters, node: InwardNode[TLAsyncClientPortParameters, TLAsyncManagerPortParameters, TLAsyncBundle]): TLAsyncManagerPortParameters =
   pu.copy(base = pu.base.v1copy(managers = pu.base.managers.map { m => m.v1copy (nodePath = node +: m.nodePath) }))
}

case class TLAsyncAdapterNode(
  clientFn:  TLAsyncClientPortParameters  => TLAsyncClientPortParameters  = { s => s },
  managerFn: TLAsyncManagerPortParameters => TLAsyncManagerPortParameters = { s => s })(
  implicit valName: ValName)
  extends AdapterNode(TLAsyncImp)(clientFn, managerFn) with TLAsyncFormatNode

case class TLAsyncIdentityNode()(implicit valName: ValName) extends IdentityNode(TLAsyncImp)() with TLAsyncFormatNode

object TLAsyncNameNode {
  def apply(name: ValName) = TLAsyncIdentityNode()(name)
  def apply(name: Option[String]): TLAsyncIdentityNode = apply(ValName(name.getOrElse("with_no_name")))
  def apply(name: String): TLAsyncIdentityNode = apply(Some(name))
}

case class TLAsyncSourceNode(sync: Option[Int])(implicit valName: ValName)
  extends MixedAdapterNode(TLImp, TLAsyncImp)(
    dFn = { p => TLAsyncClientPortParameters(p) },
    uFn = { p => p.base.v1copy(minLatency = p.base.minLatency + sync.getOrElse(p.async.sync)) }) with FormatNode[TLEdgeIn, TLAsyncEdgeParameters] // discard cycles in other clock domain
case class TLAsyncSinkNode(async: AsyncQueueParams)(implicit valName: ValName)
  extends MixedAdapterNode(TLAsyncImp, TLImp)(
    dFn = { p => p.base.v1copy(minLatency = p.base.minLatency + async.sync) },
    uFn = { p => TLAsyncManagerPortParameters(async, p) }) with FormatNode[TLAsyncEdgeParameters, TLEdgeOut]

// Rationally related crossings

trait TLRationalFormatNode extends FormatNode[TLRationalEdgeParameters, TLRationalEdgeParameters]

object TLRationalImp extends SimpleNodeImp[TLRationalClientPortParameters, TLRationalManagerPortParameters, TLRationalEdgeParameters, TLRationalBundle]
{
  def edge(pd: TLRationalClientPortParameters, pu: TLRationalManagerPortParameters, p: Parameters, sourceInfo: SourceInfo) = TLRationalEdgeParameters(pd, pu, p, sourceInfo)
  def bundle(e: TLRationalEdgeParameters) = new TLRationalBundle(e.bundle)
  def render(e: TLRationalEdgeParameters) = RenderedEdge(colour = "#00ff00" /* green */)

  override def mixO(pd: TLRationalClientPortParameters, node: OutwardNode[TLRationalClientPortParameters, TLRationalManagerPortParameters, TLRationalBundle]): TLRationalClientPortParameters  =
   pd.copy(base = pd.base.v1copy(clients  = pd.base.clients.map  { c => c.v1copy (nodePath = node +: c.nodePath) }))
  override def mixI(pu: TLRationalManagerPortParameters, node: InwardNode[TLRationalClientPortParameters, TLRationalManagerPortParameters, TLRationalBundle]): TLRationalManagerPortParameters =
   pu.copy(base = pu.base.v1copy(managers = pu.base.managers.map { m => m.v1copy (nodePath = node +: m.nodePath) }))
}

case class TLRationalAdapterNode(
  clientFn:  TLRationalClientPortParameters  => TLRationalClientPortParameters  = { s => s },
  managerFn: TLRationalManagerPortParameters => TLRationalManagerPortParameters = { s => s })(
  implicit valName: ValName)
  extends AdapterNode(TLRationalImp)(clientFn, managerFn) with TLRationalFormatNode

case class TLRationalIdentityNode()(implicit valName: ValName) extends IdentityNode(TLRationalImp)() with TLRationalFormatNode

object TLRationalNameNode {
  def apply(name: ValName) = TLRationalIdentityNode()(name)
  def apply(name: Option[String]): TLRationalIdentityNode = apply(ValName(name.getOrElse("with_no_name")))
  def apply(name: String): TLRationalIdentityNode = apply(Some(name))
}

case class TLRationalSourceNode()(implicit valName: ValName)
  extends MixedAdapterNode(TLImp, TLRationalImp)(
    dFn = { p => TLRationalClientPortParameters(p) },
    uFn = { p => p.base.v1copy(minLatency = 1) }) with FormatNode[TLEdgeIn, TLRationalEdgeParameters] // discard cycles from other clock domain
case class TLRationalSinkNode(direction: RationalDirection)(implicit valName: ValName)
  extends MixedAdapterNode(TLRationalImp, TLImp)(

    uFn = { p => TLRationalManagerPortParameters(direction, p) }) with FormatNode[TLRationalEdgeParameters, TLEdgeOut]

// Credited version of TileLink channels

trait TLCreditedFormatNode extends FormatNode[TLCreditedEdgeParameters, TLCreditedEdgeParameters]

object TLCreditedImp extends SimpleNodeImp[TLCreditedClientPortParameters, TLCreditedManagerPortParameters, TLCreditedEdgeParameters, TLCreditedBundle]
{
  def edge(pd: TLCreditedClientPortParameters, pu: TLCreditedManagerPortParameters, p: Parameters, sourceInfo: SourceInfo) = TLCreditedEdgeParameters(pd, pu, p, sourceInfo)
  def bundle(e: TLCreditedEdgeParameters) = new TLCreditedBundle(e.bundle)
  def render(e: TLCreditedEdgeParameters) = RenderedEdge(colour = "#ffff00" /* yellow */, e.delay.toString)

  override def mixO(pd: TLCreditedClientPortParameters, node: OutwardNode[TLCreditedClientPortParameters, TLCreditedManagerPortParameters, TLCreditedBundle]): TLCreditedClientPortParameters  =
   pd.copy(base = pd.base.v1copy(clients  = pd.base.clients.map  { c => c.v1copy (nodePath = node +: c.nodePath) }))
  override def mixI(pu: TLCreditedManagerPortParameters, node: InwardNode[TLCreditedClientPortParameters, TLCreditedManagerPortParameters, TLCreditedBundle]): TLCreditedManagerPortParameters =
   pu.copy(base = pu.base.v1copy(managers = pu.base.managers.map { m => m.v1copy (nodePath = node +: m.nodePath) }))
}

case class TLCreditedAdapterNode(
  clientFn:  TLCreditedClientPortParameters  => TLCreditedClientPortParameters  = { s => s },
  managerFn: TLCreditedManagerPortParameters => TLCreditedManagerPortParameters = { s => s })(
  implicit valName: ValName)
  extends AdapterNode(TLCreditedImp)(clientFn, managerFn) with TLCreditedFormatNode

case class TLCreditedIdentityNode()(implicit valName: ValName) extends IdentityNode(TLCreditedImp)() with TLCreditedFormatNode

object TLCreditedNameNode {
  def apply(name: ValName) = TLCreditedIdentityNode()(name)
  def apply(name: Option[String]): TLCreditedIdentityNode = apply(ValName(name.getOrElse("with_no_name")))
  def apply(name: String): TLCreditedIdentityNode = apply(Some(name))
}

case class TLCreditedSourceNode(delay: TLCreditedDelay)(implicit valName: ValName)
  extends MixedAdapterNode(TLImp, TLCreditedImp)(
    dFn = { p => TLCreditedClientPortParameters(delay, p) },
    uFn = { p => p.base.v1copy(minLatency = 1) }) with FormatNode[TLEdgeIn, TLCreditedEdgeParameters] // discard cycles from other clock domain

case class TLCreditedSinkNode(delay: TLCreditedDelay)(implicit valName: ValName)
  extends MixedAdapterNode(TLCreditedImp, TLImp)(
    dFn = { p => p.base.v1copy(minLatency = 1) },
    uFn = { p => TLCreditedManagerPortParameters(delay, p) }) with FormatNode[TLCreditedEdgeParameters, TLEdgeOut]


// See LICENSE.SiFive for license details.

package freechips.rocketchip.util

import chisel3._
import chisel3.util.{HasBlackBoxResource, HasBlackBoxPath}
import org.chipsalliance.cde.config.{Field, Parameters}

import java.nio.file.{Files, Paths}

case object ClockGateImpl extends Field[() => ClockGate](() => new EICG_wrapper)
case object ClockGateModelFile extends Field[Option[String]](None)

abstract class ClockGate extends BlackBox
  with HasBlackBoxResource with HasBlackBoxPath {
  val io = IO(new Bundle{
    val in = Input(Clock())
    val test_en = Input(Bool())
    val en = Input(Bool())
    val out = Output(Clock())
  })

  def addVerilogResource(vsrc: String): Unit = {
    if (Files.exists(Paths.get(vsrc)))
      addPath(vsrc)
    else
      addResource(vsrc)
  }
}

object ClockGate {
  def apply[T <: ClockGate](
      in: Clock,
      en: Bool,
      name: Option[String] = None)(implicit p: Parameters): Clock = {
    val cg = Module(p(ClockGateImpl)())
    name.foreach(cg.suggestName(_))
    p(ClockGateModelFile).map(cg.addVerilogResource(_))

    cg.io.in := in
    cg.io.test_en := false.B
    cg.io.en := en
    cg.io.out
  }

  def apply[T <: ClockGate](
      in: Clock,
      en: Bool,
      name: String)(implicit p: Parameters): Clock =
    apply(in, en, Some(name))
}

// behavioral model of Integrated Clock Gating cell


// See LICENSE.Berkeley for license details.
// See LICENSE.SiFive for license details.

package freechips.rocketchip.util

import chisel3._

// this bundle is used to expose some internal core signals
// to verification monitors which sample instruction commits

  val wrenx = Bool()
  val wrenf = Bool()
  @deprecated("replace wren with wrenx or wrenf to specify integer or floating point","Rocket Chip 2020.05")
  def wren: Bool = wrenx || wrenf
  val rd0src = UInt(width = 5.W)
  val rd0val = UInt(width = xLen.W)
  val rd1src = UInt(width = 5.W)
  val rd1val = UInt(width = xLen.W)
  val inst = UInt(width = 32.W)
}

// mark a module that has cores with CoreMonitorBundles
trait HasCoreMonitorBundles {
    def coreMonitorBundles: List[CoreMonitorBundle]
}

class CoreMonitorBundle(val xLen: Int, val fLen: Int) extends Bundle with Clocked {
  val excpt = Bool()
  val priv_mode = UInt(width = 3.W)
  val hartid = UInt(width = xLen.W)
  val timer = UInt(width = 32.W)


// See LICENSE.Berkeley for license details.
// See LICENSE.SiFive for license details.

package freechips.rocketchip.util

import chisel3.{Data, SyncReadMem, Vec}
import chisel3.util.log2Ceil

object DescribedSRAM {
  def apply[T <: Data](
    name: String,
    desc: String,
    size: BigInt, // depth
    data: T
  ): SyncReadMem[T] = {

    val mem = SyncReadMem(size, data)

    mem.suggestName(name)

    val granWidth = data match {


// Copyright 2021-2023 The Regents of the University of California
// released under BSD 3-Clause License
// author: Kevin Laeufer <laeufer@cs.berkeley.edu>

package chiseltest.coverage

import firrtl2._
import firrtl2.annotations._
import firrtl2.options.Dependency
import firrtl2.stage.Forms
import firrtl2.stage.TransformManager.TransformDependency

import scala.collection.mutable

case class FsmCoverageAnnotation(
  stateReg:    ReferenceTarget,
  states:      Seq[(String, ReferenceTarget)],
  transitions: Seq[((String, String), ReferenceTarget)])
    extends MultiTargetAnnotation
    with CoverageInfo {
  override def targets = Seq(Seq(stateReg)) ++ states.map(s => Seq(s._2)) ++ transitions.map(t => Seq(t._2))

  override def duplicate(n: Seq[Seq[Target]]) = {
    assert(n.length == 1 + states.length + transitions.length)
    n.foreach(e => assert(e.length == 1, "Cover points and state registers should not be split up!"))
    val targets = n.map(_.head.asInstanceOf[ReferenceTarget])
    val r = copy(
      stateReg = targets.head,
      states = states.map(_._1).zip(targets.slice(1, states.length + 1)),
      transitions = transitions.map(_._1).zip(targets.drop(1 + states.length))
    )
    r
  }
}

case object SkipFsmCoverageAnnotation extends NoTargetAnnotation

object FsmCoveragePass extends Transform {
  val Prefix = "f"

  override def prerequisites: Seq[TransformDependency] =
    Forms.LowForm ++ Seq(Dependency(FsmInfoPass), Dependency(RegisterResetAnnotationPass))
  override def invalidates(a: Transform): Boolean = false

  override def execute(state: CircuitState): CircuitState = {
    if (state.annotations.contains(SkipFsmCoverageAnnotation)) {
      logger.info("[FsmCoverage] skipping due to SkipFsmCoverage annotation")
      return state
    }

    // collect FSMs in modules that are not ignored
    val ignoreMods = Coverage.collectModulesToIgnore(state)
    val infos = state.annotations.collect { case a: FsmInfoAnnotation if !ignoreMods(a.target.module) => a }

    // if there are no FSMs there is nothing to do
    if (infos.isEmpty) return state

    // instrument FSMs
    val registerResets = state.annotations.collect { case a: RegisterResetAnnotation => a }
    val newAnnos = mutable.ListBuffer[Annotation]()
    val c = CircuitTarget(state.circuit.main)
    val circuit = state.circuit.mapModule(onModule(_, c, newAnnos, infos, registerResets))
    state.copy(circuit = circuit, annotations = newAnnos.toList ++ state.annotations)
  }

  private def onModule(
    m:      ir.DefModule,
    c:      CircuitTarget,
    annos:  mutable.ListBuffer[Annotation],
    infos:  Seq[FsmInfoAnnotation],
    resets: Seq[RegisterResetAnnotation]
  ): ir.DefModule = m match {
    case mod: ir.Module =>
      val fsms = infos.filter(_.target.module == mod.name)
      if (fsms.isEmpty) { mod }
      else {
        val isFsm = fsms.map(_.target.ref).toSet
        val fsmRegs = findFsmRegs(mod.body, isFsm)
        val stmts = new mutable.ListBuffer[ir.Statement]()
        val ctx = ModuleCtx(c.module(mod.name), stmts, Namespace(mod))
        val toReset = RegisterResetAnnotationPass.findResetsInModule(ctx.m, resets)
        val fsmAnnos = fsms.map { f => onFsm(f, fsmRegs.find(_.name == f.target.ref).get, ctx, toReset.get) }
        annos ++= fsmAnnos
        val newBody = ir.Block(mod.body +: stmts.toList)

        mod.copy(body = newBody)
      }
    case other => other
  }

  private case class ModuleCtx(m: ModuleTarget, stmts: mutable.ListBuffer[ir.Statement], namespace: Namespace)

  private def onFsm(fsm: FsmInfoAnnotation, reg: ir.DefRegister, ctx: ModuleCtx, toReset: String => Option[String])
    : Annotation = {
    val info = reg.info
    val clock = reg.clock
    val reset = toReset(reg.name).map(ir.Reference(_, Utils.BoolType, NodeKind, SourceFlow)).getOrElse(Utils.False())
    val notReset = Utils.not(reset)
    val regRef = ir.Reference(reg)
    val regWidth = firrtl2.bitWidth(reg.tpe)
    def inState(s: BigInt): ir.Expression = Utils.eq(regRef, ir.UIntLiteral(s, ir.IntWidth(regWidth)))

    // cover state when FSM is _not_ in reset
    val states = fsm.states.map { case (id, stateName) =>
      val name = ctx.namespace.newName(reg.name + "_" + stateName)
      ctx.stmts.append(ir.Verification(ir.Formal.Cover, info, clock, inState(id), notReset, ir.StringLit(""), name))
      stateName -> ctx.m.ref(name)
    }

    // create a register to hold the previous state
    val prevState =
      Builder.makeRegister(ctx.stmts, info, ctx.namespace.newName(reg.name + "_prev"), reg.tpe, clock, regRef)

    // create a register to track if the previous state is valid
    val prevValid = Builder.makeRegister(
      ctx.stmts,
      info,
      ctx.namespace.newName(reg.name + "_prev_valid"),
      Utils.BoolType,
      clock,
      notReset
    )

    // create a transition valid signal
    val transitionValid = ir.Reference(ctx.namespace.newName(reg.name + "_t_valid"), Utils.BoolType, NodeKind)
    ctx.stmts.append(ir.DefNode(info, transitionValid.name, Utils.and(notReset, prevValid)))

    val idToName = fsm.states.toMap
    val transitions = fsm.transitions.map { case (from, to) =>
      val (fromName, toName) = (idToName(from), idToName(to))
      val name = ctx.namespace.newName(reg.name + "_" + fromName + "_to_" + toName)
      ctx.stmts.append(
        ir.Verification(
          ir.Formal.Cover,
          info,
          clock,
          Utils.and(inPrevState(from), inState(to)),
          transitionValid,
          ir.StringLit(""),
          name
        )
      )
      (fromName, toName) -> ctx.m.ref(name)
    }

    FsmCoverageAnnotation(ctx.m.ref(reg.name), states, transitions)
  }

  private def printFsmInfo(fsm: FsmInfoAnnotation): Unit = {
    val toName = fsm.states.toMap
    println(s"[${fsm.target.module}.${fsm.target.name}] Found FSM")
    if (fsm.start.nonEmpty) {
      println(s"Start: ${toName(fsm.start.get)}")
    }
    println("Transitions:")
    fsm.transitions.foreach(t => println(s"${toName(t._1)} -> ${toName(t._2)}"))
  }

  private def findFsmRegs(s: ir.Statement, isFsm: String => Boolean): Seq[ir.DefRegister] = s match {
    case r: ir.DefRegister if isFsm(r.name) => List(r)
    case ir.Block(stmts) => stmts.flatMap(findFsmRegs(_, isFsm))
    case _: ir.Conditionally => throw new RuntimeException("Unexpected when statement! Expected LoFirrtl.")
    case _ => List()
  }
}

def inPrevState(s: BigInt): ir.Expression = Utils.eq(prevState, ir.UIntLiteral(s, ir.IntWidth(regWidth)))


package chiseltest.simulator

import chiseltest.simulator.jna.JNAUtils

import java.io.{File, FileInputStream, FileOutputStream, PrintWriter}
import scala.io.Source

private object BlackBox {

  /** add the `.f` file containing the names of all blackbox verilog files, if it exists */
  def fFileFlags(targetDir: os.Path): Seq[String] = {
    val fFile = targetDir / firrtl2.transforms.BlackBoxSourceHelper.defaultFileListName
    if (os.exists(fFile)) {
      if (JNAUtils.isWindows) {
        // The canonical path on Windows contains backslashes that
        // verilator does not recognize
        // We need to transform backslashes to slashes

        val writer = new PrintWriter(windowsfFile)
        val source = Source.fromFile(fFile.toString())
        source.getLines().foreach(line => writer.println(line.replace("\\", "/")))
        source.close()
        writer.close()
        Seq("-f", windowsfFile)
      } else {
        Seq("-f", fFile.toString())
      }
    } else { Seq() }
  }
}

val windowsfFile = s"${fFile.toString()}.win"