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))),
|
else new MESICoherence(site(L2DirectoryRepresentation))),
|
||||||
nManagers = site(NBanksPerMemoryChannel)*site(NMemoryChannels) + 1 /* MMIO */,
|
nManagers = site(NBanksPerMemoryChannel)*site(NMemoryChannels) + 1 /* MMIO */,
|
||||||
nCachingClients = site(NCachedTileLinkPorts),
|
nCachingClients = site(NCachedTileLinkPorts),
|
||||||
nCachelessClients = site(NCoreplexExtClients).get + site(NUncachedTileLinkPorts),
|
nCachelessClients = site(NCoreplexExtClients) + site(NUncachedTileLinkPorts),
|
||||||
maxClientXacts = max_int(
|
maxClientXacts = max_int(
|
||||||
// L1 cache
|
// L1 cache
|
||||||
site(DCacheKey).nMSHRs + 1 /* IOMSHR */,
|
site(DCacheKey).nMSHRs + 1 /* IOMSHR */,
|
||||||
@ -177,7 +177,7 @@ class BaseCoreplexConfig extends Config (
|
|||||||
TileLinkParameters(
|
TileLinkParameters(
|
||||||
coherencePolicy = new MICoherence(
|
coherencePolicy = new MICoherence(
|
||||||
new NullRepresentation(site(NBanksPerMemoryChannel))),
|
new NullRepresentation(site(NBanksPerMemoryChannel))),
|
||||||
nManagers = site(GlobalAddrMap).get.subMap("io").numSlaves,
|
nManagers = 1,
|
||||||
nCachingClients = 0,
|
nCachingClients = 0,
|
||||||
nCachelessClients = 1,
|
nCachelessClients = 1,
|
||||||
maxClientXacts = 4,
|
maxClientXacts = 4,
|
||||||
|
@ -32,7 +32,7 @@ trait HasCoreplexParameters {
|
|||||||
lazy val innerParams = p.alterPartial({ case TLId => "L1toL2" })
|
lazy val innerParams = p.alterPartial({ case TLId => "L1toL2" })
|
||||||
lazy val outermostParams = p.alterPartial({ case TLId => "Outermost" })
|
lazy val outermostParams = p.alterPartial({ case TLId => "Outermost" })
|
||||||
lazy val outermostMMIOParams = p.alterPartial({ case TLId => "MMIO_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(
|
case class CoreplexConfig(
|
||||||
|
@ -23,11 +23,11 @@ class WithComparator extends Config(
|
|||||||
case BuildGroundTest =>
|
case BuildGroundTest =>
|
||||||
(p: Parameters) => Module(new ComparatorCore()(p))
|
(p: Parameters) => Module(new ComparatorCore()(p))
|
||||||
case ComparatorKey => ComparatorParameters(
|
case ComparatorKey => ComparatorParameters(
|
||||||
targets = Seq("mem", "io:ext:testram").map(name =>
|
targets = Seq("mem", "io:ext:TL2:testram").map(name =>
|
||||||
site(GlobalAddrMap).get(name).start.longValue),
|
site(GlobalAddrMap)(name).start.longValue),
|
||||||
width = 8,
|
width = 8,
|
||||||
operations = 1000,
|
operations = 1000,
|
||||||
atomics = site(UseAtomics),
|
atomics = false, // !!! re-enable soon: site(UseAtomics),
|
||||||
prefetches = site("COMPARATOR_PREFETCHES"))
|
prefetches = site("COMPARATOR_PREFETCHES"))
|
||||||
case FPUConfig => None
|
case FPUConfig => None
|
||||||
case UseAtomics => false
|
case UseAtomics => false
|
||||||
@ -54,7 +54,7 @@ class WithMemtest extends Config(
|
|||||||
}
|
}
|
||||||
case GeneratorKey => GeneratorParameters(
|
case GeneratorKey => GeneratorParameters(
|
||||||
maxRequests = 128,
|
maxRequests = 128,
|
||||||
startAddress = site(GlobalAddrMap).get("mem").start)
|
startAddress = site(GlobalAddrMap)("mem").start)
|
||||||
case BuildGroundTest =>
|
case BuildGroundTest =>
|
||||||
(p: Parameters) => Module(new GeneratorTest()(p))
|
(p: Parameters) => Module(new GeneratorTest()(p))
|
||||||
case _ => throw new CDEMatchError
|
case _ => throw new CDEMatchError
|
||||||
@ -114,7 +114,7 @@ class WithNastiConverterTest extends Config(
|
|||||||
}
|
}
|
||||||
case GeneratorKey => GeneratorParameters(
|
case GeneratorKey => GeneratorParameters(
|
||||||
maxRequests = 128,
|
maxRequests = 128,
|
||||||
startAddress = site(GlobalAddrMap).get("mem").start)
|
startAddress = site(GlobalAddrMap)("mem").start)
|
||||||
case BuildGroundTest =>
|
case BuildGroundTest =>
|
||||||
(p: Parameters) => Module(new NastiConverterTest()(p))
|
(p: Parameters) => Module(new NastiConverterTest()(p))
|
||||||
case _ => throw new CDEMatchError
|
case _ => throw new CDEMatchError
|
||||||
@ -134,7 +134,7 @@ class WithTraceGen extends Config(
|
|||||||
val nSets = 32 // L2 NSets
|
val nSets = 32 // L2 NSets
|
||||||
val nWays = 1
|
val nWays = 1
|
||||||
val blockOffset = site(CacheBlockOffsetBits)
|
val blockOffset = site(CacheBlockOffsetBits)
|
||||||
val baseAddr = site(GlobalAddrMap).get("mem").start
|
val baseAddr = site(GlobalAddrMap)("mem").start
|
||||||
val nBeats = site(MIFDataBeats)
|
val nBeats = site(MIFDataBeats)
|
||||||
List.tabulate(4 * nWays) { i =>
|
List.tabulate(4 * nWays) { i =>
|
||||||
Seq.tabulate(nBeats) { j => (j * 8) + ((i * nSets) << blockOffset) }
|
Seq.tabulate(nBeats) { j => (j * 8) + ((i * nSets) << blockOffset) }
|
||||||
@ -157,7 +157,7 @@ class WithPCIeMockupTest extends Config(
|
|||||||
GroundTestTileSettings(1))
|
GroundTestTileSettings(1))
|
||||||
case GeneratorKey => GeneratorParameters(
|
case GeneratorKey => GeneratorParameters(
|
||||||
maxRequests = 128,
|
maxRequests = 128,
|
||||||
startAddress = site(GlobalAddrMap).get("mem").start)
|
startAddress = site(GlobalAddrMap)("mem").start)
|
||||||
case BuildGroundTest =>
|
case BuildGroundTest =>
|
||||||
(p: Parameters) => p(TileId) match {
|
(p: Parameters) => p(TileId) match {
|
||||||
case 0 => Module(new GeneratorTest()(p))
|
case 0 => Module(new GeneratorTest()(p))
|
||||||
@ -191,7 +191,7 @@ class WithDirectComparator extends Config(
|
|||||||
targets = Seq(0L, 0x100L),
|
targets = Seq(0L, 0x100L),
|
||||||
width = 8,
|
width = 8,
|
||||||
operations = 1000,
|
operations = 1000,
|
||||||
atomics = site(UseAtomics),
|
atomics = false, // !!! re-enable soon: site(UseAtomics),
|
||||||
prefetches = site("COMPARATOR_PREFETCHES"))
|
prefetches = site("COMPARATOR_PREFETCHES"))
|
||||||
case FPUConfig => None
|
case FPUConfig => None
|
||||||
case UseAtomics => false
|
case UseAtomics => false
|
||||||
|
@ -338,7 +338,7 @@ class ComparatorSink(implicit val p: Parameters) extends Module
|
|||||||
|
|
||||||
assert (g.is_builtin_type, "grant not builtin")
|
assert (g.is_builtin_type, "grant not builtin")
|
||||||
assert (base.g_type === g.g_type, "g_type mismatch")
|
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 (base.data === g.data || !g.hasData(), "data mismatch")
|
||||||
|
|
||||||
assert_conds.zipWithIndex.foreach { case (cond, i) =>
|
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.mem.grant.ready := Bool(true)
|
||||||
|
|
||||||
io.cache.req.valid := !get_sent && started
|
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.typ := UInt(log2Ceil(32 / 8))
|
||||||
io.cache.req.bits.cmd := M_XRD
|
io.cache.req.bits.cmd := M_XRD
|
||||||
io.cache.req.bits.tag := UInt(0)
|
io.cache.req.bits.tag := UInt(0)
|
||||||
|
@ -12,7 +12,7 @@ trait HasAddrMapParameters {
|
|||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
|
|
||||||
val paddrBits = p(PAddrBits)
|
val paddrBits = p(PAddrBits)
|
||||||
def addrMap = p(rocketchip.GlobalAddrMap).get
|
def addrMap = p(rocketchip.GlobalAddrMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
case class MemAttr(prot: Int, cacheable: Boolean = false)
|
case class MemAttr(prot: Int, cacheable: Boolean = false)
|
||||||
|
@ -20,9 +20,6 @@ import cde.{Parameters, Config, Dump, Knob, CDEMatchError}
|
|||||||
|
|
||||||
class BasePlatformConfig extends Config(
|
class BasePlatformConfig extends Config(
|
||||||
topDefinitions = {
|
topDefinitions = {
|
||||||
val configString = new GlobalVariable[String]
|
|
||||||
val globalAddrMap = new GlobalVariable[AddrMap]
|
|
||||||
val nCoreplexExtClients = new GlobalVariable[Int]
|
|
||||||
(pname,site,here) => {
|
(pname,site,here) => {
|
||||||
type PF = PartialFunction[Any,Any]
|
type PF = PartialFunction[Any,Any]
|
||||||
def findBy(sname:Any):Any = here[PF](site[Any](sname))(pname)
|
def findBy(sname:Any):Any = here[PF](site[Any](sname))(pname)
|
||||||
@ -55,7 +52,6 @@ class BasePlatformConfig extends Config(
|
|||||||
case NExtMMIOTLChannels => 0
|
case NExtMMIOTLChannels => 0
|
||||||
case AsyncBusChannels => false
|
case AsyncBusChannels => false
|
||||||
case NExtBusAXIChannels => 0
|
case NExtBusAXIChannels => 0
|
||||||
case NCoreplexExtClients => nCoreplexExtClients
|
|
||||||
case HastiId => "Ext"
|
case HastiId => "Ext"
|
||||||
case HastiKey("TL") =>
|
case HastiKey("TL") =>
|
||||||
HastiParameters(
|
HastiParameters(
|
||||||
@ -69,8 +65,6 @@ class BasePlatformConfig extends Config(
|
|||||||
case NMemoryChannels => Dump("N_MEM_CHANNELS", 1)
|
case NMemoryChannels => Dump("N_MEM_CHANNELS", 1)
|
||||||
case TMemoryChannels => BusType.AXI
|
case TMemoryChannels => BusType.AXI
|
||||||
case ExtMemSize => Dump("MEM_SIZE", 0x10000000L)
|
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 RTCPeriod => 100 // gives 10 MHz RTC assuming 1 GHz uncore clock
|
||||||
case BuildExampleTop =>
|
case BuildExampleTop =>
|
||||||
(p: Parameters) => uncore.tilelink2.LazyModule(new ExampleTop(p))
|
(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 {
|
trait Generator extends App with HasGeneratorUtilities {
|
||||||
lazy val names = {
|
lazy val names = {
|
||||||
require(args.size == 5, "Usage: sbt> " +
|
require(args.size == 5, "Usage: sbt> " +
|
||||||
@ -67,20 +71,25 @@ trait Generator extends App with HasGeneratorUtilities {
|
|||||||
configProject = args(3),
|
configProject = args(3),
|
||||||
configs = args(4))
|
configs = args(4))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lazy val td = names.targetDir
|
||||||
lazy val config = getConfig(names)
|
lazy val config = getConfig(names)
|
||||||
lazy val world = config.toInstance
|
lazy val world = config.toInstance
|
||||||
lazy val params = Parameters.root(world)
|
lazy val params = Parameters.root(world)
|
||||||
lazy val circuit = elaborate(names, params)
|
lazy val circuit = elaborate(names, params)
|
||||||
}
|
lazy val longName = names.topModuleClass + "." + names.configs
|
||||||
|
|
||||||
object RocketChipGenerator extends Generator {
|
def writeOutputFiles() {
|
||||||
val longName = names.topModuleClass + "." + names.configs
|
|
||||||
val td = names.targetDir
|
|
||||||
Driver.dumpFirrtl(circuit, Some(new File(td, s"$longName.fir"))) // FIRRTL
|
|
||||||
TestGeneration.addSuite(new RegressionTestSuite(params(RegressionTestNames)))
|
TestGeneration.addSuite(new RegressionTestSuite(params(RegressionTestNames)))
|
||||||
writeOutputFile(td, s"$longName.d", TestGeneration.generateMakefrag) // Coreplex-specific test suites
|
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"$longName.prm", ParameterDump.getDump) // Parameters flagged with Dump()
|
||||||
writeOutputFile(td, s"${names.configs}.knb", world.getKnobs) // Knobs for DSE
|
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}.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._
|
||||||
import junctions.NastiConstants._
|
import junctions.NastiConstants._
|
||||||
import uncore.tilelink._
|
import uncore.tilelink._
|
||||||
import uncore.tilelink2.{LazyModule, LazyModuleImp}
|
import uncore.tilelink2._
|
||||||
import uncore.converters._
|
import uncore.converters._
|
||||||
import uncore.devices._
|
import uncore.devices._
|
||||||
import uncore.util._
|
import uncore.util._
|
||||||
import rocket.Util._
|
import rocket.Util._
|
||||||
|
import rocket.XLen
|
||||||
|
import scala.math.max
|
||||||
import coreplex._
|
import coreplex._
|
||||||
|
|
||||||
/** Options for memory bus interface */
|
/** Options for memory bus interface */
|
||||||
@ -202,10 +204,10 @@ trait PeripheryMasterMMIOModule extends HasPeripheryParameters {
|
|||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
val outer: PeripheryMasterMMIO
|
val outer: PeripheryMasterMMIO
|
||||||
val io: PeripheryMasterMMIOBundle
|
val io: PeripheryMasterMMIOBundle
|
||||||
val mmioNetwork: Option[TileLinkRecursiveInterconnect]
|
val mmioNetwork: TileLinkRecursiveInterconnect
|
||||||
|
|
||||||
val mmio_ports = p(ExtMMIOPorts) map { port =>
|
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
|
val mmio_axi_start = 0
|
||||||
@ -278,11 +280,19 @@ trait PeripherySlaveModule extends HasPeripheryParameters {
|
|||||||
/////
|
/////
|
||||||
|
|
||||||
/** Always-ON block */
|
/** Always-ON block */
|
||||||
trait PeripheryAON extends LazyModule {
|
trait PeripheryAON extends LazyModule with HasPeripheryParameters {
|
||||||
implicit val p: Parameters
|
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 {
|
trait PeripheryAONBundle {
|
||||||
@ -293,21 +303,23 @@ trait PeripheryAONModule extends HasPeripheryParameters {
|
|||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
val outer: PeripheryAON
|
val outer: PeripheryAON
|
||||||
val io: PeripheryAONBundle
|
val io: PeripheryAONBundle
|
||||||
val mmioNetwork: Option[TileLinkRecursiveInterconnect]
|
|
||||||
val coreplex: Coreplex
|
val coreplex: Coreplex
|
||||||
|
|
||||||
val prci = Module(new PRCI()(innerMMIOParams))
|
outer.prci.module.io.rtcTick := Counter(p(RTCPeriod)).inc()
|
||||||
prci.io.rtcTick := Counter(p(RTCPeriod)).inc()
|
coreplex.io.prci <> outer.prci.module.io.tiles
|
||||||
prci.io.tl <> mmioNetwork.get.port("prci")
|
|
||||||
coreplex.io.prci <> prci.io.tiles
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////
|
/////
|
||||||
|
|
||||||
trait PeripheryBootROM extends LazyModule {
|
trait PeripheryBootROM extends LazyModule {
|
||||||
implicit val p: Parameters
|
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))))
|
pDevices.add(AddrMapEntry("bootrom", MemRange(0x1000, 4096, MemAttr(AddrMapProt.RX))))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,20 +331,23 @@ trait PeripheryBootROMModule extends HasPeripheryParameters {
|
|||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
val outer: PeripheryBootROM
|
val outer: PeripheryBootROM
|
||||||
val io: PeripheryBootROMBundle
|
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 {
|
trait PeripheryTestRAM extends LazyModule {
|
||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
val pDevices: ResourceManager[AddrMapEntry]
|
val peripheryBus: TLXbar
|
||||||
|
|
||||||
|
val ramBase = 0x52000000
|
||||||
val ramSize = 0x1000
|
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 {
|
trait PeripheryTestRAMBundle {
|
||||||
@ -342,22 +357,16 @@ trait PeripheryTestRAMBundle {
|
|||||||
trait PeripheryTestRAMModule extends HasPeripheryParameters {
|
trait PeripheryTestRAMModule extends HasPeripheryParameters {
|
||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
val outer: PeripheryTestRAM
|
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 {
|
trait PeripheryTestBusMaster extends LazyModule {
|
||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
val pBusMasters: RangeManager
|
val peripheryBus: TLXbar
|
||||||
val pDevices: ResourceManager[AddrMapEntry]
|
|
||||||
|
|
||||||
pBusMasters.add("busmaster", 1)
|
val fuzzer = LazyModule(new TLFuzzer(5000))
|
||||||
pDevices.add(AddrMapEntry("busmaster", MemSize(4096, MemAttr(AddrMapProt.RW))))
|
peripheryBus.node := fuzzer.node
|
||||||
}
|
}
|
||||||
|
|
||||||
trait PeripheryTestBusMasterBundle {
|
trait PeripheryTestBusMasterBundle {
|
||||||
@ -367,16 +376,4 @@ trait PeripheryTestBusMasterBundle {
|
|||||||
trait PeripheryTestBusMasterModule {
|
trait PeripheryTestBusMasterModule {
|
||||||
implicit val p: Parameters
|
implicit val p: Parameters
|
||||||
val outer: PeripheryTestBusMaster
|
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))),
|
else new MESICoherence(site(L2DirectoryRepresentation))),
|
||||||
nManagers = site(NBanksPerMemoryChannel)*site(NMemoryChannels) + 1,
|
nManagers = site(NBanksPerMemoryChannel)*site(NMemoryChannels) + 1,
|
||||||
nCachingClients = site(NCachedTileLinkPorts),
|
nCachingClients = site(NCachedTileLinkPorts),
|
||||||
nCachelessClients = site(NCoreplexExtClients).get + site(NUncachedTileLinkPorts),
|
nCachelessClients = site(NCoreplexExtClients) + site(NUncachedTileLinkPorts),
|
||||||
maxClientXacts = ((site(DCacheKey).nMSHRs + 1) +:
|
maxClientXacts = ((site(DCacheKey).nMSHRs + 1) +:
|
||||||
site(GroundTestKey).map(_.maxXacts))
|
site(GroundTestKey).map(_.maxXacts))
|
||||||
.reduce(max(_, _)),
|
.reduce(max(_, _)),
|
||||||
|
@ -11,11 +11,12 @@ import junctions.NastiConstants._
|
|||||||
case object BuildExampleTop extends Field[Parameters => ExampleTop]
|
case object BuildExampleTop extends Field[Parameters => ExampleTop]
|
||||||
case object SimMemLatency extends Field[Int]
|
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 io = new Bundle {
|
||||||
val success = Bool(OUTPUT)
|
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
|
// This test harness isn't especially flexible yet
|
||||||
require(dut.io.mem_clk.isEmpty)
|
require(dut.io.mem_clk.isEmpty)
|
||||||
@ -33,7 +34,7 @@ class TestHarness(implicit val p: Parameters) extends Module with HasAddrMapPara
|
|||||||
int := false
|
int := false
|
||||||
|
|
||||||
if (dut.io.mem_axi.nonEmpty) {
|
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)
|
require(memSize % dut.io.mem_axi.size == 0)
|
||||||
for (axi <- dut.io.mem_axi) {
|
for (axi <- dut.io.mem_axi) {
|
||||||
val mem = Module(new SimAXIMem(memSize / dut.io.mem_axi.size))
|
val mem = Module(new SimAXIMem(memSize / dut.io.mem_axi.size))
|
||||||
|
@ -6,7 +6,7 @@ import Chisel._
|
|||||||
import cde.{Parameters, Field}
|
import cde.{Parameters, Field}
|
||||||
import junctions._
|
import junctions._
|
||||||
import uncore.tilelink._
|
import uncore.tilelink._
|
||||||
import uncore.tilelink2.{LazyModule, LazyModuleImp}
|
import uncore.tilelink2._
|
||||||
import uncore.devices._
|
import uncore.devices._
|
||||||
import util.ParameterizedBundle
|
import util.ParameterizedBundle
|
||||||
import rocket._
|
import rocket._
|
||||||
@ -14,18 +14,41 @@ import rocket.Util._
|
|||||||
import coreplex._
|
import coreplex._
|
||||||
|
|
||||||
// the following parameters will be refactored properly with TL2
|
// the following parameters will be refactored properly with TL2
|
||||||
case object GlobalAddrMap extends Field[GlobalVariable[AddrMap]]
|
case object GlobalAddrMap extends Field[AddrMap]
|
||||||
case object ConfigString extends Field[GlobalVariable[String]]
|
case object ConfigString extends Field[String]
|
||||||
case object NCoreplexExtClients extends Field[GlobalVariable[Int]]
|
case object NCoreplexExtClients extends Field[Int]
|
||||||
/** Function for building Coreplex */
|
/** Function for building Coreplex */
|
||||||
case object BuildCoreplex extends Field[(Parameters, CoreplexConfig) => Coreplex]
|
case object BuildCoreplex extends Field[(Parameters, CoreplexConfig) => Coreplex]
|
||||||
|
|
||||||
/** Base Top with no Periphery */
|
/** 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
|
// the following variables will be refactored properly with TL2
|
||||||
val pInterrupts = new RangeManager
|
val pInterrupts = new RangeManager
|
||||||
val pBusMasters = new RangeManager
|
val pBusMasters = new RangeManager
|
||||||
val pDevices = new ResourceManager[AddrMapEntry]
|
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) {
|
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) {
|
class BaseTopModule[+L <: BaseTop, +B <: BaseTopBundle](val p: Parameters, l: L, b: Coreplex => B) extends LazyModuleImp(l) {
|
||||||
val outer: L = l
|
val outer: L = l
|
||||||
|
|
||||||
val c = CoreplexConfig(
|
val coreplex = p(BuildCoreplex)(p, outer.c)
|
||||||
nTiles = p(NTiles),
|
val io: B = b(coreplex)
|
||||||
nExtInterrupts = outer.pInterrupts.sum,
|
|
||||||
nSlaves = outer.pBusMasters.sum,
|
|
||||||
nMemChannels = p(NMemoryChannels),
|
|
||||||
hasSupervisor = p(UseVM),
|
|
||||||
hasExtMMIOPort = !(outer.pDevices.get.isEmpty && p(ExtMMIOPorts).isEmpty)
|
|
||||||
)
|
|
||||||
|
|
||||||
def genGlobalAddrMap = GenerateGlobalAddrMap(p, outer.pDevices.get)
|
io.success zip coreplex.io.success map { case (x, y) => x := y }
|
||||||
def genConfigString = GenerateConfigString(p, c, outer.pDevices.get)
|
|
||||||
|
|
||||||
p(NCoreplexExtClients).assign(outer.pBusMasters.sum)
|
val mmioNetwork =
|
||||||
p(GlobalAddrMap).assign(genGlobalAddrMap)
|
Module(new TileLinkRecursiveInterconnect(1, p(GlobalAddrMap).subMap("io:ext"))(
|
||||||
p(ConfigString).assign(genConfigString)
|
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")
|
println("Generated Address Map")
|
||||||
for (entry <- p(GlobalAddrMap).get.flatten) {
|
for (entry <- p(GlobalAddrMap).flatten) {
|
||||||
val name = entry.name
|
val name = entry.name
|
||||||
val start = entry.region.start
|
val start = entry.region.start
|
||||||
val end = entry.region.start + entry.region.size - 1
|
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("Generated Configuration String")
|
||||||
println(p(ConfigString).get)
|
println(p(ConfigString))
|
||||||
|
ConfigStringOutput.contents = Some(p(ConfigString))
|
||||||
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 }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Example Top with Periphery */
|
/** 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 PeripheryBootROM with PeripheryDebug with PeripheryExtInterrupts with PeripheryAON
|
||||||
with PeripheryMasterMem with PeripheryMasterMMIO with PeripherySlave {
|
with PeripheryMasterMem with PeripheryMasterMMIO with PeripherySlave {
|
||||||
override lazy val module = Module(new ExampleTopModule(p, this, new ExampleTopBundle(p, _)))
|
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
|
with PeripheryMasterMemModule with PeripheryMasterMMIOModule with PeripherySlaveModule
|
||||||
|
|
||||||
/** Example Top with TestRAM */
|
/** Example Top with TestRAM */
|
||||||
class ExampleTopWithTestRAM(p: Parameters) extends ExampleTop(p)
|
class ExampleTopWithTestRAM(q: Parameters) extends ExampleTop(q)
|
||||||
with PeripheryTestRAM {
|
with PeripheryTestRAM {
|
||||||
override lazy val module = Module(new ExampleTopWithTestRAMModule(p, this, new ExampleTopWithTestRAMBundle(p, _)))
|
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)
|
val success = Bool(OUTPUT)
|
||||||
}
|
}
|
||||||
|
|
||||||
p(NCoreplexExtClients).assign(0)
|
val l1params = p.alterPartial({
|
||||||
p(ConfigString).assign("")
|
case NCoreplexExtClients => 0
|
||||||
|
case ConfigString => ""
|
||||||
val l1params = p.alterPartial({ case TLId => "L1toL2" })
|
case TLId => "L1toL2" })
|
||||||
val tests = Module(new UnitTestSuite()(l1params))
|
val tests = Module(new UnitTestSuite()(l1params))
|
||||||
|
|
||||||
io.success := tests.io.finished
|
io.success := tests.io.finished
|
||||||
|
@ -64,10 +64,8 @@ object GenerateGlobalAddrMap {
|
|||||||
new AddrMap(entries)
|
new AddrMap(entries)
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy val extIOAddrMap = new AddrMap(
|
lazy val tl2AddrMap = new AddrMap(pDevicesEntries, collapse = true)
|
||||||
pDevicesEntries ++ p(ExtMMIOPorts),
|
lazy val extIOAddrMap = new AddrMap(AddrMapEntry("TL2", tl2AddrMap) +: p(ExtMMIOPorts), collapse = true)
|
||||||
start = BigInt("50000000", 16),
|
|
||||||
collapse = true)
|
|
||||||
|
|
||||||
val memBase = 0x80000000L
|
val memBase = 0x80000000L
|
||||||
val memSize = p(ExtMemSize)
|
val memSize = p(ExtMemSize)
|
||||||
@ -83,9 +81,9 @@ object GenerateGlobalAddrMap {
|
|||||||
|
|
||||||
object GenerateConfigString {
|
object GenerateConfigString {
|
||||||
def apply(p: Parameters, c: CoreplexConfig, pDevicesEntries: Seq[AddrMapEntry]) = {
|
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 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 xLen = p(XLen)
|
||||||
val res = new StringBuilder
|
val res = new StringBuilder
|
||||||
res append "plic {\n"
|
res append "plic {\n"
|
||||||
@ -138,7 +136,7 @@ object GenerateConfigString {
|
|||||||
}
|
}
|
||||||
res append "};\n"
|
res append "};\n"
|
||||||
pDevicesEntries foreach { entry =>
|
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"${entry.name} {\n"
|
||||||
res append s" addr 0x${region.start.toString(16)};\n"
|
res append s" addr 0x${region.start.toString(16)};\n"
|
||||||
res append s" size 0x${region.size.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
|
// for now, have the reset vector jump straight to memory
|
||||||
val memBase = (
|
val memBase = (
|
||||||
if (p(GlobalAddrMap).get contains "mem") p(GlobalAddrMap).get("mem")
|
if (p(GlobalAddrMap) contains "mem") p(GlobalAddrMap)("mem")
|
||||||
else p(GlobalAddrMap).get("io:int:dmem0")
|
else p(GlobalAddrMap)("io:int:dmem0")
|
||||||
).start
|
).start
|
||||||
val resetToMemDist = memBase - p(ResetVector)
|
val resetToMemDist = memBase - p(ResetVector)
|
||||||
require(resetToMemDist == (resetToMemDist.toInt >> 12 << 12))
|
require(resetToMemDist == (resetToMemDist.toInt >> 12 << 12))
|
||||||
@ -168,6 +166,6 @@ object GenerateBootROM {
|
|||||||
require(rom.getInt(12) == 0,
|
require(rom.getInt(12) == 0,
|
||||||
"Config string address position should not be occupied by code")
|
"Config string address position should not be occupied by code")
|
||||||
rom.putInt(12, configStringAddr)
|
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 rocket.Util._
|
||||||
import junctions._
|
import junctions._
|
||||||
import junctions.NastiConstants._
|
import junctions.NastiConstants._
|
||||||
import uncore.tilelink._
|
import uncore.tilelink2._
|
||||||
import uncore.util._
|
import uncore.util._
|
||||||
|
import scala.math.{min,max}
|
||||||
import cde.{Parameters, Field}
|
import cde.{Parameters, Field}
|
||||||
|
|
||||||
/** Number of tiles */
|
/** Number of tiles */
|
||||||
@ -32,45 +33,28 @@ object PRCI {
|
|||||||
def size = 0xc000
|
def size = 0xc000
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Power, Reset, Clock, Interrupt */
|
case class PRCIConfig(beatBytes: Int, address: BigInt = 0x44000000)
|
||||||
class PRCI(implicit val p: Parameters) extends Module
|
|
||||||
with HasTileLinkParameters
|
trait MixPRCIParameters {
|
||||||
with HasAddrMapParameters {
|
val params: (PRCIConfig, Parameters)
|
||||||
val io = new Bundle {
|
val c = params._1
|
||||||
val tl = new ClientUncachedTileLinkIO().flip
|
implicit val p = params._2
|
||||||
|
}
|
||||||
|
|
||||||
|
trait PRCIBundle extends Bundle with MixPRCIParameters {
|
||||||
val tiles = Vec(p(NTiles), new PRCITileIO)
|
val tiles = Vec(p(NTiles), new PRCITileIO)
|
||||||
val rtcTick = Bool(INPUT)
|
val rtcTick = Bool(INPUT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait PRCIModule extends Module with HasRegMap with MixPRCIParameters {
|
||||||
|
val io: PRCIBundle
|
||||||
|
|
||||||
val timeWidth = 64
|
val timeWidth = 64
|
||||||
val timecmp = Reg(Vec(p(NTiles), UInt(width = timeWidth)))
|
val time = Reg(init=UInt(0, width = timeWidth))
|
||||||
val time = Reg(init=UInt(0, timeWidth))
|
|
||||||
when (io.rtcTick) { time := time + UInt(1) }
|
when (io.rtcTick) { time := time + UInt(1) }
|
||||||
|
|
||||||
val ipi = Reg(init=Vec.fill(p(NTiles))(UInt(0, 32)))
|
val timecmp = Seq.fill(p(NTiles)) { Reg(UInt(width = timeWidth)) }
|
||||||
|
val ipi = Seq.fill(p(NTiles)) { RegInit(UInt(0, width = 1)) }
|
||||||
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))
|
|
||||||
}
|
|
||||||
|
|
||||||
for ((tile, i) <- io.tiles zipWithIndex) {
|
for ((tile, i) <- io.tiles zipWithIndex) {
|
||||||
tile.interrupts.msip := ipi(i)(0)
|
tile.interrupts.msip := ipi(i)(0)
|
||||||
@ -78,42 +62,40 @@ class PRCI(implicit val p: Parameters) extends Module
|
|||||||
tile.reset := reset
|
tile.reset := reset
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO generalize these to help other TL slaves
|
/* 0000 msip hart 0
|
||||||
def load(v: Seq[UInt], acq: Acquire): UInt = {
|
* 0004 msip hart 1
|
||||||
val w = v.head.getWidth
|
* 4000 mtimecmp hart 0 lo
|
||||||
val a = acq.full_addr()
|
* 4004 mtimecmp hart 0 hi
|
||||||
require(isPow2(w) && w >= 8)
|
* 4008 mtimecmp hart 1 lo
|
||||||
if (w > tlDataBits) {
|
* 400c mtimecmp hart 1 hi
|
||||||
(v(a.extract(log2Ceil(w/8*v.size)-1,log2Ceil(w/8))) >> a.extract(log2Ceil(w/8)-1,log2Ceil(tlDataBytes)))(tlDataBits-1,0)
|
* bff8 mtime lo
|
||||||
} else {
|
* bffc mtime hi
|
||||||
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)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def store(v: Seq[UInt], acq: Acquire, en: Bool): UInt = {
|
// laying out IPI fields suck...
|
||||||
val w = v.head.getWidth
|
// bytes=1 -> pad to 7, step 4, group 1
|
||||||
require(isPow2(w) && w >= 8)
|
// bytes=2 -> pad to 15, step 2, group 1
|
||||||
val a = acq.full_addr()
|
// bytes=4 -> pad to 31, step 1, group 1
|
||||||
val rdata = load(v, acq)
|
// bytes=8 -> pad to 31, step 1, group 2
|
||||||
val wdata = (acq.data & acq.full_wmask()) | (rdata & ~acq.full_wmask())
|
// bytes=16-> pad to 31, step 1, group 4
|
||||||
when (en && acq.isBuiltInType(Acquire.putType)) {
|
val pad = min(c.beatBytes*8,32) - 1
|
||||||
if (w <= tlDataBits) {
|
val step = max(1, 4/c.beatBytes)
|
||||||
val word =
|
val group = max(1, c.beatBytes/4)
|
||||||
if (tlDataBits/w >= v.size) UInt(0)
|
val ipi_regs = ipi.map { reg => Seq(RegField(1, reg), RegField(pad)) }.flatten.grouped(group*2).
|
||||||
else a(log2Up(w/8*v.size)-1,log2Up(tlDataBytes))
|
zipWithIndex.map { case (fields, i) => (i*step -> fields) }
|
||||||
for (i <- 0 until v.size) when (word === i/(tlDataBits/w)) {
|
|
||||||
val base = i % (tlDataBits/w)
|
// Just split up time fields by bytes
|
||||||
v(i) := wdata >> (w * (i % (tlDataBits/w)))
|
val timecmp_regs = timecmp.zipWithIndex.map { case (reg, i) =>
|
||||||
}
|
RegField.bytes(reg, PRCI.timecmp(i)/c.beatBytes, c.beatBytes)
|
||||||
} else {
|
}.flatten
|
||||||
val i = a.extract(log2Ceil(w/8*v.size)-1,log2Ceil(w/8))
|
val time_reg = RegField.bytes(time, PRCI.time/c.beatBytes, c.beatBytes)
|
||||||
val mask = FillInterleaved(tlDataBits, UIntToOH(a.extract(log2Ceil(w/8)-1,log2Ceil(tlDataBytes))))
|
|
||||||
v(i) := (wdata & mask) | (v(i) & ~mask)
|
regmap((timecmp_regs ++ time_reg ++ ipi_regs):_*)
|
||||||
}
|
|
||||||
}
|
|
||||||
rdata
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 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 unittest.UnitTest
|
||||||
import junctions._
|
import junctions._
|
||||||
import uncore.tilelink._
|
import uncore.tilelink._
|
||||||
|
import uncore.tilelink2._
|
||||||
import uncore.util._
|
import uncore.util._
|
||||||
import cde.{Parameters, Field}
|
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
|
class ROMSlave(contents: Seq[Byte])(implicit val p: Parameters) extends Module
|
||||||
with HasTileLinkParameters
|
with HasTileLinkParameters
|
||||||
with HasAddrMapParameters {
|
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 dFragnum = out.d.bits.source(fragmentBits-1, 0)
|
||||||
val dFirst = acknum === UInt(0)
|
val dFirst = acknum === UInt(0)
|
||||||
val dsizeOH = UIntToOH (out.d.bits.size, log2Ceil(maxDownSize)+1)
|
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)
|
val dHasData = edgeOut.hasData(out.d.bits)
|
||||||
|
|
||||||
// calculate new acknum
|
// calculate new acknum
|
||||||
@ -209,7 +209,7 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten
|
|||||||
val aOrig = in.a.bits.size
|
val aOrig = in.a.bits.size
|
||||||
val aFrag = Mux(aOrig > limit, limit, aOrig)
|
val aFrag = Mux(aOrig > limit, limit, aOrig)
|
||||||
val aOrigOH1 = UIntToOH1(aOrig, log2Ceil(maxSize))
|
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 aHasData = node.edgesIn(0).hasData(in.a.bits)
|
||||||
val aMask = Mux(aHasData, UInt(0), aFragOH1)
|
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(_&&_)
|
val smartManagers = edgeOut.manager.managers.map(_.supportsHint.max == edgeOut.manager.maxTransfer).reduce(_&&_)
|
||||||
|
|
||||||
if (supportManagers && !smartManagers) {
|
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 address = edgeIn.address(in.a.bits)
|
||||||
val handleA = if (passthrough) !edgeOut.manager.supportsHint(address, edgeIn.size(in.a.bits)) else Bool(true)
|
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)
|
// Prioritize existing D traffic over HintAck (and finish multibeat xfers)
|
||||||
val beats1 = edgeOut.numBeats1(out.d.bits)
|
val hintWinsD = hintHoldsD || (!outerHoldsD && !outerWantsD)
|
||||||
val counter = RegInit(UInt(0, width = log2Up(edgeOut.manager.maxTransfer/edgeOut.manager.beatBytes)))
|
hintHoldsD := hintWantsD && hintWinsD && !in.d.ready
|
||||||
val first = counter === UInt(0)
|
// Hint can only hold D b/c it still wants it from last cycle
|
||||||
when (out.d.fire()) { counter := Mux(first, beats1, counter - UInt(1)) }
|
assert (!hintHoldsD || hintWantsD)
|
||||||
|
|
||||||
in.d.valid := out.d.valid || (bypassD && in.a.valid && first)
|
in.d.valid := Mux(hintWinsD, hintWantsD, outerWantsD)
|
||||||
out.d.ready := in.d.ready
|
in.d.bits := Mux(hintWinsD, edgeIn.HintAck(in.a.bits, edgeOut.manager.findId(address)), out.d.bits)
|
||||||
in.d.bits := Mux(out.d.valid, out.d.bits, edgeIn.HintAck(in.a.bits, edgeOut.manager.findId(address)))
|
out.d.ready := in.d.ready && !hintHoldsD
|
||||||
|
|
||||||
in.a.ready := Mux(bypassD, in.d.ready && first && !out.d.valid, out.a.ready)
|
in.a.ready := Mux(hintBitsAtA, hintWinsD && in.d.ready, out.a.ready)
|
||||||
out.a.valid := in.a.valid && !bypassD
|
out.a.valid := in.a.valid && !hintBitsAtA
|
||||||
out.a.bits := in.a.bits
|
out.a.bits := in.a.bits
|
||||||
} else {
|
} else {
|
||||||
out.a.valid := in.a.valid
|
out.a.valid := in.a.valid
|
||||||
@ -60,21 +74,35 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (supportClients && !smartClients) {
|
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 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)
|
// Prioritize existing C traffic over HintAck (and finish multibeat xfers)
|
||||||
val beats1 = edgeIn.numBeats1(in.c.bits)
|
val hintWinsC = hintHoldsC || (!innerHoldsC && !innerWantsC)
|
||||||
val counter = RegInit(UInt(0, width = log2Up(edgeIn.client.maxTransfer/edgeIn.manager.beatBytes)))
|
hintHoldsC := hintWantsC && hintWinsC && !out.c.ready
|
||||||
val first = counter === UInt(0)
|
// Hint can only hold C b/c it still wants it from last cycle
|
||||||
when (in.c.fire()) { counter := Mux(first, beats1, counter - UInt(1)) }
|
assert (!hintHoldsC || hintWantsC)
|
||||||
|
|
||||||
out.c.valid := in.c.valid || (bypassC && in.b.valid && first)
|
out.c.valid := Mux(hintWinsC, hintWantsC, innerWantsC)
|
||||||
in.c.ready := out.c.ready
|
out.c.bits := Mux(hintWinsC, edgeOut.HintAck(out.b.bits), in.c.bits)
|
||||||
out.c.bits := Mux(in.c.valid, in.c.bits, edgeOut.HintAck(out.b.bits))
|
in.c.ready := out.c.ready && !hintHoldsC
|
||||||
|
|
||||||
out.b.ready := Mux(bypassC, out.c.ready && first && !in.c.valid, in.b.ready)
|
out.b.ready := Mux(hintBitsAtB, hintWinsC && out.c.ready, in.b.ready)
|
||||||
in.b.valid := out.b.valid && !bypassC
|
in.b.valid := out.b.valid && !hintBitsAtB
|
||||||
in.b.bits := out.b.bits
|
in.b.bits := out.b.bits
|
||||||
} else if (bce) {
|
} else if (bce) {
|
||||||
in.b.valid := out.b.valid
|
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
|
// During conversion from TL Legacy, we won't support Acquire
|
||||||
|
|
||||||
// Must be able to fit TL2 sink_id into TL legacy
|
// 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)
|
val out = io.out(0)
|
||||||
out.a.valid := io.legacy.acquire.valid
|
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_MINU -> edge.Arithmetic(source, address, beat, data, TLAtomics.MINU)._2,
|
||||||
MemoryOpConstants.M_XA_MAXU -> edge.Arithmetic(source, address, beat, data, TLAtomics.MAXU)._2))
|
MemoryOpConstants.M_XA_MAXU -> edge.Arithmetic(source, address, beat, data, TLAtomics.MAXU)._2))
|
||||||
} else {
|
} 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))
|
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 connectOut = bundleOut
|
||||||
def connectIn = bundleIn
|
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 x = this // x := y
|
||||||
val info = sourceLine(sourceInfo, " at ", "")
|
val info = sourceLine(sourceInfo, " at ", "")
|
||||||
require (!LazyModule.stack.isEmpty, s"${y.name} cannot be connected to ${x.name} outside of LazyModule scope" + info)
|
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 contains(x: TransferSizes) = x.none || (min <= x.min && x.max <= max)
|
||||||
|
|
||||||
def intersect(x: TransferSizes) =
|
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))
|
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
|
// 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=0x200, mask=0xff describes a device managing 0x200-0x2ff
|
||||||
// e.g: base=0x1000, mask=0xf0f decribes a device managing 0x1000-0x100f, 0x1100-0x110f, ...
|
// 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)
|
// Forbid misaligned base address (and empty sets)
|
||||||
require ((base & mask) == 0)
|
require ((base & mask) == 0)
|
||||||
@ -97,12 +97,24 @@ case class AddressSet(base: BigInt, mask: BigInt)
|
|||||||
|
|
||||||
// A strided slave serves discontiguous ranges
|
// A strided slave serves discontiguous ranges
|
||||||
def strided = alignment1 != mask
|
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(
|
case class TLManagerParameters(
|
||||||
address: Seq[AddressSet],
|
address: Seq[AddressSet],
|
||||||
sinkId: IdRange = IdRange(0, 1),
|
sinkId: IdRange = IdRange(0, 1),
|
||||||
regionType: RegionType.T = RegionType.GET_EFFECTS,
|
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
|
// Supports both Acquire+Release+Finish of these sizes
|
||||||
supportsAcquire: TransferSizes = TransferSizes.none,
|
supportsAcquire: TransferSizes = TransferSizes.none,
|
||||||
supportsArithmetic: 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 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)))
|
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
|
// !!! need a cheaper version of find, where we assume a valid address match exists
|
||||||
|
|
||||||
// Does this Port manage this ID/address?
|
// Does this Port manage this ID/address?
|
||||||
@ -208,6 +221,7 @@ case class TLManagerPortParameters(managers: Seq[TLManagerParameters], beatBytes
|
|||||||
|
|
||||||
case class TLClientParameters(
|
case class TLClientParameters(
|
||||||
sourceId: IdRange = IdRange(0,1),
|
sourceId: IdRange = IdRange(0,1),
|
||||||
|
nodePath: Seq[TLBaseNode] = Seq(),
|
||||||
// Supports both Probe+Grant of these sizes
|
// Supports both Probe+Grant of these sizes
|
||||||
supportsProbe: TransferSizes = TransferSizes.none,
|
supportsProbe: TransferSizes = TransferSizes.none,
|
||||||
supportsArithmetic: TransferSizes = TransferSizes.none,
|
supportsArithmetic: TransferSizes = TransferSizes.none,
|
||||||
|
@ -105,6 +105,23 @@ object RegField
|
|||||||
bb.d := data
|
bb.d := data
|
||||||
Bool(true)
|
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
|
trait HasRegMap
|
||||||
|
@ -28,8 +28,8 @@ class RegMapperOutput(params: RegMapperParams) extends GenericParameterizedBundl
|
|||||||
object RegMapper
|
object RegMapper
|
||||||
{
|
{
|
||||||
// Create a generic register-based device
|
// Create a generic register-based device
|
||||||
def apply(bytes: Int, concurrency: Option[Int], in: DecoupledIO[RegMapperInput], mapping: RegField.Map*) = {
|
def apply(bytes: Int, concurrency: Option[Int], undefZero: Boolean, in: DecoupledIO[RegMapperInput], mapping: RegField.Map*) = {
|
||||||
val regmap = mapping.toList
|
val regmap = mapping.toList.filter(!_._2.isEmpty)
|
||||||
require (!regmap.isEmpty)
|
require (!regmap.isEmpty)
|
||||||
|
|
||||||
// Ensure no register appears twice
|
// Ensure no register appears twice
|
||||||
@ -37,15 +37,31 @@ object RegMapper
|
|||||||
require (reg1 != reg2)
|
require (reg1 != reg2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flatten the regmap into (Reg:Int, Offset:Int, field:RegField)
|
// Convert to and from Bits
|
||||||
val flat = regmap.map { case (reg, fields) =>
|
def toBits(x: Int, tail: List[Boolean] = List.empty): List[Boolean] =
|
||||||
val offsets = fields.scanLeft(0)(_ + _.width).init
|
if (x == 0) tail.reverse else toBits(x >> 1, ((x & 1) == 1) :: tail)
|
||||||
(offsets zip fields) map { case (o, f) => (reg, o, f) }
|
def ofBits(bits: List[Boolean]) = bits.foldRight(0){ case (x,y) => (if (x) 1 else 0) | y << 1 }
|
||||||
}.flatten
|
|
||||||
require (!flat.isEmpty)
|
|
||||||
|
|
||||||
|
// 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 endIndex = 1 << log2Ceil(regmap.map(_._1).max+1)
|
||||||
val params = RegMapperParams(log2Up(endIndex), bytes, in.bits.params.extraBits)
|
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 out = Wire(Irrevocable(new RegMapperOutput(params)))
|
||||||
val front = Wire(Irrevocable(new RegMapperInput(params)))
|
val front = Wire(Irrevocable(new RegMapperInput(params)))
|
||||||
@ -69,13 +85,13 @@ object RegMapper
|
|||||||
val woready = Wire(Vec(flat.size, Bool()))
|
val woready = Wire(Vec(flat.size, Bool()))
|
||||||
|
|
||||||
// Per-register list of all control signals needed for data to flow
|
// Per-register list of all control signals needed for data to flow
|
||||||
val rifire = Array.tabulate(endIndex) { i => Seq(Bool(true)) }
|
val rifire = Array.tabulate(regSize) { i => Seq(Bool(true)) }
|
||||||
val wifire = Array.tabulate(endIndex) { i => Seq(Bool(true)) }
|
val wifire = Array.tabulate(regSize) { i => Seq(Bool(true)) }
|
||||||
val rofire = Array.tabulate(endIndex) { i => Seq(Bool(true)) }
|
val rofire = Array.tabulate(regSize) { i => Seq(Bool(true)) }
|
||||||
val wofire = Array.tabulate(endIndex) { i => Seq(Bool(true)) }
|
val wofire = Array.tabulate(regSize) { i => Seq(Bool(true)) }
|
||||||
|
|
||||||
// The output values for each register
|
// The output values for each register
|
||||||
val dataOut = Array.tabulate(endIndex) { _ => UInt(0) }
|
val dataOut = Array.tabulate(regSize) { _ => UInt(0) }
|
||||||
|
|
||||||
// Which bits are touched?
|
// Which bits are touched?
|
||||||
val frontMask = FillInterleaved(8, front.bits.mask)
|
val frontMask = FillInterleaved(8, front.bits.mask)
|
||||||
@ -110,8 +126,10 @@ object RegMapper
|
|||||||
val wifireMux = Vec(wifire.map(_.reduce(_ && _)))
|
val wifireMux = Vec(wifire.map(_.reduce(_ && _)))
|
||||||
val rofireMux = Vec(rofire.map(_.reduce(_ && _)))
|
val rofireMux = Vec(rofire.map(_.reduce(_ && _)))
|
||||||
val wofireMux = Vec(wofire.map(_.reduce(_ && _)))
|
val wofireMux = Vec(wofire.map(_.reduce(_ && _)))
|
||||||
val iready = Mux(front.bits.read, rifireMux(front.bits.index), wifireMux(front.bits.index))
|
val iindex = regIndexU(front.bits.index)
|
||||||
val oready = Mux(back .bits.read, rofireMux(back .bits.index), wofireMux(back .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
|
// Connect the pipeline
|
||||||
in.ready := front.ready && iready
|
in.ready := front.ready && iready
|
||||||
@ -120,11 +138,11 @@ object RegMapper
|
|||||||
out.valid := back.valid && oready
|
out.valid := back.valid && oready
|
||||||
|
|
||||||
// Which register is touched?
|
// Which register is touched?
|
||||||
val frontSel = UIntToOH(front.bits.index)
|
val frontSel = UIntToOH(iindex)
|
||||||
val backSel = UIntToOH(back.bits.index)
|
val backSel = UIntToOH(oindex)
|
||||||
|
|
||||||
// Include the per-register one-hot selected criteria
|
// 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)
|
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)
|
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)
|
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.read := back.bits.read
|
||||||
out.bits.data := Vec(dataOut)(back.bits.index)
|
out.bits.data := Vec(dataOut)(oindex)
|
||||||
out.bits.extra := back.bits.extra
|
out.bits.extra := back.bits.extra
|
||||||
|
|
||||||
(endIndex, out)
|
(endIndex, out)
|
||||||
|
@ -4,7 +4,7 @@ package uncore.tilelink2
|
|||||||
|
|
||||||
import Chisel._
|
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(
|
extends TLManagerNode(beatBytes, TLManagerParameters(
|
||||||
address = Seq(address),
|
address = Seq(address),
|
||||||
supportsGet = TransferSizes(1, beatBytes),
|
supportsGet = TransferSizes(1, beatBytes),
|
||||||
@ -25,7 +25,7 @@ class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatB
|
|||||||
val baseEnd = 0
|
val baseEnd = 0
|
||||||
val (sizeEnd, sizeOff) = (edge.bundle.sizeBits + baseEnd, baseEnd)
|
val (sizeEnd, sizeOff) = (edge.bundle.sizeBits + baseEnd, baseEnd)
|
||||||
val (sourceEnd, sourceOff) = (edge.bundle.sourceBits + sizeEnd, sizeEnd)
|
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 params = RegMapperParams(log2Up(address.mask+1), beatBytes, addrLoEnd)
|
||||||
val in = Wire(Decoupled(new RegMapperInput(params)))
|
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)
|
in.bits.extra := Cat(edge.addr_lo(a.bits), a.bits.source, a.bits.size)
|
||||||
|
|
||||||
// Invoke the register map builder
|
// 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
|
// All registers must fit inside the device address space
|
||||||
require (address.mask >= (endIndex-1)*beatBytes)
|
require (address.mask >= (endIndex-1)*beatBytes)
|
||||||
@ -67,17 +67,17 @@ class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatB
|
|||||||
|
|
||||||
object TLRegisterNode
|
object TLRegisterNode
|
||||||
{
|
{
|
||||||
def apply(address: AddressSet, concurrency: Option[Int] = None, beatBytes: Int = 4) =
|
def apply(address: AddressSet, concurrency: Option[Int] = None, beatBytes: Int = 4, undefZero: Boolean = true) =
|
||||||
new TLRegisterNode(address, concurrency, beatBytes)
|
new TLRegisterNode(address, concurrency, beatBytes, undefZero)
|
||||||
}
|
}
|
||||||
|
|
||||||
// These convenience methods below combine to make it possible to create a TL2
|
// These convenience methods below combine to make it possible to create a TL2
|
||||||
// register mapped device from a totally abstract register mapped device.
|
// register mapped device from a totally abstract register mapped device.
|
||||||
// See GPIO.scala in this directory for an example
|
// 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)
|
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]
|
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)
|
(bundleBuilder: TLRegBundleArg => B)
|
||||||
(moduleBuilder: (=> B, TLRegisterRouterBase) => M)
|
(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 (isPow2(size))
|
||||||
// require (size >= 4096) ... not absolutely required, but highly recommended
|
// 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(
|
val node = TLManagerNode(beatBytes, TLManagerParameters(
|
||||||
address = List(address),
|
address = List(address),
|
||||||
regionType = RegionType.UNCACHED,
|
regionType = RegionType.UNCACHED,
|
||||||
|
executable = true,
|
||||||
supportsGet = TransferSizes(1, beatBytes),
|
supportsGet = TransferSizes(1, beatBytes),
|
||||||
supportsPutPartial = TransferSizes(1, beatBytes),
|
supportsPutPartial = TransferSizes(1, beatBytes),
|
||||||
supportsPutFull = TransferSizes(1, beatBytes),
|
supportsPutFull = TransferSizes(1, beatBytes),
|
||||||
|
Loading…
Reference in New Issue
Block a user