418 lines
12 KiB
Scala
418 lines
12 KiB
Scala
// See LICENSE.SiFive for license details.
|
|
|
|
package rocketchip
|
|
|
|
import Chisel._
|
|
import config._
|
|
import coreplex._
|
|
import diplomacy._
|
|
import tile.XLen
|
|
import uncore.tilelink2._
|
|
import uncore.axi4._
|
|
import uncore.converters._
|
|
import uncore.devices._
|
|
import uncore.util._
|
|
import util._
|
|
import scala.math.{min,max}
|
|
|
|
/** Specifies the size of external memory */
|
|
case class MasterConfig(base: Long, size: Long, beatBytes: Int, idBits: Int)
|
|
case object ExtMem extends Field[MasterConfig]
|
|
case object ExtBus extends Field[MasterConfig]
|
|
case class SlaveConfig(beatBytes: Int, idBits: Int, sourceBits: Int)
|
|
case object ExtIn extends Field[SlaveConfig]
|
|
/** Specifies the number of external interrupts */
|
|
case object NExtTopInterrupts extends Field[Int]
|
|
/** Source of RTC. First bundle is TopIO.extra, Second bundle is periphery.io.extra **/
|
|
case object RTCPeriod extends Field[Int]
|
|
/* Specifies the periphery bus configuration */
|
|
case object PeripheryBusConfig extends Field[TLBusConfig]
|
|
case object PeripheryBusArithmetic extends Field[Boolean]
|
|
/* Specifies the SOC-bus configuration */
|
|
case object SOCBusConfig extends Field[TLBusConfig]
|
|
/* Specifies the location of the Zero device */
|
|
case class ZeroConfig(base: Long, size: Long, beatBytes: Int)
|
|
case object ZeroConfig extends Field[ZeroConfig]
|
|
/* Specifies the location of the Error device */
|
|
case class ErrorConfig(address: Seq[AddressSet])
|
|
case object ErrorConfig extends Field[ErrorConfig]
|
|
|
|
/** Utility trait for quick access to some relevant parameters */
|
|
trait HasPeripheryParameters {
|
|
implicit val p: Parameters
|
|
def peripheryBusConfig = p(PeripheryBusConfig)
|
|
def peripheryBusBytes = peripheryBusConfig.beatBytes
|
|
def socBusConfig = p(SOCBusConfig)
|
|
def socBusBytes = socBusConfig.beatBytes
|
|
def cacheBlockBytes = p(CacheBlockBytes)
|
|
def peripheryBusArithmetic = p(PeripheryBusArithmetic)
|
|
def nMemoryChannels = p(coreplex.BankedL2Config).nMemoryChannels
|
|
}
|
|
|
|
/////
|
|
abstract trait PeripheryExtInterrupts {
|
|
this: HasTopLevelNetworks =>
|
|
|
|
private val device = new Device with DeviceInterrupts {
|
|
def describe(resources: ResourceBindings): Description = {
|
|
Description("soc/offchip-interrupts", describeInterrupts(resources))
|
|
}
|
|
}
|
|
|
|
val nExtInterrupts = p(NExtTopInterrupts)
|
|
val extInterrupts = IntInternalInputNode(IntSourcePortSimple(num = nExtInterrupts, resources = device.int))
|
|
|
|
}
|
|
|
|
trait PeripheryExtInterruptsBundle {
|
|
this: HasTopLevelNetworksBundle {
|
|
val outer: PeripheryExtInterrupts
|
|
} =>
|
|
val interrupts = UInt(INPUT, width = outer.nExtInterrupts)
|
|
}
|
|
|
|
trait PeripheryExtInterruptsModule {
|
|
this: HasTopLevelNetworksModule {
|
|
val outer: PeripheryExtInterrupts
|
|
val io: PeripheryExtInterruptsBundle
|
|
} =>
|
|
outer.extInterrupts.bundleIn.flatten.zipWithIndex.foreach { case(o, i) => o := io.interrupts(i) }
|
|
}
|
|
|
|
// This trait should be used if the External Interrupts have NOT
|
|
// already been synchronized
|
|
// to the Periphery (PLIC) Clock.
|
|
|
|
trait PeripheryAsyncExtInterrupts extends PeripheryExtInterrupts {
|
|
this: HasTopLevelNetworks =>
|
|
|
|
if (nExtInterrupts > 0) {
|
|
val extInterruptXing = LazyModule(new IntXing)
|
|
intBus.intnode := extInterruptXing.intnode
|
|
extInterruptXing.intnode := extInterrupts
|
|
}
|
|
|
|
}
|
|
|
|
// This trait can be used if the External Interrupts have already been synchronized
|
|
// to the Periphery (PLIC) Clock.
|
|
|
|
trait PeripherySyncExtInterrupts extends PeripheryExtInterrupts {
|
|
this: HasTopLevelNetworks =>
|
|
|
|
if (nExtInterrupts > 0) {
|
|
intBus.intnode := extInterrupts
|
|
}
|
|
}
|
|
|
|
/////
|
|
|
|
|
|
trait PeripheryMasterAXI4Mem {
|
|
this: HasTopLevelNetworks =>
|
|
val module: PeripheryMasterAXI4MemModule
|
|
|
|
private val config = p(ExtMem)
|
|
private val channels = p(BankedL2Config).nMemoryChannels
|
|
private val lineBytes = p(CacheBlockBytes)
|
|
|
|
private val device = new MemoryDevice
|
|
|
|
val mem_axi4 = AXI4BlindOutputNode(Seq.tabulate(channels) { channel =>
|
|
val base = AddressSet(config.base, config.size-1)
|
|
val filter = AddressSet(channel * lineBytes, ~((channels-1) * lineBytes))
|
|
|
|
AXI4SlavePortParameters(
|
|
slaves = Seq(AXI4SlaveParameters(
|
|
address = base.intersect(filter).toList,
|
|
resources = device.reg,
|
|
regionType = RegionType.UNCACHED, // cacheable
|
|
executable = true,
|
|
supportsWrite = TransferSizes(1, 256), // The slave supports 1-256 byte transfers
|
|
supportsRead = TransferSizes(1, 256),
|
|
interleavedId = Some(0))), // slave does not interleave read responses
|
|
beatBytes = config.beatBytes)
|
|
})
|
|
|
|
private val converter = LazyModule(new TLToAXI4(config.idBits))
|
|
private val buffer = LazyModule(new AXI4Buffer)
|
|
|
|
mem foreach { case xbar =>
|
|
converter.node := xbar.node
|
|
buffer.node := converter.node
|
|
mem_axi4 := buffer.node
|
|
}
|
|
}
|
|
|
|
trait PeripheryMasterAXI4MemBundle {
|
|
this: HasTopLevelNetworksBundle {
|
|
val outer: PeripheryMasterAXI4Mem
|
|
} =>
|
|
val mem_axi4 = outer.mem_axi4.bundleOut
|
|
}
|
|
|
|
trait PeripheryMasterAXI4MemModule {
|
|
this: HasTopLevelNetworksModule {
|
|
val outer: PeripheryMasterAXI4Mem
|
|
val io: PeripheryMasterAXI4MemBundle
|
|
} =>
|
|
}
|
|
|
|
/////
|
|
|
|
trait PeripheryZero {
|
|
this: HasTopLevelNetworks =>
|
|
val module: PeripheryZeroModule
|
|
|
|
private val config = p(ZeroConfig)
|
|
private val address = AddressSet(config.base, config.size-1)
|
|
private val lineBytes = p(CacheBlockBytes)
|
|
|
|
val zeros = mem map { case xbar =>
|
|
val zero = LazyModule(new TLZero(address, beatBytes = config.beatBytes))
|
|
zero.node := TLFragmenter(config.beatBytes, lineBytes)(xbar.node)
|
|
zero
|
|
}
|
|
}
|
|
|
|
trait PeripheryZeroBundle {
|
|
this: HasTopLevelNetworksBundle {
|
|
val outer: PeripheryZero
|
|
} =>
|
|
}
|
|
|
|
trait PeripheryZeroModule {
|
|
this: HasTopLevelNetworksModule {
|
|
val outer: PeripheryZero
|
|
val io: PeripheryZeroBundle
|
|
} =>
|
|
}
|
|
|
|
/////
|
|
|
|
// PeripheryMasterAXI4MMIO is an example, make your own cake pattern like this one.
|
|
trait PeripheryMasterAXI4MMIO {
|
|
this: HasTopLevelNetworks =>
|
|
|
|
private val config = p(ExtBus)
|
|
private val device = new SimpleDevice("mmio", Nil)
|
|
val mmio_axi4 = AXI4BlindOutputNode(Seq(AXI4SlavePortParameters(
|
|
slaves = Seq(AXI4SlaveParameters(
|
|
address = List(AddressSet(BigInt(config.base), config.size-1)),
|
|
resources = device.reg,
|
|
executable = true, // Can we run programs on this memory?
|
|
supportsWrite = TransferSizes(1, 256), // The slave supports 1-256 byte transfers
|
|
supportsRead = TransferSizes(1, 256))),
|
|
beatBytes = config.beatBytes)))
|
|
|
|
mmio_axi4 :=
|
|
AXI4Buffer()(
|
|
AXI4Deinterleaver(cacheBlockBytes)(
|
|
TLToAXI4(idBits = config.idBits)( // use idBits = 0 for AXI4-Lite
|
|
TLWidthWidget(socBusConfig.beatBytes)( // convert width before attaching to socBus
|
|
socBus.node))))
|
|
}
|
|
|
|
trait PeripheryMasterAXI4MMIOBundle {
|
|
this: HasTopLevelNetworksBundle {
|
|
val outer: PeripheryMasterAXI4MMIO
|
|
} =>
|
|
val mmio_axi4 = outer.mmio_axi4.bundleOut
|
|
}
|
|
|
|
trait PeripheryMasterAXI4MMIOModule {
|
|
this: HasTopLevelNetworksModule {
|
|
val outer: PeripheryMasterAXI4MMIO
|
|
val io: PeripheryMasterAXI4MMIOBundle
|
|
} =>
|
|
// nothing to do
|
|
}
|
|
|
|
/////
|
|
|
|
// PeripherySlaveAXI4 is an example, make your own cake pattern like this one.
|
|
trait PeripherySlaveAXI4 extends HasTopLevelNetworks {
|
|
private val config = p(ExtIn)
|
|
val l2FrontendAXI4Node = AXI4BlindInputNode(Seq(AXI4MasterPortParameters(
|
|
masters = Seq(AXI4MasterParameters(
|
|
id = IdRange(0, 1 << config.idBits))))))
|
|
|
|
private val fifoBits = 1
|
|
fsb.node :=
|
|
TLWidthWidget(config.beatBytes)(
|
|
AXI4ToTL()(
|
|
AXI4UserYanker(1 << (config.sourceBits - fifoBits - 1))(
|
|
AXI4Fragmenter()(
|
|
AXI4IdIndexer(fifoBits)(
|
|
l2FrontendAXI4Node)))))
|
|
}
|
|
|
|
trait PeripherySlaveAXI4Bundle extends HasTopLevelNetworksBundle {
|
|
val outer: PeripherySlaveAXI4
|
|
val l2_frontend_bus_axi4 = outer.l2FrontendAXI4Node.bundleIn
|
|
}
|
|
|
|
trait PeripherySlaveAXI4Module extends HasTopLevelNetworksModule {
|
|
val outer: PeripherySlaveAXI4
|
|
val io: PeripherySlaveAXI4Bundle
|
|
// nothing to do
|
|
}
|
|
|
|
/////
|
|
|
|
// Add an external TL-UL slave
|
|
trait PeripheryMasterTLMMIO {
|
|
this: HasTopLevelNetworks =>
|
|
|
|
private val config = p(ExtBus)
|
|
private val device = new SimpleDevice("mmio", Nil)
|
|
val mmio_tl = TLBlindOutputNode(Seq(TLManagerPortParameters(
|
|
managers = Seq(TLManagerParameters(
|
|
address = List(AddressSet(BigInt(config.base), config.size-1)),
|
|
resources = device.reg,
|
|
executable = true,
|
|
supportsGet = TransferSizes(1, cacheBlockBytes),
|
|
supportsPutFull = TransferSizes(1, cacheBlockBytes),
|
|
supportsPutPartial = TransferSizes(1, cacheBlockBytes))),
|
|
beatBytes = config.beatBytes)))
|
|
|
|
mmio_tl :=
|
|
TLBuffer()(
|
|
TLSourceShrinker(1 << config.idBits)(
|
|
TLWidthWidget(socBusConfig.beatBytes)(
|
|
socBus.node)))
|
|
}
|
|
|
|
trait PeripheryMasterTLMMIOBundle {
|
|
this: HasTopLevelNetworksBundle {
|
|
val outer: PeripheryMasterTLMMIO
|
|
} =>
|
|
val mmio_tl = outer.mmio_tl.bundleOut
|
|
}
|
|
|
|
trait PeripheryMasterTLMMIOModule {
|
|
this: HasTopLevelNetworksModule {
|
|
val outer: PeripheryMasterTLMMIO
|
|
val io: PeripheryMasterTLMMIOBundle
|
|
} =>
|
|
// nothing to do
|
|
}
|
|
|
|
/////
|
|
|
|
// NOTE: this port is NOT allowed to issue Acquires
|
|
trait PeripherySlaveTL extends HasTopLevelNetworks {
|
|
private val config = p(ExtIn)
|
|
val l2FrontendTLNode = TLBlindInputNode(Seq(TLClientPortParameters(
|
|
clients = Seq(TLClientParameters(
|
|
sourceId = IdRange(0, 1 << config.idBits))))))
|
|
|
|
fsb.node :=
|
|
TLSourceShrinker(1 << config.sourceBits)(
|
|
TLWidthWidget(config.beatBytes)(
|
|
l2FrontendTLNode))
|
|
}
|
|
|
|
trait PeripherySlaveTLBundle extends HasTopLevelNetworksBundle {
|
|
val outer: PeripherySlaveTL
|
|
val l2_frontend_bus_tl = outer.l2FrontendTLNode.bundleIn
|
|
}
|
|
|
|
trait PeripherySlaveTLModule extends HasTopLevelNetworksModule {
|
|
val outer: PeripherySlaveTL
|
|
val io: PeripherySlaveTLBundle
|
|
// nothing to do
|
|
}
|
|
|
|
/////
|
|
|
|
trait PeripheryBootROM {
|
|
this: HasTopLevelNetworks =>
|
|
val coreplex: CoreplexRISCVPlatform
|
|
|
|
private val bootrom_address = 0x10000
|
|
private val bootrom_size = 0x10000
|
|
private lazy val bootrom_contents = GenerateBootROM(coreplex.dtb)
|
|
val bootrom = LazyModule(new TLROM(bootrom_address, bootrom_size, bootrom_contents, true, peripheryBusConfig.beatBytes))
|
|
bootrom.node := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
|
|
}
|
|
|
|
trait PeripheryBootROMBundle {
|
|
this: HasTopLevelNetworksBundle {
|
|
val outer: PeripheryBootROM
|
|
} =>
|
|
}
|
|
|
|
trait PeripheryBootROMModule {
|
|
this: HasTopLevelNetworksModule {
|
|
val outer: PeripheryBootROM
|
|
val io: PeripheryBootROMBundle
|
|
} =>
|
|
}
|
|
|
|
/////
|
|
|
|
trait PeripheryTestRAM {
|
|
this: HasTopLevelNetworks =>
|
|
|
|
val testram = LazyModule(new TLRAM(AddressSet(0x52000000, 0xfff), true, peripheryBusConfig.beatBytes))
|
|
testram.node := TLFragmenter(peripheryBusConfig.beatBytes, cacheBlockBytes)(peripheryBus.node)
|
|
}
|
|
|
|
trait PeripheryTestRAMBundle {
|
|
this: HasTopLevelNetworksBundle {
|
|
val outer: PeripheryTestRAM
|
|
} =>
|
|
}
|
|
|
|
trait PeripheryTestRAMModule {
|
|
this: HasTopLevelNetworksModule {
|
|
val outer: PeripheryTestRAM
|
|
val io: PeripheryTestRAMBundle
|
|
} =>
|
|
}
|
|
|
|
/////
|
|
|
|
trait PeripheryTestBusMaster {
|
|
this: HasTopLevelNetworks =>
|
|
val fuzzer = LazyModule(new TLFuzzer(5000))
|
|
peripheryBus.node := fuzzer.node
|
|
}
|
|
|
|
trait PeripheryTestBusMasterBundle {
|
|
this: HasTopLevelNetworksBundle {
|
|
val outer: PeripheryTestBusMaster
|
|
} =>
|
|
}
|
|
|
|
trait PeripheryTestBusMasterModule {
|
|
this: HasTopLevelNetworksModule {
|
|
val outer: PeripheryTestBusMaster
|
|
val io: PeripheryTestBusMasterBundle
|
|
} =>
|
|
}
|
|
|
|
/////
|
|
|
|
trait PeripheryErrorSlave {
|
|
this: HasTopLevelNetworks =>
|
|
private val config = p(ErrorConfig)
|
|
private val maxXfer = min(config.address.map(_.alignment).max.toInt, 4096)
|
|
val error = LazyModule(new TLError(config.address, peripheryBusConfig.beatBytes))
|
|
error.node := TLFragmenter(peripheryBusConfig.beatBytes, maxXfer)(peripheryBus.node)
|
|
}
|
|
|
|
trait PeripheryErrorSlaveBundle {
|
|
this: HasTopLevelNetworksBundle {
|
|
val outer: PeripheryErrorSlave
|
|
} =>
|
|
}
|
|
|
|
trait PeripheryErrorSlaveModule {
|
|
this: HasTopLevelNetworksModule {
|
|
val outer: PeripheryErrorSlave
|
|
val io: PeripheryErrorSlaveBundle
|
|
} =>
|
|
}
|