commit
198a2d7022
2
chisel3
2
chisel3
@ -1 +1 @@
|
||||
Subproject commit 2ff229dac5f915e7f583cbf9cc8118674a4e52a5
|
||||
Subproject commit dda64c1dee16b5da15ac690bd3cd6759c3d5c032
|
@ -146,7 +146,7 @@ class BaseCoreplexConfig extends Config (
|
||||
else new MESICoherence(site(L2DirectoryRepresentation))),
|
||||
nManagers = site(NBanksPerMemoryChannel)*site(NMemoryChannels) + 1 /* MMIO */,
|
||||
nCachingClients = site(NCachedTileLinkPorts),
|
||||
nCachelessClients = site(NCoreplexExtClients).get + site(NUncachedTileLinkPorts),
|
||||
nCachelessClients = site(NCoreplexExtClients) + site(NUncachedTileLinkPorts),
|
||||
maxClientXacts = max_int(
|
||||
// L1 cache
|
||||
site(DCacheKey).nMSHRs + 1 /* IOMSHR */,
|
||||
@ -177,7 +177,7 @@ class BaseCoreplexConfig extends Config (
|
||||
TileLinkParameters(
|
||||
coherencePolicy = new MICoherence(
|
||||
new NullRepresentation(site(NBanksPerMemoryChannel))),
|
||||
nManagers = site(GlobalAddrMap).get.subMap("io").numSlaves,
|
||||
nManagers = 1,
|
||||
nCachingClients = 0,
|
||||
nCachelessClients = 1,
|
||||
maxClientXacts = 4,
|
||||
|
@ -32,7 +32,7 @@ trait HasCoreplexParameters {
|
||||
lazy val innerParams = p.alterPartial({ case TLId => "L1toL2" })
|
||||
lazy val outermostParams = p.alterPartial({ case TLId => "Outermost" })
|
||||
lazy val outermostMMIOParams = p.alterPartial({ case TLId => "MMIO_Outermost" })
|
||||
lazy val globalAddrMap = p(rocketchip.GlobalAddrMap).get
|
||||
lazy val globalAddrMap = p(rocketchip.GlobalAddrMap)
|
||||
}
|
||||
|
||||
case class CoreplexConfig(
|
||||
|
@ -23,11 +23,11 @@ class WithComparator extends Config(
|
||||
case BuildGroundTest =>
|
||||
(p: Parameters) => Module(new ComparatorCore()(p))
|
||||
case ComparatorKey => ComparatorParameters(
|
||||
targets = Seq("mem", "io:ext:testram").map(name =>
|
||||
site(GlobalAddrMap).get(name).start.longValue),
|
||||
targets = Seq("mem", "io:ext:TL2:testram").map(name =>
|
||||
site(GlobalAddrMap)(name).start.longValue),
|
||||
width = 8,
|
||||
operations = 1000,
|
||||
atomics = site(UseAtomics),
|
||||
atomics = false, // !!! re-enable soon: site(UseAtomics),
|
||||
prefetches = site("COMPARATOR_PREFETCHES"))
|
||||
case FPUConfig => None
|
||||
case UseAtomics => false
|
||||
@ -54,7 +54,7 @@ class WithMemtest extends Config(
|
||||
}
|
||||
case GeneratorKey => GeneratorParameters(
|
||||
maxRequests = 128,
|
||||
startAddress = site(GlobalAddrMap).get("mem").start)
|
||||
startAddress = site(GlobalAddrMap)("mem").start)
|
||||
case BuildGroundTest =>
|
||||
(p: Parameters) => Module(new GeneratorTest()(p))
|
||||
case _ => throw new CDEMatchError
|
||||
@ -114,7 +114,7 @@ class WithNastiConverterTest extends Config(
|
||||
}
|
||||
case GeneratorKey => GeneratorParameters(
|
||||
maxRequests = 128,
|
||||
startAddress = site(GlobalAddrMap).get("mem").start)
|
||||
startAddress = site(GlobalAddrMap)("mem").start)
|
||||
case BuildGroundTest =>
|
||||
(p: Parameters) => Module(new NastiConverterTest()(p))
|
||||
case _ => throw new CDEMatchError
|
||||
@ -134,7 +134,7 @@ class WithTraceGen extends Config(
|
||||
val nSets = 32 // L2 NSets
|
||||
val nWays = 1
|
||||
val blockOffset = site(CacheBlockOffsetBits)
|
||||
val baseAddr = site(GlobalAddrMap).get("mem").start
|
||||
val baseAddr = site(GlobalAddrMap)("mem").start
|
||||
val nBeats = site(MIFDataBeats)
|
||||
List.tabulate(4 * nWays) { i =>
|
||||
Seq.tabulate(nBeats) { j => (j * 8) + ((i * nSets) << blockOffset) }
|
||||
@ -157,7 +157,7 @@ class WithPCIeMockupTest extends Config(
|
||||
GroundTestTileSettings(1))
|
||||
case GeneratorKey => GeneratorParameters(
|
||||
maxRequests = 128,
|
||||
startAddress = site(GlobalAddrMap).get("mem").start)
|
||||
startAddress = site(GlobalAddrMap)("mem").start)
|
||||
case BuildGroundTest =>
|
||||
(p: Parameters) => p(TileId) match {
|
||||
case 0 => Module(new GeneratorTest()(p))
|
||||
@ -191,7 +191,7 @@ class WithDirectComparator extends Config(
|
||||
targets = Seq(0L, 0x100L),
|
||||
width = 8,
|
||||
operations = 1000,
|
||||
atomics = site(UseAtomics),
|
||||
atomics = false, // !!! re-enable soon: site(UseAtomics),
|
||||
prefetches = site("COMPARATOR_PREFETCHES"))
|
||||
case FPUConfig => None
|
||||
case UseAtomics => false
|
||||
|
@ -338,7 +338,7 @@ class ComparatorSink(implicit val p: Parameters) extends Module
|
||||
|
||||
assert (g.is_builtin_type, "grant not builtin")
|
||||
assert (base.g_type === g.g_type, "g_type mismatch")
|
||||
assert (base.addr_beat === g.addr_beat || !g.hasData(), "addr_beat mismatch")
|
||||
assert (base.addr_beat === g.addr_beat || !g.hasMultibeatData(), "addr_beat mismatch")
|
||||
assert (base.data === g.data || !g.hasData(), "data mismatch")
|
||||
|
||||
assert_conds.zipWithIndex.foreach { case (cond, i) =>
|
||||
|
@ -72,7 +72,7 @@ class IOGetAfterPutBlockRegression(implicit p: Parameters) extends Regression()(
|
||||
io.mem.grant.ready := Bool(true)
|
||||
|
||||
io.cache.req.valid := !get_sent && started
|
||||
io.cache.req.bits.addr := UInt(addrMap("io:ext:bootrom").start)
|
||||
io.cache.req.bits.addr := UInt(addrMap("io:ext:TL2:bootrom").start)
|
||||
io.cache.req.bits.typ := UInt(log2Ceil(32 / 8))
|
||||
io.cache.req.bits.cmd := M_XRD
|
||||
io.cache.req.bits.tag := UInt(0)
|
||||
|
@ -12,7 +12,7 @@ trait HasAddrMapParameters {
|
||||
implicit val p: Parameters
|
||||
|
||||
val paddrBits = p(PAddrBits)
|
||||
def addrMap = p(rocketchip.GlobalAddrMap).get
|
||||
def addrMap = p(rocketchip.GlobalAddrMap)
|
||||
}
|
||||
|
||||
case class MemAttr(prot: Int, cacheable: Boolean = false)
|
||||
|
@ -20,9 +20,6 @@ import cde.{Parameters, Config, Dump, Knob, CDEMatchError}
|
||||
|
||||
class BasePlatformConfig extends Config(
|
||||
topDefinitions = {
|
||||
val configString = new GlobalVariable[String]
|
||||
val globalAddrMap = new GlobalVariable[AddrMap]
|
||||
val nCoreplexExtClients = new GlobalVariable[Int]
|
||||
(pname,site,here) => {
|
||||
type PF = PartialFunction[Any,Any]
|
||||
def findBy(sname:Any):Any = here[PF](site[Any](sname))(pname)
|
||||
@ -55,7 +52,6 @@ class BasePlatformConfig extends Config(
|
||||
case NExtMMIOTLChannels => 0
|
||||
case AsyncBusChannels => false
|
||||
case NExtBusAXIChannels => 0
|
||||
case NCoreplexExtClients => nCoreplexExtClients
|
||||
case HastiId => "Ext"
|
||||
case HastiKey("TL") =>
|
||||
HastiParameters(
|
||||
@ -69,8 +65,6 @@ class BasePlatformConfig extends Config(
|
||||
case NMemoryChannels => Dump("N_MEM_CHANNELS", 1)
|
||||
case TMemoryChannels => BusType.AXI
|
||||
case ExtMemSize => Dump("MEM_SIZE", 0x10000000L)
|
||||
case ConfigString => configString
|
||||
case GlobalAddrMap => globalAddrMap
|
||||
case RTCPeriod => 100 // gives 10 MHz RTC assuming 1 GHz uncore clock
|
||||
case BuildExampleTop =>
|
||||
(p: Parameters) => uncore.tilelink2.LazyModule(new ExampleTop(p))
|
||||
|
@ -56,6 +56,10 @@ trait HasGeneratorUtilities {
|
||||
}
|
||||
}
|
||||
|
||||
object ConfigStringOutput {
|
||||
var contents: Option[String] = None
|
||||
}
|
||||
|
||||
trait Generator extends App with HasGeneratorUtilities {
|
||||
lazy val names = {
|
||||
require(args.size == 5, "Usage: sbt> " +
|
||||
@ -67,20 +71,25 @@ trait Generator extends App with HasGeneratorUtilities {
|
||||
configProject = args(3),
|
||||
configs = args(4))
|
||||
}
|
||||
|
||||
lazy val td = names.targetDir
|
||||
lazy val config = getConfig(names)
|
||||
lazy val world = config.toInstance
|
||||
lazy val params = Parameters.root(world)
|
||||
lazy val circuit = elaborate(names, params)
|
||||
}
|
||||
lazy val longName = names.topModuleClass + "." + names.configs
|
||||
|
||||
object RocketChipGenerator extends Generator {
|
||||
val longName = names.topModuleClass + "." + names.configs
|
||||
val td = names.targetDir
|
||||
Driver.dumpFirrtl(circuit, Some(new File(td, s"$longName.fir"))) // FIRRTL
|
||||
def writeOutputFiles() {
|
||||
TestGeneration.addSuite(new RegressionTestSuite(params(RegressionTestNames)))
|
||||
writeOutputFile(td, s"$longName.d", TestGeneration.generateMakefrag) // Coreplex-specific test suites
|
||||
writeOutputFile(td, s"$longName.prm", ParameterDump.getDump) // Parameters flagged with Dump()
|
||||
writeOutputFile(td, s"${names.configs}.knb", world.getKnobs) // Knobs for DSE
|
||||
writeOutputFile(td, s"${names.configs}.cst", world.getConstraints) // Constraints for DSE
|
||||
writeOutputFile(td, s"${names.configs}.cfg", params(ConfigString).get) // String for software
|
||||
ConfigStringOutput.contents.foreach(c => writeOutputFile(td, s"${names.configs}.cfg", c)) // String for software
|
||||
}
|
||||
}
|
||||
|
||||
object RocketChipGenerator extends Generator {
|
||||
Driver.dumpFirrtl(circuit, Some(new File(td, s"$longName.fir"))) // FIRRTL
|
||||
writeOutputFiles()
|
||||
}
|
||||
|
@ -7,11 +7,13 @@ import cde.{Parameters, Field}
|
||||
import junctions._
|
||||
import junctions.NastiConstants._
|
||||
import uncore.tilelink._
|
||||
import uncore.tilelink2.{LazyModule, LazyModuleImp}
|
||||
import uncore.tilelink2._
|
||||
import uncore.converters._
|
||||
import uncore.devices._
|
||||
import uncore.util._
|
||||
import rocket.Util._
|
||||
import rocket.XLen
|
||||
import scala.math.max
|
||||
import coreplex._
|
||||
|
||||
/** Options for memory bus interface */
|
||||
@ -202,10 +204,10 @@ trait PeripheryMasterMMIOModule extends HasPeripheryParameters {
|
||||
implicit val p: Parameters
|
||||
val outer: PeripheryMasterMMIO
|
||||
val io: PeripheryMasterMMIOBundle
|
||||
val mmioNetwork: Option[TileLinkRecursiveInterconnect]
|
||||
val mmioNetwork: TileLinkRecursiveInterconnect
|
||||
|
||||
val mmio_ports = p(ExtMMIOPorts) map { port =>
|
||||
TileLinkWidthAdapter(mmioNetwork.get.port(port.name), "MMIO_Outermost")
|
||||
TileLinkWidthAdapter(mmioNetwork.port(port.name), "MMIO_Outermost")
|
||||
}
|
||||
|
||||
val mmio_axi_start = 0
|
||||
@ -278,11 +280,19 @@ trait PeripherySlaveModule extends HasPeripheryParameters {
|
||||
/////
|
||||
|
||||
/** Always-ON block */
|
||||
trait PeripheryAON extends LazyModule {
|
||||
trait PeripheryAON extends LazyModule with HasPeripheryParameters {
|
||||
implicit val p: Parameters
|
||||
val pDevices: ResourceManager[AddrMapEntry]
|
||||
val peripheryBus: TLXbar
|
||||
|
||||
pDevices.add(AddrMapEntry("prci", MemSize(0x4000000, MemAttr(AddrMapProt.RW))))
|
||||
// PRCI must be at least XLen in size for atomicity
|
||||
val beatBytes = max(innerMMIOParams(XLen)/8, 4)
|
||||
val prci = LazyModule(new PRCI(PRCIConfig(beatBytes))(innerMMIOParams))
|
||||
// The periphery bus is 32-bit, so we may need to adapt PRCI's width
|
||||
prci.node := TLFragmenter(TLWidthWidget(peripheryBus.node, 4), beatBytes, 256)
|
||||
|
||||
// TL1 legacy
|
||||
val pDevices: ResourceManager[AddrMapEntry]
|
||||
pDevices.add(AddrMapEntry("prci", MemRange(prci.base, prci.size, MemAttr(AddrMapProt.RW))))
|
||||
}
|
||||
|
||||
trait PeripheryAONBundle {
|
||||
@ -293,21 +303,23 @@ trait PeripheryAONModule extends HasPeripheryParameters {
|
||||
implicit val p: Parameters
|
||||
val outer: PeripheryAON
|
||||
val io: PeripheryAONBundle
|
||||
val mmioNetwork: Option[TileLinkRecursiveInterconnect]
|
||||
val coreplex: Coreplex
|
||||
|
||||
val prci = Module(new PRCI()(innerMMIOParams))
|
||||
prci.io.rtcTick := Counter(p(RTCPeriod)).inc()
|
||||
prci.io.tl <> mmioNetwork.get.port("prci")
|
||||
coreplex.io.prci <> prci.io.tiles
|
||||
outer.prci.module.io.rtcTick := Counter(p(RTCPeriod)).inc()
|
||||
coreplex.io.prci <> outer.prci.module.io.tiles
|
||||
}
|
||||
|
||||
/////
|
||||
|
||||
trait PeripheryBootROM extends LazyModule {
|
||||
implicit val p: Parameters
|
||||
val pDevices: ResourceManager[AddrMapEntry]
|
||||
val peripheryBus: TLXbar
|
||||
|
||||
val rom = LazyModule(new TLROM(0x1000, 0x1000, GenerateBootROM(p)))
|
||||
rom.node := TLFragmenter(peripheryBus.node, 4, 256)
|
||||
|
||||
// TL1 legacy address map
|
||||
val pDevices: ResourceManager[AddrMapEntry]
|
||||
pDevices.add(AddrMapEntry("bootrom", MemRange(0x1000, 4096, MemAttr(AddrMapProt.RX))))
|
||||
}
|
||||
|
||||
@ -319,20 +331,23 @@ trait PeripheryBootROMModule extends HasPeripheryParameters {
|
||||
implicit val p: Parameters
|
||||
val outer: PeripheryBootROM
|
||||
val io: PeripheryBootROMBundle
|
||||
val mmioNetwork: Option[TileLinkRecursiveInterconnect]
|
||||
|
||||
val bootROM = Module(new ROMSlave(GenerateBootROM(p))(innerMMIOParams))
|
||||
bootROM.io <> mmioNetwork.get.port("bootrom")
|
||||
}
|
||||
|
||||
/////
|
||||
|
||||
trait PeripheryTestRAM extends LazyModule {
|
||||
implicit val p: Parameters
|
||||
val pDevices: ResourceManager[AddrMapEntry]
|
||||
val peripheryBus: TLXbar
|
||||
|
||||
val ramBase = 0x52000000
|
||||
val ramSize = 0x1000
|
||||
pDevices.add(AddrMapEntry("testram", MemSize(ramSize, MemAttr(AddrMapProt.RW))))
|
||||
|
||||
val sram = LazyModule(new TLRAM(AddressSet(ramBase, ramSize-1)))
|
||||
sram.node := TLFragmenter(peripheryBus.node, 4, 256)
|
||||
|
||||
// TL1 legacy address map
|
||||
val pDevices: ResourceManager[AddrMapEntry]
|
||||
pDevices.add(AddrMapEntry("testram", MemRange(ramBase, ramSize, MemAttr(AddrMapProt.RW))))
|
||||
}
|
||||
|
||||
trait PeripheryTestRAMBundle {
|
||||
@ -342,22 +357,16 @@ trait PeripheryTestRAMBundle {
|
||||
trait PeripheryTestRAMModule extends HasPeripheryParameters {
|
||||
implicit val p: Parameters
|
||||
val outer: PeripheryTestRAM
|
||||
val io: PeripheryTestRAMBundle
|
||||
val mmioNetwork: Option[TileLinkRecursiveInterconnect]
|
||||
|
||||
val testram = Module(new TileLinkTestRAM(outer.ramSize)(innerMMIOParams))
|
||||
testram.io <> mmioNetwork.get.port("testram")
|
||||
}
|
||||
|
||||
/////
|
||||
|
||||
trait PeripheryTestBusMaster extends LazyModule {
|
||||
implicit val p: Parameters
|
||||
val pBusMasters: RangeManager
|
||||
val pDevices: ResourceManager[AddrMapEntry]
|
||||
val peripheryBus: TLXbar
|
||||
|
||||
pBusMasters.add("busmaster", 1)
|
||||
pDevices.add(AddrMapEntry("busmaster", MemSize(4096, MemAttr(AddrMapProt.RW))))
|
||||
val fuzzer = LazyModule(new TLFuzzer(5000))
|
||||
peripheryBus.node := fuzzer.node
|
||||
}
|
||||
|
||||
trait PeripheryTestBusMasterBundle {
|
||||
@ -367,16 +376,4 @@ trait PeripheryTestBusMasterBundle {
|
||||
trait PeripheryTestBusMasterModule {
|
||||
implicit val p: Parameters
|
||||
val outer: PeripheryTestBusMaster
|
||||
val io: PeripheryTestBusMasterBundle
|
||||
val mmioNetwork: Option[TileLinkRecursiveInterconnect]
|
||||
val coreplex: Coreplex
|
||||
|
||||
val busmaster = Module(new groundtest.ExampleBusMaster()(p))
|
||||
busmaster.io.mmio <> mmioNetwork.get.port("busmaster")
|
||||
|
||||
{
|
||||
val r = outer.pBusMasters.range("busmaster")
|
||||
require(r._2 - r._1 == 1, "RangeManager should return 1 slot")
|
||||
coreplex.io.slave(r._1) <> busmaster.io.mem
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ class WithGroundTest extends Config(
|
||||
else new MESICoherence(site(L2DirectoryRepresentation))),
|
||||
nManagers = site(NBanksPerMemoryChannel)*site(NMemoryChannels) + 1,
|
||||
nCachingClients = site(NCachedTileLinkPorts),
|
||||
nCachelessClients = site(NCoreplexExtClients).get + site(NUncachedTileLinkPorts),
|
||||
nCachelessClients = site(NCoreplexExtClients) + site(NUncachedTileLinkPorts),
|
||||
maxClientXacts = ((site(DCacheKey).nMSHRs + 1) +:
|
||||
site(GroundTestKey).map(_.maxXacts))
|
||||
.reduce(max(_, _)),
|
||||
|
@ -11,11 +11,12 @@ import junctions.NastiConstants._
|
||||
case object BuildExampleTop extends Field[Parameters => ExampleTop]
|
||||
case object SimMemLatency extends Field[Int]
|
||||
|
||||
class TestHarness(implicit val p: Parameters) extends Module with HasAddrMapParameters {
|
||||
class TestHarness(q: Parameters) extends Module {
|
||||
val io = new Bundle {
|
||||
val success = Bool(OUTPUT)
|
||||
}
|
||||
val dut = p(BuildExampleTop)(p).module
|
||||
val dut = q(BuildExampleTop)(q).module
|
||||
implicit val p = dut.p
|
||||
|
||||
// This test harness isn't especially flexible yet
|
||||
require(dut.io.mem_clk.isEmpty)
|
||||
@ -33,7 +34,7 @@ class TestHarness(implicit val p: Parameters) extends Module with HasAddrMapPara
|
||||
int := false
|
||||
|
||||
if (dut.io.mem_axi.nonEmpty) {
|
||||
val memSize = addrMap("mem").size
|
||||
val memSize = p(GlobalAddrMap)("mem").size
|
||||
require(memSize % dut.io.mem_axi.size == 0)
|
||||
for (axi <- dut.io.mem_axi) {
|
||||
val mem = Module(new SimAXIMem(memSize / dut.io.mem_axi.size))
|
||||
|
@ -6,7 +6,7 @@ import Chisel._
|
||||
import cde.{Parameters, Field}
|
||||
import junctions._
|
||||
import uncore.tilelink._
|
||||
import uncore.tilelink2.{LazyModule, LazyModuleImp}
|
||||
import uncore.tilelink2._
|
||||
import uncore.devices._
|
||||
import util.ParameterizedBundle
|
||||
import rocket._
|
||||
@ -14,18 +14,41 @@ import rocket.Util._
|
||||
import coreplex._
|
||||
|
||||
// the following parameters will be refactored properly with TL2
|
||||
case object GlobalAddrMap extends Field[GlobalVariable[AddrMap]]
|
||||
case object ConfigString extends Field[GlobalVariable[String]]
|
||||
case object NCoreplexExtClients extends Field[GlobalVariable[Int]]
|
||||
case object GlobalAddrMap extends Field[AddrMap]
|
||||
case object ConfigString extends Field[String]
|
||||
case object NCoreplexExtClients extends Field[Int]
|
||||
/** Function for building Coreplex */
|
||||
case object BuildCoreplex extends Field[(Parameters, CoreplexConfig) => Coreplex]
|
||||
|
||||
/** Base Top with no Periphery */
|
||||
abstract class BaseTop(val p: Parameters) extends LazyModule {
|
||||
abstract class BaseTop(q: Parameters) extends LazyModule {
|
||||
// the following variables will be refactored properly with TL2
|
||||
val pInterrupts = new RangeManager
|
||||
val pBusMasters = new RangeManager
|
||||
val pDevices = new ResourceManager[AddrMapEntry]
|
||||
|
||||
lazy val c = CoreplexConfig(
|
||||
nTiles = q(NTiles),
|
||||
nExtInterrupts = pInterrupts.sum,
|
||||
nSlaves = pBusMasters.sum,
|
||||
nMemChannels = q(NMemoryChannels),
|
||||
hasSupervisor = q(UseVM),
|
||||
hasExtMMIOPort = true
|
||||
)
|
||||
|
||||
lazy val genGlobalAddrMap = GenerateGlobalAddrMap(q, pDevices.get)
|
||||
private val qWithMap = q.alterPartial({case GlobalAddrMap => genGlobalAddrMap})
|
||||
|
||||
lazy val genConfigString = GenerateConfigString(qWithMap, c, pDevices.get)
|
||||
implicit val p = qWithMap.alterPartial({
|
||||
case ConfigString => genConfigString
|
||||
case NCoreplexExtClients => pBusMasters.sum})
|
||||
|
||||
// Add a peripheral bus
|
||||
val peripheryBus = LazyModule(new TLXbar)
|
||||
val legacy = LazyModule(new TLLegacy()(p.alterPartial({ case TLId => "L2toMMIO" })))
|
||||
|
||||
peripheryBus.node := TLBuffer(TLWidthWidget(TLHintHandler(legacy.node), legacy.tlDataBytes))
|
||||
}
|
||||
|
||||
class BaseTopBundle(val p: Parameters, val c: Coreplex) extends ParameterizedBundle()(p) {
|
||||
@ -35,24 +58,19 @@ class BaseTopBundle(val p: Parameters, val c: Coreplex) extends ParameterizedBun
|
||||
class BaseTopModule[+L <: BaseTop, +B <: BaseTopBundle](val p: Parameters, l: L, b: Coreplex => B) extends LazyModuleImp(l) {
|
||||
val outer: L = l
|
||||
|
||||
val c = CoreplexConfig(
|
||||
nTiles = p(NTiles),
|
||||
nExtInterrupts = outer.pInterrupts.sum,
|
||||
nSlaves = outer.pBusMasters.sum,
|
||||
nMemChannels = p(NMemoryChannels),
|
||||
hasSupervisor = p(UseVM),
|
||||
hasExtMMIOPort = !(outer.pDevices.get.isEmpty && p(ExtMMIOPorts).isEmpty)
|
||||
)
|
||||
val coreplex = p(BuildCoreplex)(p, outer.c)
|
||||
val io: B = b(coreplex)
|
||||
|
||||
def genGlobalAddrMap = GenerateGlobalAddrMap(p, outer.pDevices.get)
|
||||
def genConfigString = GenerateConfigString(p, c, outer.pDevices.get)
|
||||
io.success zip coreplex.io.success map { case (x, y) => x := y }
|
||||
|
||||
p(NCoreplexExtClients).assign(outer.pBusMasters.sum)
|
||||
p(GlobalAddrMap).assign(genGlobalAddrMap)
|
||||
p(ConfigString).assign(genConfigString)
|
||||
val mmioNetwork =
|
||||
Module(new TileLinkRecursiveInterconnect(1, p(GlobalAddrMap).subMap("io:ext"))(
|
||||
p.alterPartial({ case TLId => "L2toMMIO" })))
|
||||
mmioNetwork.io.in.head <> coreplex.io.master.mmio.get
|
||||
outer.legacy.module.io.legacy <> mmioNetwork.port("TL2")
|
||||
|
||||
println("Generated Address Map")
|
||||
for (entry <- p(GlobalAddrMap).get.flatten) {
|
||||
for (entry <- p(GlobalAddrMap).flatten) {
|
||||
val name = entry.name
|
||||
val start = entry.region.start
|
||||
val end = entry.region.start + entry.region.size - 1
|
||||
@ -60,21 +78,12 @@ class BaseTopModule[+L <: BaseTop, +B <: BaseTopBundle](val p: Parameters, l: L,
|
||||
}
|
||||
|
||||
println("Generated Configuration String")
|
||||
println(p(ConfigString).get)
|
||||
|
||||
val coreplex = p(BuildCoreplex)(p, c)
|
||||
val io: B = b(coreplex)
|
||||
|
||||
io.success zip coreplex.io.success map { case (x, y) => x := y }
|
||||
|
||||
val mmioNetwork = c.hasExtMMIOPort.option(
|
||||
Module(new TileLinkRecursiveInterconnect(1, p(GlobalAddrMap).get.subMap("io:ext"))(
|
||||
p.alterPartial({ case TLId => "L2toMMIO" }))))
|
||||
mmioNetwork.foreach { _.io.in.head <> coreplex.io.master.mmio.get }
|
||||
println(p(ConfigString))
|
||||
ConfigStringOutput.contents = Some(p(ConfigString))
|
||||
}
|
||||
|
||||
/** Example Top with Periphery */
|
||||
class ExampleTop(p: Parameters) extends BaseTop(p)
|
||||
class ExampleTop(q: Parameters) extends BaseTop(q)
|
||||
with PeripheryBootROM with PeripheryDebug with PeripheryExtInterrupts with PeripheryAON
|
||||
with PeripheryMasterMem with PeripheryMasterMMIO with PeripherySlave {
|
||||
override lazy val module = Module(new ExampleTopModule(p, this, new ExampleTopBundle(p, _)))
|
||||
@ -89,7 +98,7 @@ class ExampleTopModule[+L <: ExampleTop, +B <: ExampleTopBundle](p: Parameters,
|
||||
with PeripheryMasterMemModule with PeripheryMasterMMIOModule with PeripherySlaveModule
|
||||
|
||||
/** Example Top with TestRAM */
|
||||
class ExampleTopWithTestRAM(p: Parameters) extends ExampleTop(p)
|
||||
class ExampleTopWithTestRAM(q: Parameters) extends ExampleTop(q)
|
||||
with PeripheryTestRAM {
|
||||
override lazy val module = Module(new ExampleTopWithTestRAMModule(p, this, new ExampleTopWithTestRAMBundle(p, _)))
|
||||
}
|
||||
|
@ -36,10 +36,10 @@ class UnitTestHarness(implicit val p: Parameters) extends Module {
|
||||
val success = Bool(OUTPUT)
|
||||
}
|
||||
|
||||
p(NCoreplexExtClients).assign(0)
|
||||
p(ConfigString).assign("")
|
||||
|
||||
val l1params = p.alterPartial({ case TLId => "L1toL2" })
|
||||
val l1params = p.alterPartial({
|
||||
case NCoreplexExtClients => 0
|
||||
case ConfigString => ""
|
||||
case TLId => "L1toL2" })
|
||||
val tests = Module(new UnitTestSuite()(l1params))
|
||||
|
||||
io.success := tests.io.finished
|
||||
|
@ -64,10 +64,8 @@ object GenerateGlobalAddrMap {
|
||||
new AddrMap(entries)
|
||||
}
|
||||
|
||||
lazy val extIOAddrMap = new AddrMap(
|
||||
pDevicesEntries ++ p(ExtMMIOPorts),
|
||||
start = BigInt("50000000", 16),
|
||||
collapse = true)
|
||||
lazy val tl2AddrMap = new AddrMap(pDevicesEntries, collapse = true)
|
||||
lazy val extIOAddrMap = new AddrMap(AddrMapEntry("TL2", tl2AddrMap) +: p(ExtMMIOPorts), collapse = true)
|
||||
|
||||
val memBase = 0x80000000L
|
||||
val memSize = p(ExtMemSize)
|
||||
@ -83,9 +81,9 @@ object GenerateGlobalAddrMap {
|
||||
|
||||
object GenerateConfigString {
|
||||
def apply(p: Parameters, c: CoreplexConfig, pDevicesEntries: Seq[AddrMapEntry]) = {
|
||||
val addrMap = p(GlobalAddrMap).get
|
||||
val addrMap = p(GlobalAddrMap)
|
||||
val plicAddr = addrMap("io:int:plic").start
|
||||
val prciAddr = addrMap("io:ext:prci").start
|
||||
val prciAddr = addrMap("io:ext:TL2:prci").start
|
||||
val xLen = p(XLen)
|
||||
val res = new StringBuilder
|
||||
res append "plic {\n"
|
||||
@ -138,7 +136,7 @@ object GenerateConfigString {
|
||||
}
|
||||
res append "};\n"
|
||||
pDevicesEntries foreach { entry =>
|
||||
val region = addrMap("io:ext:" + entry.name)
|
||||
val region = addrMap("io:ext:TL2:" + entry.name)
|
||||
res append s"${entry.name} {\n"
|
||||
res append s" addr 0x${region.start.toString(16)};\n"
|
||||
res append s" size 0x${region.size.toString(16)}; \n"
|
||||
@ -158,8 +156,8 @@ object GenerateBootROM {
|
||||
|
||||
// for now, have the reset vector jump straight to memory
|
||||
val memBase = (
|
||||
if (p(GlobalAddrMap).get contains "mem") p(GlobalAddrMap).get("mem")
|
||||
else p(GlobalAddrMap).get("io:int:dmem0")
|
||||
if (p(GlobalAddrMap) contains "mem") p(GlobalAddrMap)("mem")
|
||||
else p(GlobalAddrMap)("io:int:dmem0")
|
||||
).start
|
||||
val resetToMemDist = memBase - p(ResetVector)
|
||||
require(resetToMemDist == (resetToMemDist.toInt >> 12 << 12))
|
||||
@ -168,6 +166,6 @@ object GenerateBootROM {
|
||||
require(rom.getInt(12) == 0,
|
||||
"Config string address position should not be occupied by code")
|
||||
rom.putInt(12, configStringAddr)
|
||||
rom.array() ++ (p(ConfigString).get.getBytes.toSeq)
|
||||
rom.array() ++ (p(ConfigString).getBytes.toSeq)
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,9 @@ import Chisel._
|
||||
import rocket.Util._
|
||||
import junctions._
|
||||
import junctions.NastiConstants._
|
||||
import uncore.tilelink._
|
||||
import uncore.tilelink2._
|
||||
import uncore.util._
|
||||
import scala.math.{min,max}
|
||||
import cde.{Parameters, Field}
|
||||
|
||||
/** Number of tiles */
|
||||
@ -32,45 +33,28 @@ object PRCI {
|
||||
def size = 0xc000
|
||||
}
|
||||
|
||||
/** Power, Reset, Clock, Interrupt */
|
||||
class PRCI(implicit val p: Parameters) extends Module
|
||||
with HasTileLinkParameters
|
||||
with HasAddrMapParameters {
|
||||
val io = new Bundle {
|
||||
val tl = new ClientUncachedTileLinkIO().flip
|
||||
case class PRCIConfig(beatBytes: Int, address: BigInt = 0x44000000)
|
||||
|
||||
trait MixPRCIParameters {
|
||||
val params: (PRCIConfig, Parameters)
|
||||
val c = params._1
|
||||
implicit val p = params._2
|
||||
}
|
||||
|
||||
trait PRCIBundle extends Bundle with MixPRCIParameters {
|
||||
val tiles = Vec(p(NTiles), new PRCITileIO)
|
||||
val rtcTick = Bool(INPUT)
|
||||
}
|
||||
}
|
||||
|
||||
trait PRCIModule extends Module with HasRegMap with MixPRCIParameters {
|
||||
val io: PRCIBundle
|
||||
|
||||
val timeWidth = 64
|
||||
val timecmp = Reg(Vec(p(NTiles), UInt(width = timeWidth)))
|
||||
val time = Reg(init=UInt(0, timeWidth))
|
||||
val time = Reg(init=UInt(0, width = timeWidth))
|
||||
when (io.rtcTick) { time := time + UInt(1) }
|
||||
|
||||
val ipi = Reg(init=Vec.fill(p(NTiles))(UInt(0, 32)))
|
||||
|
||||
val acq = Queue(io.tl.acquire, 1)
|
||||
val addr = acq.bits.full_addr()(log2Ceil(PRCI.size)-1,0)
|
||||
val read = acq.bits.isBuiltInType(Acquire.getType)
|
||||
val rdata = Wire(init=UInt(0))
|
||||
io.tl.grant.valid := acq.valid
|
||||
acq.ready := io.tl.grant.ready
|
||||
io.tl.grant.bits := Grant(
|
||||
is_builtin_type = Bool(true),
|
||||
g_type = acq.bits.getBuiltInGrantType(),
|
||||
client_xact_id = acq.bits.client_xact_id,
|
||||
manager_xact_id = UInt(0),
|
||||
addr_beat = UInt(0),
|
||||
data = rdata)
|
||||
|
||||
when (addr(log2Floor(PRCI.time))) {
|
||||
require(log2Floor(PRCI.timecmp(p(NTiles)-1)) < log2Floor(PRCI.time))
|
||||
rdata := store(Seq(time), acq.bits, io.tl.grant.fire())
|
||||
}.elsewhen (addr >= PRCI.timecmp(0)) {
|
||||
rdata := store(timecmp, acq.bits, io.tl.grant.fire())
|
||||
}.otherwise {
|
||||
rdata := store(ipi, acq.bits, io.tl.grant.fire()) & Fill(tlDataBits/32, UInt(1, 32))
|
||||
}
|
||||
val timecmp = Seq.fill(p(NTiles)) { Reg(UInt(width = timeWidth)) }
|
||||
val ipi = Seq.fill(p(NTiles)) { RegInit(UInt(0, width = 1)) }
|
||||
|
||||
for ((tile, i) <- io.tiles zipWithIndex) {
|
||||
tile.interrupts.msip := ipi(i)(0)
|
||||
@ -78,42 +62,40 @@ class PRCI(implicit val p: Parameters) extends Module
|
||||
tile.reset := reset
|
||||
}
|
||||
|
||||
// TODO generalize these to help other TL slaves
|
||||
def load(v: Seq[UInt], acq: Acquire): UInt = {
|
||||
val w = v.head.getWidth
|
||||
val a = acq.full_addr()
|
||||
require(isPow2(w) && w >= 8)
|
||||
if (w > tlDataBits) {
|
||||
(v(a.extract(log2Ceil(w/8*v.size)-1,log2Ceil(w/8))) >> a.extract(log2Ceil(w/8)-1,log2Ceil(tlDataBytes)))(tlDataBits-1,0)
|
||||
} else {
|
||||
val row: Seq[UInt] = for (i <- 0 until v.size by tlDataBits/w)
|
||||
yield Cat(v.slice(i, i + tlDataBits/w).reverse)
|
||||
if (row.size == 1) row.head
|
||||
else row(a(log2Ceil(w/8*v.size)-1,log2Ceil(tlDataBytes)))
|
||||
}
|
||||
}
|
||||
/* 0000 msip hart 0
|
||||
* 0004 msip hart 1
|
||||
* 4000 mtimecmp hart 0 lo
|
||||
* 4004 mtimecmp hart 0 hi
|
||||
* 4008 mtimecmp hart 1 lo
|
||||
* 400c mtimecmp hart 1 hi
|
||||
* bff8 mtime lo
|
||||
* bffc mtime hi
|
||||
*/
|
||||
|
||||
def store(v: Seq[UInt], acq: Acquire, en: Bool): UInt = {
|
||||
val w = v.head.getWidth
|
||||
require(isPow2(w) && w >= 8)
|
||||
val a = acq.full_addr()
|
||||
val rdata = load(v, acq)
|
||||
val wdata = (acq.data & acq.full_wmask()) | (rdata & ~acq.full_wmask())
|
||||
when (en && acq.isBuiltInType(Acquire.putType)) {
|
||||
if (w <= tlDataBits) {
|
||||
val word =
|
||||
if (tlDataBits/w >= v.size) UInt(0)
|
||||
else a(log2Up(w/8*v.size)-1,log2Up(tlDataBytes))
|
||||
for (i <- 0 until v.size) when (word === i/(tlDataBits/w)) {
|
||||
val base = i % (tlDataBits/w)
|
||||
v(i) := wdata >> (w * (i % (tlDataBits/w)))
|
||||
}
|
||||
} else {
|
||||
val i = a.extract(log2Ceil(w/8*v.size)-1,log2Ceil(w/8))
|
||||
val mask = FillInterleaved(tlDataBits, UIntToOH(a.extract(log2Ceil(w/8)-1,log2Ceil(tlDataBytes))))
|
||||
v(i) := (wdata & mask) | (v(i) & ~mask)
|
||||
}
|
||||
}
|
||||
rdata
|
||||
}
|
||||
// laying out IPI fields suck...
|
||||
// bytes=1 -> pad to 7, step 4, group 1
|
||||
// bytes=2 -> pad to 15, step 2, group 1
|
||||
// bytes=4 -> pad to 31, step 1, group 1
|
||||
// bytes=8 -> pad to 31, step 1, group 2
|
||||
// bytes=16-> pad to 31, step 1, group 4
|
||||
val pad = min(c.beatBytes*8,32) - 1
|
||||
val step = max(1, 4/c.beatBytes)
|
||||
val group = max(1, c.beatBytes/4)
|
||||
val ipi_regs = ipi.map { reg => Seq(RegField(1, reg), RegField(pad)) }.flatten.grouped(group*2).
|
||||
zipWithIndex.map { case (fields, i) => (i*step -> fields) }
|
||||
|
||||
// Just split up time fields by bytes
|
||||
val timecmp_regs = timecmp.zipWithIndex.map { case (reg, i) =>
|
||||
RegField.bytes(reg, PRCI.timecmp(i)/c.beatBytes, c.beatBytes)
|
||||
}.flatten
|
||||
val time_reg = RegField.bytes(time, PRCI.time/c.beatBytes, c.beatBytes)
|
||||
|
||||
regmap((timecmp_regs ++ time_reg ++ ipi_regs):_*)
|
||||
}
|
||||
|
||||
/** Power, Reset, Clock, Interrupt */
|
||||
// Magic TL2 Incantation to create a TL2 Slave
|
||||
class PRCI(c: PRCIConfig)(implicit val p: Parameters)
|
||||
extends TLRegisterRouter(c.address, 0, 0x10000, None, c.beatBytes, false)(
|
||||
new TLRegBundle((c, p), _) with PRCIBundle)(
|
||||
new TLRegModule((c, p), _, _) with PRCIModule)
|
||||
|
@ -4,9 +4,46 @@ import Chisel._
|
||||
import unittest.UnitTest
|
||||
import junctions._
|
||||
import uncore.tilelink._
|
||||
import uncore.tilelink2._
|
||||
import uncore.util._
|
||||
import cde.{Parameters, Field}
|
||||
|
||||
class TLROM(val base: BigInt, val size: Int, contentsDelayed: => Seq[Byte], beatBytes: Int = 4) extends LazyModule
|
||||
{
|
||||
val node = TLManagerNode(beatBytes, TLManagerParameters(
|
||||
address = List(AddressSet(base, size-1)),
|
||||
regionType = RegionType.UNCACHED,
|
||||
supportsGet = TransferSizes(1, beatBytes),
|
||||
fifoId = Some(0)))
|
||||
|
||||
lazy val module = new LazyModuleImp(this) {
|
||||
val io = new Bundle {
|
||||
val in = node.bundleIn
|
||||
}
|
||||
|
||||
val contents = contentsDelayed
|
||||
require (contents.size <= size)
|
||||
|
||||
val in = io.in(0)
|
||||
val edge = node.edgesIn(0)
|
||||
|
||||
val words = (contents ++ Seq.fill(size-contents.size)(0.toByte)).grouped(beatBytes).toSeq
|
||||
val bigs = words.map(_.foldRight(BigInt(0)){ case (x,y) => (x.toInt & 0xff) | y << 8})
|
||||
val rom = Vec(bigs.map(x => UInt(x, width = 8*beatBytes)))
|
||||
|
||||
in.d.valid := in.a.valid
|
||||
in.a.ready := in.d.ready
|
||||
|
||||
val index = in.a.bits.addr_hi(log2Ceil(size/beatBytes)-1,0)
|
||||
in.d.bits := edge.AccessAck(in.a.bits, UInt(0), rom(index))
|
||||
|
||||
// Tie off unused channels
|
||||
in.b.valid := Bool(false)
|
||||
in.c.ready := Bool(true)
|
||||
in.e.ready := Bool(true)
|
||||
}
|
||||
}
|
||||
|
||||
class ROMSlave(contents: Seq[Byte])(implicit val p: Parameters) extends Module
|
||||
with HasTileLinkParameters
|
||||
with HasAddrMapParameters {
|
||||
|
118
src/main/scala/uncore/tilelink2/AddressDecoder.scala
Normal file
118
src/main/scala/uncore/tilelink2/AddressDecoder.scala
Normal file
@ -0,0 +1,118 @@
|
||||
// See LICENSE for license details.
|
||||
|
||||
package uncore.tilelink2
|
||||
|
||||
import Chisel._
|
||||
import scala.math.{max,min}
|
||||
|
||||
object AddressDecoder
|
||||
{
|
||||
type Port = Seq[AddressSet]
|
||||
type Ports = Seq[Port]
|
||||
type Partition = Ports
|
||||
type Partitions = Seq[Partition]
|
||||
|
||||
val addressOrder = Ordering.ordered[AddressSet]
|
||||
val portOrder = Ordering.Iterable(addressOrder)
|
||||
val partitionOrder = Ordering.Iterable(portOrder)
|
||||
|
||||
// Find the minimum subset of bits needed to disambiguate port addresses.
|
||||
// ie: inspecting only the bits in the output, you can look at an address
|
||||
// and decide to which port (outer Seq) the address belongs.
|
||||
def apply(ports: Ports): BigInt = if (ports.size <= 1) 0 else {
|
||||
// Every port must have at least one address!
|
||||
ports.foreach { p => require (!p.isEmpty) }
|
||||
// Verify the user did not give us an impossible problem
|
||||
ports.combinations(2).foreach { case Seq(x, y) =>
|
||||
x.foreach { a => y.foreach { b =>
|
||||
require (!a.overlaps(b)) // it must be possible to disambiguate addresses!
|
||||
} }
|
||||
}
|
||||
val maxBits = log2Ceil(ports.map(_.map(_.max).max).max + 1)
|
||||
val bits = (0 until maxBits).map(BigInt(1) << _).toSeq
|
||||
val selected = recurse(Seq(ports.map(_.sorted).sorted(portOrder)), bits)
|
||||
selected.reduceLeft(_ | _)
|
||||
}
|
||||
|
||||
// A simpler version that works for a Seq[Int]
|
||||
def apply(keys: Seq[Int]): Int = {
|
||||
val ports = keys.map(b => Seq(AddressSet(b, 0)))
|
||||
apply(ports).toInt
|
||||
}
|
||||
|
||||
// The algorithm has a set of partitions, discriminated by the selected bits.
|
||||
// Each partion has a set of ports, listing all addresses that lead to that port.
|
||||
// Seq[Seq[Seq[AddressSet]]]
|
||||
// ^^^^^^^^^^^^^^^ set of addresses that are routed out this port
|
||||
// ^^^ the list of ports
|
||||
// ^^^ cases already distinguished by the selected bits thus far
|
||||
//
|
||||
// Solving this problem is NP-hard, so we use a simple greedy heuristic:
|
||||
// pick the bit which minimizes the number of ports in each partition
|
||||
// as a secondary goal, reduce the number of AddressSets within a partition
|
||||
|
||||
val bigValue = 100000
|
||||
def bitScore(partitions: Partitions): Int = {
|
||||
val maxPortsPerPartition = partitions.map(_.size).max
|
||||
val maxSetsPerPartition = partitions.map(_.map(_.size).sum).max
|
||||
maxPortsPerPartition * bigValue + maxSetsPerPartition
|
||||
}
|
||||
|
||||
def partitionPort(port: Port, bit: BigInt): (Port, Port) = {
|
||||
val addr_a = AddressSet(0, ~bit)
|
||||
val addr_b = AddressSet(bit, ~bit)
|
||||
// The addresses were sorted, so the filtered addresses are still sorted
|
||||
val subset_a = port.filter(_.overlaps(addr_a))
|
||||
val subset_b = port.filter(_.overlaps(addr_b))
|
||||
(subset_a, subset_b)
|
||||
}
|
||||
|
||||
def partitionPorts(ports: Ports, bit: BigInt): (Ports, Ports) = {
|
||||
val partitioned_ports = ports.map(p => partitionPort(p, bit))
|
||||
// because partitionPort dropped AddresSets, the ports might no longer be sorted
|
||||
val case_a_ports = partitioned_ports.map(_._1).filter(!_.isEmpty).sorted(portOrder)
|
||||
val case_b_ports = partitioned_ports.map(_._2).filter(!_.isEmpty).sorted(portOrder)
|
||||
(case_a_ports, case_b_ports)
|
||||
}
|
||||
|
||||
def partitionPartitions(partitions: Partitions, bit: BigInt): Partitions = {
|
||||
val partitioned_partitions = partitions.map(p => partitionPorts(p, bit))
|
||||
val case_a_partitions = partitioned_partitions.map(_._1)
|
||||
val case_b_partitions = partitioned_partitions.map(_._2)
|
||||
val new_partitions = (case_a_partitions ++ case_b_partitions).sorted(partitionOrder)
|
||||
// Prevent combinational memory explosion; if two partitions are equal, keep only one
|
||||
// Note: AddressSets in a port are sorted, and ports in a partition are sorted.
|
||||
// This makes it easy to structurally compare two partitions for equality
|
||||
val keep = (new_partitions.init zip new_partitions.tail) filter { case (a,b) => partitionOrder.compare(a,b) != 0 } map { _._2 }
|
||||
new_partitions.head +: keep
|
||||
}
|
||||
|
||||
// requirement: ports have sorted addresses and are sorted lexicographically
|
||||
val debug = false
|
||||
def recurse(partitions: Partitions, bits: Seq[BigInt]): Seq[BigInt] = {
|
||||
if (debug) {
|
||||
println("Partitioning:")
|
||||
partitions.foreach { partition =>
|
||||
println(" Partition:")
|
||||
partition.foreach { port =>
|
||||
print(" ")
|
||||
port.foreach { a => print(s" ${a}") }
|
||||
println("")
|
||||
}
|
||||
}
|
||||
}
|
||||
val candidates = bits.map { bit =>
|
||||
val result = partitionPartitions(partitions, bit)
|
||||
val score = bitScore(result)
|
||||
(score, bit, result)
|
||||
}
|
||||
val (bestScore, bestBit, bestPartitions) = candidates.min(Ordering.by[(Int, BigInt, Partitions), Int](_._1))
|
||||
if (debug) println("=> Selected bit 0x%x".format(bestBit))
|
||||
if (bestScore < 2*bigValue) {
|
||||
if (debug) println("---")
|
||||
Seq(bestBit)
|
||||
} else {
|
||||
bestBit +: recurse(bestPartitions, bits.filter(_ != bestBit))
|
||||
}
|
||||
}
|
||||
}
|
@ -146,7 +146,7 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten
|
||||
val dFragnum = out.d.bits.source(fragmentBits-1, 0)
|
||||
val dFirst = acknum === UInt(0)
|
||||
val dsizeOH = UIntToOH (out.d.bits.size, log2Ceil(maxDownSize)+1)
|
||||
val dsizeOH1 = UIntToOH1(out.d.bits.size, log2Ceil(maxDownSize))
|
||||
val dsizeOH1 = UIntToOH1(out.d.bits.size, log2Up(maxDownSize))
|
||||
val dHasData = edgeOut.hasData(out.d.bits)
|
||||
|
||||
// calculate new acknum
|
||||
@ -209,7 +209,7 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten
|
||||
val aOrig = in.a.bits.size
|
||||
val aFrag = Mux(aOrig > limit, limit, aOrig)
|
||||
val aOrigOH1 = UIntToOH1(aOrig, log2Ceil(maxSize))
|
||||
val aFragOH1 = UIntToOH1(aFrag, log2Ceil(maxDownSize))
|
||||
val aFragOH1 = UIntToOH1(aFrag, log2Up(maxDownSize))
|
||||
val aHasData = node.edgesIn(0).hasData(in.a.bits)
|
||||
val aMask = Mux(aHasData, UInt(0), aFragOH1)
|
||||
|
||||
|
@ -32,22 +32,36 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f
|
||||
val smartManagers = edgeOut.manager.managers.map(_.supportsHint.max == edgeOut.manager.maxTransfer).reduce(_&&_)
|
||||
|
||||
if (supportManagers && !smartManagers) {
|
||||
// State of the Hint bypass
|
||||
val counter = RegInit(UInt(0, width = log2Up(edgeOut.manager.maxTransfer/edgeOut.manager.beatBytes)))
|
||||
val hintHoldsD = RegInit(Bool(false))
|
||||
val outerHoldsD = counter =/= UInt(0)
|
||||
// Only one of them can hold it
|
||||
assert (!hintHoldsD || !outerHoldsD)
|
||||
|
||||
// Count outer D beats
|
||||
val beats1 = edgeOut.numBeats1(out.d.bits)
|
||||
when (out.d.fire()) { counter := Mux(outerHoldsD, counter - UInt(1), beats1) }
|
||||
|
||||
// Who wants what?
|
||||
val address = edgeIn.address(in.a.bits)
|
||||
val handleA = if (passthrough) !edgeOut.manager.supportsHint(address, edgeIn.size(in.a.bits)) else Bool(true)
|
||||
val bypassD = handleA && in.a.bits.opcode === TLMessages.Hint
|
||||
val hintBitsAtA = handleA && in.a.bits.opcode === TLMessages.Hint
|
||||
val hintWantsD = in.a.valid && hintBitsAtA
|
||||
val outerWantsD = out.d.valid
|
||||
|
||||
// Prioritize existing D traffic over HintAck (and finish multibeat xfers)
|
||||
val beats1 = edgeOut.numBeats1(out.d.bits)
|
||||
val counter = RegInit(UInt(0, width = log2Up(edgeOut.manager.maxTransfer/edgeOut.manager.beatBytes)))
|
||||
val first = counter === UInt(0)
|
||||
when (out.d.fire()) { counter := Mux(first, beats1, counter - UInt(1)) }
|
||||
val hintWinsD = hintHoldsD || (!outerHoldsD && !outerWantsD)
|
||||
hintHoldsD := hintWantsD && hintWinsD && !in.d.ready
|
||||
// Hint can only hold D b/c it still wants it from last cycle
|
||||
assert (!hintHoldsD || hintWantsD)
|
||||
|
||||
in.d.valid := out.d.valid || (bypassD && in.a.valid && first)
|
||||
out.d.ready := in.d.ready
|
||||
in.d.bits := Mux(out.d.valid, out.d.bits, edgeIn.HintAck(in.a.bits, edgeOut.manager.findId(address)))
|
||||
in.d.valid := Mux(hintWinsD, hintWantsD, outerWantsD)
|
||||
in.d.bits := Mux(hintWinsD, edgeIn.HintAck(in.a.bits, edgeOut.manager.findId(address)), out.d.bits)
|
||||
out.d.ready := in.d.ready && !hintHoldsD
|
||||
|
||||
in.a.ready := Mux(bypassD, in.d.ready && first && !out.d.valid, out.a.ready)
|
||||
out.a.valid := in.a.valid && !bypassD
|
||||
in.a.ready := Mux(hintBitsAtA, hintWinsD && in.d.ready, out.a.ready)
|
||||
out.a.valid := in.a.valid && !hintBitsAtA
|
||||
out.a.bits := in.a.bits
|
||||
} else {
|
||||
out.a.valid := in.a.valid
|
||||
@ -60,21 +74,35 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f
|
||||
}
|
||||
|
||||
if (supportClients && !smartClients) {
|
||||
// State of the Hint bypass
|
||||
val counter = RegInit(UInt(0, width = log2Up(edgeIn.client.maxTransfer/edgeIn.manager.beatBytes)))
|
||||
val hintHoldsC = RegInit(Bool(false))
|
||||
val innerHoldsC = counter =/= UInt(0)
|
||||
// Only one of them can hold it
|
||||
assert (!hintHoldsC || !innerHoldsC)
|
||||
|
||||
// Count inner C beats
|
||||
val beats1 = edgeIn.numBeats1(in.c.bits)
|
||||
when (in.c.fire()) { counter := Mux(innerHoldsC, counter - UInt(1), beats1) }
|
||||
|
||||
// Who wants what?
|
||||
val handleB = if (passthrough) !edgeIn.client.supportsHint(out.b.bits.source, edgeOut.size(out.b.bits)) else Bool(true)
|
||||
val bypassC = handleB && out.b.bits.opcode === TLMessages.Hint
|
||||
val hintBitsAtB = handleB && out.b.bits.opcode === TLMessages.Hint
|
||||
val hintWantsC = out.b.valid && hintBitsAtB
|
||||
val innerWantsC = in.c.valid
|
||||
|
||||
// Prioritize existing C traffic over HintAck (and finish multibeat xfers)
|
||||
val beats1 = edgeIn.numBeats1(in.c.bits)
|
||||
val counter = RegInit(UInt(0, width = log2Up(edgeIn.client.maxTransfer/edgeIn.manager.beatBytes)))
|
||||
val first = counter === UInt(0)
|
||||
when (in.c.fire()) { counter := Mux(first, beats1, counter - UInt(1)) }
|
||||
val hintWinsC = hintHoldsC || (!innerHoldsC && !innerWantsC)
|
||||
hintHoldsC := hintWantsC && hintWinsC && !out.c.ready
|
||||
// Hint can only hold C b/c it still wants it from last cycle
|
||||
assert (!hintHoldsC || hintWantsC)
|
||||
|
||||
out.c.valid := in.c.valid || (bypassC && in.b.valid && first)
|
||||
in.c.ready := out.c.ready
|
||||
out.c.bits := Mux(in.c.valid, in.c.bits, edgeOut.HintAck(out.b.bits))
|
||||
out.c.valid := Mux(hintWinsC, hintWantsC, innerWantsC)
|
||||
out.c.bits := Mux(hintWinsC, edgeOut.HintAck(out.b.bits), in.c.bits)
|
||||
in.c.ready := out.c.ready && !hintHoldsC
|
||||
|
||||
out.b.ready := Mux(bypassC, out.c.ready && first && !in.c.valid, in.b.ready)
|
||||
in.b.valid := out.b.valid && !bypassC
|
||||
out.b.ready := Mux(hintBitsAtB, hintWinsC && out.c.ready, in.b.ready)
|
||||
in.b.valid := out.b.valid && !hintBitsAtB
|
||||
in.b.bits := out.b.bits
|
||||
} else if (bce) {
|
||||
in.b.valid := out.b.valid
|
||||
|
@ -49,7 +49,7 @@ class TLLegacy(implicit val p: Parameters) extends LazyModule with HasTileLinkPa
|
||||
// During conversion from TL Legacy, we won't support Acquire
|
||||
|
||||
// Must be able to fit TL2 sink_id into TL legacy
|
||||
require ((1 << tlManagerXactIdBits) >= edge.manager.endSinkId)
|
||||
require ((1 << tlManagerXactIdBits) >= edge.manager.endSinkId || !edge.manager.anySupportAcquire)
|
||||
|
||||
val out = io.out(0)
|
||||
out.a.valid := io.legacy.acquire.valid
|
||||
@ -78,6 +78,8 @@ class TLLegacy(implicit val p: Parameters) extends LazyModule with HasTileLinkPa
|
||||
MemoryOpConstants.M_XA_MINU -> edge.Arithmetic(source, address, beat, data, TLAtomics.MINU)._2,
|
||||
MemoryOpConstants.M_XA_MAXU -> edge.Arithmetic(source, address, beat, data, TLAtomics.MAXU)._2))
|
||||
} else {
|
||||
// If no managers support atomics, assert fail if TL1 asks for them
|
||||
assert (!io.legacy.acquire.valid || io.legacy.acquire.bits.a_type =/= Acquire.putAtomicType)
|
||||
Wire(new TLBundleA(edge.bundle))
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,7 @@ class BaseNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(
|
||||
def connectOut = bundleOut
|
||||
def connectIn = bundleIn
|
||||
|
||||
protected[tilelink2] def := (y: BaseNode[PO, PI, EO, EI, B])(implicit sourceInfo: SourceInfo) = {
|
||||
def := (y: BaseNode[PO, PI, EO, EI, B])(implicit sourceInfo: SourceInfo) = {
|
||||
val x = this // x := y
|
||||
val info = sourceLine(sourceInfo, " at ", "")
|
||||
require (!LazyModule.stack.isEmpty, s"${y.name} cannot be connected to ${x.name} outside of LazyModule scope" + info)
|
||||
|
@ -63,7 +63,7 @@ case class TransferSizes(min: Int, max: Int)
|
||||
def contains(x: TransferSizes) = x.none || (min <= x.min && x.max <= max)
|
||||
|
||||
def intersect(x: TransferSizes) =
|
||||
if (x.max < min || min < x.max) TransferSizes.none
|
||||
if (x.max < min || max < x.min) TransferSizes.none
|
||||
else TransferSizes(scala.math.max(min, x.min), scala.math.min(max, x.max))
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ object TransferSizes {
|
||||
// Base is the base address, and mask are the bits consumed by the manager
|
||||
// e.g: base=0x200, mask=0xff describes a device managing 0x200-0x2ff
|
||||
// e.g: base=0x1000, mask=0xf0f decribes a device managing 0x1000-0x100f, 0x1100-0x110f, ...
|
||||
case class AddressSet(base: BigInt, mask: BigInt)
|
||||
case class AddressSet(base: BigInt, mask: BigInt) extends Ordered[AddressSet]
|
||||
{
|
||||
// Forbid misaligned base address (and empty sets)
|
||||
require ((base & mask) == 0)
|
||||
@ -97,12 +97,24 @@ case class AddressSet(base: BigInt, mask: BigInt)
|
||||
|
||||
// A strided slave serves discontiguous ranges
|
||||
def strided = alignment1 != mask
|
||||
|
||||
// AddressSets have one natural Ordering (the containment order)
|
||||
def compare(x: AddressSet) = {
|
||||
val primary = (this.base - x.base).signum // smallest address first
|
||||
val secondary = (x.mask - this.mask).signum // largest mask first
|
||||
if (primary != 0) primary else secondary
|
||||
}
|
||||
|
||||
// We always want to see things in hex
|
||||
override def toString() = "AddressSet(0x%x, 0x%x)".format(base, mask)
|
||||
}
|
||||
|
||||
case class TLManagerParameters(
|
||||
address: Seq[AddressSet],
|
||||
sinkId: IdRange = IdRange(0, 1),
|
||||
regionType: RegionType.T = RegionType.GET_EFFECTS,
|
||||
executable: Boolean = false, // processor can execute from this memory
|
||||
nodePath: Seq[TLBaseNode] = Seq(),
|
||||
// Supports both Acquire+Release+Finish of these sizes
|
||||
supportsAcquire: TransferSizes = TransferSizes.none,
|
||||
supportsArithmetic: TransferSizes = TransferSizes.none,
|
||||
@ -183,6 +195,7 @@ case class TLManagerPortParameters(managers: Seq[TLManagerParameters], beatBytes
|
||||
def findFifoId(address: UInt) = Mux1H(find(address), managers.map(m => UInt(m.fifoId.map(_+1).getOrElse(0))))
|
||||
def hasFifoId(address: UInt) = Mux1H(find(address), managers.map(m => Bool(m.fifoId.isDefined)))
|
||||
|
||||
lazy val addressMask = AddressDecoder(managers.map(_.address))
|
||||
// !!! need a cheaper version of find, where we assume a valid address match exists
|
||||
|
||||
// Does this Port manage this ID/address?
|
||||
@ -208,6 +221,7 @@ case class TLManagerPortParameters(managers: Seq[TLManagerParameters], beatBytes
|
||||
|
||||
case class TLClientParameters(
|
||||
sourceId: IdRange = IdRange(0,1),
|
||||
nodePath: Seq[TLBaseNode] = Seq(),
|
||||
// Supports both Probe+Grant of these sizes
|
||||
supportsProbe: TransferSizes = TransferSizes.none,
|
||||
supportsArithmetic: TransferSizes = TransferSizes.none,
|
||||
|
@ -105,6 +105,23 @@ object RegField
|
||||
bb.d := data
|
||||
Bool(true)
|
||||
}))
|
||||
|
||||
// Split a large register into a sequence of byte fields
|
||||
// The bytes can be individually written, as they are one byte per field
|
||||
def bytes(x: UInt, base: Int = 0, beatBytes: Int = 4): Seq[RegField.Map] = {
|
||||
require (x.getWidth % 8 == 0)
|
||||
Seq.tabulate(x.getWidth/8) { i =>
|
||||
RegField(8, x(8*(i+1)-1, 8*i), RegWriteFn { (valid, data) =>
|
||||
when (valid) {
|
||||
val mask = ~UInt(BigInt(0xff) << 8*i, width = x.getWidth)
|
||||
x := (x & mask) | (data & UInt(0xff)) << 8*i
|
||||
}
|
||||
Bool(true)
|
||||
})
|
||||
}.grouped(beatBytes).toSeq.zipWithIndex.map { case (reg, i) =>
|
||||
(i+base, reg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait HasRegMap
|
||||
|
@ -28,8 +28,8 @@ class RegMapperOutput(params: RegMapperParams) extends GenericParameterizedBundl
|
||||
object RegMapper
|
||||
{
|
||||
// Create a generic register-based device
|
||||
def apply(bytes: Int, concurrency: Option[Int], in: DecoupledIO[RegMapperInput], mapping: RegField.Map*) = {
|
||||
val regmap = mapping.toList
|
||||
def apply(bytes: Int, concurrency: Option[Int], undefZero: Boolean, in: DecoupledIO[RegMapperInput], mapping: RegField.Map*) = {
|
||||
val regmap = mapping.toList.filter(!_._2.isEmpty)
|
||||
require (!regmap.isEmpty)
|
||||
|
||||
// Ensure no register appears twice
|
||||
@ -37,15 +37,31 @@ object RegMapper
|
||||
require (reg1 != reg2)
|
||||
}
|
||||
|
||||
// Flatten the regmap into (Reg:Int, Offset:Int, field:RegField)
|
||||
val flat = regmap.map { case (reg, fields) =>
|
||||
val offsets = fields.scanLeft(0)(_ + _.width).init
|
||||
(offsets zip fields) map { case (o, f) => (reg, o, f) }
|
||||
}.flatten
|
||||
require (!flat.isEmpty)
|
||||
// Convert to and from Bits
|
||||
def toBits(x: Int, tail: List[Boolean] = List.empty): List[Boolean] =
|
||||
if (x == 0) tail.reverse else toBits(x >> 1, ((x & 1) == 1) :: tail)
|
||||
def ofBits(bits: List[Boolean]) = bits.foldRight(0){ case (x,y) => (if (x) 1 else 0) | y << 1 }
|
||||
|
||||
// Find the minimal mask that can decide the register map
|
||||
val mask = AddressDecoder(regmap.map(_._1))
|
||||
val maskFilter = toBits(mask)
|
||||
val maskBits = maskFilter.filter(x => x).size
|
||||
|
||||
// Calculate size and indexes into the register map
|
||||
val endIndex = 1 << log2Ceil(regmap.map(_._1).max+1)
|
||||
val params = RegMapperParams(log2Up(endIndex), bytes, in.bits.params.extraBits)
|
||||
val regSize = 1 << maskBits
|
||||
def regIndexI(x: Int) = ofBits((maskFilter zip toBits(x)).filter(_._1).map(_._2))
|
||||
def regIndexU(x: UInt) = if (maskBits == 0) UInt(0) else
|
||||
Cat((maskFilter zip x.toBools).filter(_._1).map(_._2).reverse)
|
||||
|
||||
// Flatten the regmap into (RegIndex:Int, Offset:Int, field:RegField)
|
||||
val flat = regmap.map { case (reg, fields) =>
|
||||
val offsets = fields.scanLeft(0)(_ + _.width).init
|
||||
val index = regIndexI(reg)
|
||||
// println("mapping 0x%x -> 0x%x for 0x%x/%d".format(reg, index, mask, maskBits))
|
||||
(offsets zip fields) map { case (o, f) => (index, o, f) }
|
||||
}.flatten
|
||||
|
||||
val out = Wire(Irrevocable(new RegMapperOutput(params)))
|
||||
val front = Wire(Irrevocable(new RegMapperInput(params)))
|
||||
@ -69,13 +85,13 @@ object RegMapper
|
||||
val woready = Wire(Vec(flat.size, Bool()))
|
||||
|
||||
// Per-register list of all control signals needed for data to flow
|
||||
val rifire = Array.tabulate(endIndex) { i => Seq(Bool(true)) }
|
||||
val wifire = Array.tabulate(endIndex) { i => Seq(Bool(true)) }
|
||||
val rofire = Array.tabulate(endIndex) { i => Seq(Bool(true)) }
|
||||
val wofire = Array.tabulate(endIndex) { i => Seq(Bool(true)) }
|
||||
val rifire = Array.tabulate(regSize) { i => Seq(Bool(true)) }
|
||||
val wifire = Array.tabulate(regSize) { i => Seq(Bool(true)) }
|
||||
val rofire = Array.tabulate(regSize) { i => Seq(Bool(true)) }
|
||||
val wofire = Array.tabulate(regSize) { i => Seq(Bool(true)) }
|
||||
|
||||
// The output values for each register
|
||||
val dataOut = Array.tabulate(endIndex) { _ => UInt(0) }
|
||||
val dataOut = Array.tabulate(regSize) { _ => UInt(0) }
|
||||
|
||||
// Which bits are touched?
|
||||
val frontMask = FillInterleaved(8, front.bits.mask)
|
||||
@ -110,8 +126,10 @@ object RegMapper
|
||||
val wifireMux = Vec(wifire.map(_.reduce(_ && _)))
|
||||
val rofireMux = Vec(rofire.map(_.reduce(_ && _)))
|
||||
val wofireMux = Vec(wofire.map(_.reduce(_ && _)))
|
||||
val iready = Mux(front.bits.read, rifireMux(front.bits.index), wifireMux(front.bits.index))
|
||||
val oready = Mux(back .bits.read, rofireMux(back .bits.index), wofireMux(back .bits.index))
|
||||
val iindex = regIndexU(front.bits.index)
|
||||
val oindex = regIndexU(back .bits.index)
|
||||
val iready = Mux(front.bits.read, rifireMux(iindex), wifireMux(iindex))
|
||||
val oready = Mux(back .bits.read, rofireMux(oindex), wofireMux(oindex))
|
||||
|
||||
// Connect the pipeline
|
||||
in.ready := front.ready && iready
|
||||
@ -120,11 +138,11 @@ object RegMapper
|
||||
out.valid := back.valid && oready
|
||||
|
||||
// Which register is touched?
|
||||
val frontSel = UIntToOH(front.bits.index)
|
||||
val backSel = UIntToOH(back.bits.index)
|
||||
val frontSel = UIntToOH(iindex)
|
||||
val backSel = UIntToOH(oindex)
|
||||
|
||||
// Include the per-register one-hot selected criteria
|
||||
for (reg <- 0 until endIndex) {
|
||||
for (reg <- 0 until regSize) {
|
||||
rifire(reg) = (in.valid && front.ready && front.bits.read && frontSel(reg)) +: rifire(reg)
|
||||
wifire(reg) = (in.valid && front.ready && !front.bits.read && frontSel(reg)) +: wifire(reg)
|
||||
rofire(reg) = (back.valid && out.ready && back .bits.read && backSel (reg)) +: rofire(reg)
|
||||
@ -141,7 +159,7 @@ object RegMapper
|
||||
}
|
||||
|
||||
out.bits.read := back.bits.read
|
||||
out.bits.data := Vec(dataOut)(back.bits.index)
|
||||
out.bits.data := Vec(dataOut)(oindex)
|
||||
out.bits.extra := back.bits.extra
|
||||
|
||||
(endIndex, out)
|
||||
|
@ -4,7 +4,7 @@ package uncore.tilelink2
|
||||
|
||||
import Chisel._
|
||||
|
||||
class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatBytes: Int = 4)
|
||||
class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatBytes: Int = 4, undefZero: Boolean = true)
|
||||
extends TLManagerNode(beatBytes, TLManagerParameters(
|
||||
address = Seq(address),
|
||||
supportsGet = TransferSizes(1, beatBytes),
|
||||
@ -25,7 +25,7 @@ class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatB
|
||||
val baseEnd = 0
|
||||
val (sizeEnd, sizeOff) = (edge.bundle.sizeBits + baseEnd, baseEnd)
|
||||
val (sourceEnd, sourceOff) = (edge.bundle.sourceBits + sizeEnd, sizeEnd)
|
||||
val (addrLoEnd, addrLoOff) = (log2Ceil(beatBytes) + sourceEnd, sourceEnd)
|
||||
val (addrLoEnd, addrLoOff) = (log2Up(beatBytes) + sourceEnd, sourceEnd)
|
||||
|
||||
val params = RegMapperParams(log2Up(address.mask+1), beatBytes, addrLoEnd)
|
||||
val in = Wire(Decoupled(new RegMapperInput(params)))
|
||||
@ -36,7 +36,7 @@ class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatB
|
||||
in.bits.extra := Cat(edge.addr_lo(a.bits), a.bits.source, a.bits.size)
|
||||
|
||||
// Invoke the register map builder
|
||||
val (endIndex, out) = RegMapper(beatBytes, concurrency, in, mapping:_*)
|
||||
val (endIndex, out) = RegMapper(beatBytes, concurrency, undefZero, in, mapping:_*)
|
||||
|
||||
// All registers must fit inside the device address space
|
||||
require (address.mask >= (endIndex-1)*beatBytes)
|
||||
@ -67,17 +67,17 @@ class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatB
|
||||
|
||||
object TLRegisterNode
|
||||
{
|
||||
def apply(address: AddressSet, concurrency: Option[Int] = None, beatBytes: Int = 4) =
|
||||
new TLRegisterNode(address, concurrency, beatBytes)
|
||||
def apply(address: AddressSet, concurrency: Option[Int] = None, beatBytes: Int = 4, undefZero: Boolean = true) =
|
||||
new TLRegisterNode(address, concurrency, beatBytes, undefZero)
|
||||
}
|
||||
|
||||
// These convenience methods below combine to make it possible to create a TL2
|
||||
// register mapped device from a totally abstract register mapped device.
|
||||
// See GPIO.scala in this directory for an example
|
||||
|
||||
abstract class TLRegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Option[Int], beatBytes: Int) extends LazyModule
|
||||
abstract class TLRegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Option[Int], beatBytes: Int, undefZero: Boolean) extends LazyModule
|
||||
{
|
||||
val node = TLRegisterNode(address, concurrency, beatBytes)
|
||||
val node = TLRegisterNode(address, concurrency, beatBytes, undefZero)
|
||||
val intnode = IntSourceNode(name + s" @ ${address.base}", interrupts)
|
||||
}
|
||||
|
||||
@ -100,10 +100,10 @@ class TLRegModule[P, B <: TLRegBundleBase](val params: P, bundleBuilder: => B, r
|
||||
}
|
||||
|
||||
class TLRegisterRouter[B <: TLRegBundleBase, M <: LazyModuleImp]
|
||||
(base: BigInt, interrupts: Int = 0, size: BigInt = 4096, concurrency: Option[Int] = None, beatBytes: Int = 4)
|
||||
(val base: BigInt, val interrupts: Int = 0, val size: BigInt = 4096, val concurrency: Option[Int] = None, val beatBytes: Int = 4, undefZero: Boolean = true)
|
||||
(bundleBuilder: TLRegBundleArg => B)
|
||||
(moduleBuilder: (=> B, TLRegisterRouterBase) => M)
|
||||
extends TLRegisterRouterBase(AddressSet(base, size-1), interrupts, concurrency, beatBytes)
|
||||
extends TLRegisterRouterBase(AddressSet(base, size-1), interrupts, concurrency, beatBytes, undefZero)
|
||||
{
|
||||
require (isPow2(size))
|
||||
// require (size >= 4096) ... not absolutely required, but highly recommended
|
||||
|
@ -9,6 +9,7 @@ class TLRAM(address: AddressSet, beatBytes: Int = 4) extends LazyModule
|
||||
val node = TLManagerNode(beatBytes, TLManagerParameters(
|
||||
address = List(address),
|
||||
regionType = RegionType.UNCACHED,
|
||||
executable = true,
|
||||
supportsGet = TransferSizes(1, beatBytes),
|
||||
supportsPutPartial = TransferSizes(1, beatBytes),
|
||||
supportsPutFull = TransferSizes(1, beatBytes),
|
||||
|
Loading…
Reference in New Issue
Block a user