1
0

Merge remote-tracking branch 'origin/master' into rxia-testharness-refactor

This commit is contained in:
Richard Xia 2016-09-16 17:10:52 -07:00
commit 63f13ae7ce
33 changed files with 632 additions and 337 deletions

@ -1 +1 @@
Subproject commit 2ff229dac5f915e7f583cbf9cc8118674a4e52a5 Subproject commit dda64c1dee16b5da15ac690bd3cd6759c3d5c032

2
firrtl

@ -1 +1 @@
Subproject commit 7c38199ce7a5d9dd7e27ffbb9b2b2770b972ed94 Subproject commit 726c808375fe513c70376bf05e76dd938e578bf9

View File

@ -139,7 +139,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 */,
@ -170,7 +170,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,

View File

@ -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(
@ -56,7 +56,7 @@ abstract class Coreplex(implicit val p: Parameters, implicit val c: CoreplexConf
val slave = Vec(c.nSlaves, new ClientUncachedTileLinkIO()(innerParams)).flip val slave = Vec(c.nSlaves, new ClientUncachedTileLinkIO()(innerParams)).flip
val interrupts = Vec(c.nExtInterrupts, Bool()).asInput val interrupts = Vec(c.nExtInterrupts, Bool()).asInput
val debug = new DebugBusIO()(p).flip val debug = new DebugBusIO()(p).flip
val prci = Vec(c.nTiles, new PRCITileIO).flip val clint = Vec(c.nTiles, new CoreplexLocalInterrupts).asInput
val success = Bool(OUTPUT) val success = Bool(OUTPUT)
} }
@ -149,8 +149,8 @@ class DefaultCoreplex(tp: Parameters, tc: CoreplexConfig) extends Coreplex()(tp,
// connect coreplex-internal interrupts to tiles // connect coreplex-internal interrupts to tiles
for (((tile, tileReset), i) <- (tileList zip tileResets) zipWithIndex) { for (((tile, tileReset), i) <- (tileList zip tileResets) zipWithIndex) {
tileReset := io.prci(i).reset tileReset := reset // TODO should tiles be reset separately from coreplex?
tile.io.interrupts := io.prci(i).interrupts tile.io.interrupts := io.clint(i)
tile.io.interrupts.meip := plic.io.harts(plic.cfg.context(i, 'M')) tile.io.interrupts.meip := plic.io.harts(plic.cfg.context(i, 'M'))
tile.io.interrupts.seip.foreach(_ := plic.io.harts(plic.cfg.context(i, 'S'))) tile.io.interrupts.seip.foreach(_ := plic.io.harts(plic.cfg.context(i, 'S')))
tile.io.interrupts.debug := debugModule.io.debugInterrupts(i) tile.io.interrupts.debug := debugModule.io.debugInterrupts(i)

View File

@ -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) =>

View File

@ -92,7 +92,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(_, _)),
@ -137,11 +137,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
@ -168,7 +168,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
@ -228,7 +228,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
@ -248,7 +248,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) }
@ -260,6 +260,7 @@ class WithTraceGen extends Config(
knobValues = { knobValues = {
case "L1D_SETS" => 16 case "L1D_SETS" => 16
case "L1D_WAYS" => 1 case "L1D_WAYS" => 1
case _ => throw new CDEMatchError
}) })
class WithPCIeMockupTest extends Config( class WithPCIeMockupTest extends Config(
@ -270,7 +271,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))
@ -304,7 +305,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

View File

@ -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)

View File

@ -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)

View File

@ -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))
@ -152,6 +146,7 @@ class RoccExampleConfig extends Config(new WithRoccExample ++ new BaseConfig)
class WithMIFDataBits(n: Int) extends Config( class WithMIFDataBits(n: Int) extends Config(
(pname, site, here) => pname match { (pname, site, here) => pname match {
case MIFDataBits => Dump("MIF_DATA_BITS", n) case MIFDataBits => Dump("MIF_DATA_BITS", n)
case _ => throw new CDEMatchError
}) })
class MIF128BitConfig extends Config( class MIF128BitConfig extends Config(
@ -183,11 +178,13 @@ class TinyConfig extends Config(
class WithAsyncDebug extends Config ( class WithAsyncDebug extends Config (
(pname, site, here) => pname match { (pname, site, here) => pname match {
case AsyncDebugBus => true case AsyncDebugBus => true
case _ => throw new CDEMatchError
} }
) )
class WithJtagDTM extends Config ( class WithJtagDTM extends Config (
(pname, site, here) => pname match { (pname, site, here) => pname match {
case IncludeJtagDTM => true case IncludeJtagDTM => true
case _ => throw new CDEMatchError
} }
) )

View File

@ -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()
} }

View File

@ -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
@ -277,37 +279,47 @@ trait PeripherySlaveModule extends HasPeripheryParameters {
///// /////
/** Always-ON block */ trait PeripheryCoreplexLocalInterrupter extends LazyModule with HasPeripheryParameters {
trait PeripheryAON extends LazyModule {
implicit val p: Parameters implicit val p: Parameters
val peripheryBus: TLXbar
// CoreplexLocalInterrupter must be at least 64b if XLen >= 64
val beatBytes = (innerMMIOParams(XLen) min 64) / 8
val clintConfig = CoreplexLocalInterrupterConfig(beatBytes)
val clint = LazyModule(new CoreplexLocalInterrupter(clintConfig)(innerMMIOParams))
// The periphery bus is 32-bit, so we may need to adapt its width to XLen
clint.node := TLFragmenter(TLWidthWidget(peripheryBus.node, 4), beatBytes, 256)
// TL1 legacy
val pDevices: ResourceManager[AddrMapEntry] val pDevices: ResourceManager[AddrMapEntry]
pDevices.add(AddrMapEntry("clint", MemRange(clintConfig.address, clintConfig.size, MemAttr(AddrMapProt.RW))))
pDevices.add(AddrMapEntry("prci", MemSize(0x4000000, MemAttr(AddrMapProt.RW))))
} }
trait PeripheryAONBundle { trait PeripheryCoreplexLocalInterrupterBundle {
implicit val p: Parameters implicit val p: Parameters
} }
trait PeripheryAONModule extends HasPeripheryParameters { trait PeripheryCoreplexLocalInterrupterModule extends HasPeripheryParameters {
implicit val p: Parameters implicit val p: Parameters
val outer: PeripheryAON val outer: PeripheryCoreplexLocalInterrupter
val io: PeripheryAONBundle val io: PeripheryCoreplexLocalInterrupterBundle
val mmioNetwork: Option[TileLinkRecursiveInterconnect]
val coreplex: Coreplex val coreplex: Coreplex
val prci = Module(new PRCI()(innerMMIOParams)) outer.clint.module.io.rtcTick := Counter(p(RTCPeriod)).inc()
prci.io.rtcTick := Counter(p(RTCPeriod)).inc() coreplex.io.clint <> outer.clint.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
}
} }

View File

@ -12,11 +12,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)
@ -34,7 +35,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))

View File

@ -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 := coreplex.io.success
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,36 +78,27 @@ 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 := coreplex.io.success
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 PeripheryCoreplexLocalInterrupter
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, _)))
} }
class ExampleTopBundle(p: Parameters, c: Coreplex) extends BaseTopBundle(p, c) class ExampleTopBundle(p: Parameters, c: Coreplex) extends BaseTopBundle(p, c)
with PeripheryBootROMBundle with PeripheryDebugBundle with PeripheryExtInterruptsBundle with PeripheryAONBundle with PeripheryBootROMBundle with PeripheryDebugBundle with PeripheryExtInterruptsBundle with PeripheryCoreplexLocalInterrupterBundle
with PeripheryMasterMemBundle with PeripheryMasterMMIOBundle with PeripherySlaveBundle with PeripheryMasterMemBundle with PeripheryMasterMMIOBundle with PeripherySlaveBundle
class ExampleTopModule[+L <: ExampleTop, +B <: ExampleTopBundle](p: Parameters, l: L, b: Coreplex => B) extends BaseTopModule(p, l, b) class ExampleTopModule[+L <: ExampleTop, +B <: ExampleTopBundle](p: Parameters, l: L, b: Coreplex => B) extends BaseTopModule(p, l, b)
with PeripheryBootROMModule with PeripheryDebugModule with PeripheryExtInterruptsModule with PeripheryAONModule with PeripheryBootROMModule with PeripheryDebugModule with PeripheryExtInterruptsModule with PeripheryCoreplexLocalInterrupterModule
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, _)))
} }

View File

@ -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 clint = CoreplexLocalInterrupterConfig(0, addrMap("io:ext:TL2:clint").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"
@ -94,7 +92,7 @@ object GenerateConfigString {
res append s" ndevs ${c.plicKey.nDevices};\n" res append s" ndevs ${c.plicKey.nDevices};\n"
res append "};\n" res append "};\n"
res append "rtc {\n" res append "rtc {\n"
res append s" addr 0x${(prciAddr + PRCI.time).toString(16)};\n" res append s" addr 0x${clint.timeAddress.toString(16)};\n"
res append "};\n" res append "};\n"
if (addrMap contains "mem") { if (addrMap contains "mem") {
res append "ram {\n" res append "ram {\n"
@ -117,8 +115,8 @@ object GenerateConfigString {
res append s" $i {\n" res append s" $i {\n"
res append " 0 {\n" res append " 0 {\n"
res append s" isa $isa;\n" res append s" isa $isa;\n"
res append s" timecmp 0x${(prciAddr + PRCI.timecmp(i)).toString(16)};\n" res append s" timecmp 0x${clint.timecmpAddress(i).toString(16)};\n"
res append s" ipi 0x${(prciAddr + PRCI.msip(i)).toString(16)};\n" res append s" ipi 0x${clint.msipAddress(i).toString(16)};\n"
res append s" plic {\n" res append s" plic {\n"
res append s" m {\n" res append s" m {\n"
res append s" ie 0x${(plicAddr + c.plicKey.enableAddr(i, 'M')).toString(16)};\n" res append s" ie 0x${(plicAddr + c.plicKey.enableAddr(i, 'M')).toString(16)};\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)
} }
} }

View File

@ -1,7 +1,7 @@
package uncore package uncore
import Chisel._ import Chisel._
import cde.{Config, Parameters, ParameterDump, Knob, Dump} import cde.{Config, Parameters, ParameterDump, Knob, Dump, CDEMatchError}
import junctions.PAddrBits import junctions.PAddrBits
import uncore.tilelink._ import uncore.tilelink._
import uncore.agents._ import uncore.agents._
@ -85,6 +85,7 @@ class DefaultL2Config extends Config (
case ECCCode => None case ECCCode => None
case AmoAluOperandBits => 64 case AmoAluOperandBits => 64
case SplitMetadata => false case SplitMetadata => false
case _ => throw new CDEMatchError
// case XLen => 128 // case XLen => 128
}}, }},
knobValues = { knobValues = {
@ -93,22 +94,24 @@ class DefaultL2Config extends Config (
case "NTILES" => 2 case "NTILES" => 2
case "N_CACHED_TILES" => 2 case "N_CACHED_TILES" => 2
case "L2_CAPACITY_IN_KB" => 256 case "L2_CAPACITY_IN_KB" => 256
case _ => throw new CDEMatchError
} }
) )
class WithPLRU extends Config( class WithPLRU extends Config(
(pname, site, here) => pname match { (pname, site, here) => pname match {
case L2Replacer => () => new SeqPLRU(site(NSets), site(NWays)) case L2Replacer => () => new SeqPLRU(site(NSets), site(NWays))
case _ => throw new CDEMatchError
}) })
class PLRUL2Config extends Config(new WithPLRU ++ new DefaultL2Config) class PLRUL2Config extends Config(new WithPLRU ++ new DefaultL2Config)
class With1L2Ways extends Config(knobValues = { case "L2_WAYS" => 1 }) class With1L2Ways extends Config(knobValues = { case "L2_WAYS" => 1; case _ => throw new CDEMatchError })
class With2L2Ways extends Config(knobValues = { case "L2_WAYS" => 2 }) class With2L2Ways extends Config(knobValues = { case "L2_WAYS" => 2; case _ => throw new CDEMatchError })
class With4L2Ways extends Config(knobValues = { case "L2_WAYS" => 4 }) class With4L2Ways extends Config(knobValues = { case "L2_WAYS" => 4; case _ => throw new CDEMatchError })
class With1Cached extends Config(knobValues = { case "N_CACHED_TILES" => 1 }) class With1Cached extends Config(knobValues = { case "N_CACHED_TILES" => 1; case _ => throw new CDEMatchError })
class With2Cached extends Config(knobValues = { case "N_CACHED_TILES" => 2 }) class With2Cached extends Config(knobValues = { case "N_CACHED_TILES" => 2; case _ => throw new CDEMatchError })
class W1Cached1WaysConfig extends Config(new With1L2Ways ++ new With1Cached ++ new DefaultL2Config) class W1Cached1WaysConfig extends Config(new With1L2Ways ++ new With1Cached ++ new DefaultL2Config)

View File

@ -6,114 +6,84 @@ 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 */
case object NTiles extends Field[Int] case object NTiles extends Field[Int]
class PRCITileIO(implicit p: Parameters) extends Bundle { class CoreplexLocalInterrupts extends Bundle {
val reset = Bool(OUTPUT)
val interrupts = new Bundle {
val mtip = Bool() val mtip = Bool()
val msip = Bool() val msip = Bool()
}
override def cloneType: this.type = new PRCITileIO().asInstanceOf[this.type]
} }
object PRCI { case class CoreplexLocalInterrupterConfig(beatBytes: Int, address: BigInt = 0x44000000) {
def msip(hart: Int) = hart * msipBytes def msipOffset(hart: Int) = hart * msipBytes
def timecmp(hart: Int) = 0x4000 + hart * timecmpBytes def msipAddress(hart: Int) = address + msipOffset(hart)
def time = 0xbff8 def timecmpOffset(hart: Int) = 0x4000 + hart * timecmpBytes
def timecmpAddress(hart: Int) = address + timecmpOffset(hart)
def timeOffset = 0xbff8
def timeAddress = address + timeOffset
def msipBytes = 4 def msipBytes = 4
def timecmpBytes = 8 def timecmpBytes = 8
def size = 0xc000 def size = 0x10000
}
trait MixCoreplexLocalInterrupterParameters {
val params: (CoreplexLocalInterrupterConfig, Parameters)
val c = params._1
implicit val p = params._2
}
trait CoreplexLocalInterrupterBundle extends Bundle with MixCoreplexLocalInterrupterParameters {
val tiles = Vec(p(NTiles), new CoreplexLocalInterrupts).asOutput
val rtcTick = Bool(INPUT)
}
trait CoreplexLocalInterrupterModule extends Module with HasRegMap with MixCoreplexLocalInterrupterParameters {
val io: CoreplexLocalInterrupterBundle
val timeWidth = 64
val time = Reg(init=UInt(0, width = timeWidth))
when (io.rtcTick) { time := time + UInt(1) }
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.msip := ipi(i)(0)
tile.mtip := time >= timecmp(i)
}
def pad = RegField(8) // each use is a new field
val ipi_fields = ipi.map(r => Seq(RegField(1, r), RegField(7), pad, pad, pad)).flatten
val timecmp_fields = timecmp.map(RegField.bytes(_)).flatten
val time_fields = Seq.fill(c.timeOffset % c.beatBytes)(pad) ++ RegField.bytes(time)
/* 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
*/
val ipi_base = 0
val timecmp_base = c.timecmpOffset(0) / c.beatBytes
val time_base = c.timeOffset / c.beatBytes
regmap((
RegField.split(ipi_fields, ipi_base, c.beatBytes) ++
RegField.split(timecmp_fields, timecmp_base, c.beatBytes) ++
RegField.split(time_fields, time_base, c.beatBytes)):_*)
} }
/** Power, Reset, Clock, Interrupt */ /** Power, Reset, Clock, Interrupt */
class PRCI(implicit val p: Parameters) extends Module // Magic TL2 Incantation to create a TL2 Slave
with HasTileLinkParameters class CoreplexLocalInterrupter(c: CoreplexLocalInterrupterConfig)(implicit val p: Parameters)
with HasAddrMapParameters { extends TLRegisterRouter(c.address, 0, c.size, None, c.beatBytes, false)(
val io = new Bundle { new TLRegBundle((c, p), _) with CoreplexLocalInterrupterBundle)(
val tl = new ClientUncachedTileLinkIO().flip new TLRegModule((c, p), _, _) with CoreplexLocalInterrupterModule)
val tiles = Vec(p(NTiles), new PRCITileIO)
val rtcTick = Bool(INPUT)
}
val timeWidth = 64
val timecmp = Reg(Vec(p(NTiles), UInt(width = timeWidth)))
val time = Reg(init=UInt(0, 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))
}
for ((tile, i) <- io.tiles zipWithIndex) {
tile.interrupts.msip := ipi(i)(0)
tile.interrupts.mtip := time >= timecmp(i)
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)))
}
}
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
}
}

View File

@ -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 {

View 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))
}
}
}

View File

@ -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)

View File

@ -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

View File

@ -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))
} }

View File

@ -406,7 +406,7 @@ object TLMonitor
val last_v = RegNext(irr.valid, Bool(false)) val last_v = RegNext(irr.valid, Bool(false))
val last_r = RegNext(irr.ready, Bool(false)) val last_r = RegNext(irr.ready, Bool(false))
val last_b = RegNext(irr.bits) val last_b = RegNext(irr.bits)
val bits_changed = irr.bits.toBits === last_b.toBits val bits_changed = irr.bits.asUInt === last_b.asUInt
when (last_v && !last_r) { when (last_v && !last_r) {
assert(irr.valid, s"${irr.bits.channelName} had contents that were revoked by the supplier (valid lowered)" + extra) assert(irr.valid, s"${irr.bits.channelName} had contents that were revoked by the supplier (valid lowered)" + extra)

View File

@ -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)

View File

@ -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,

View File

@ -105,6 +105,28 @@ 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): Seq[RegField] = {
require (x.getWidth % 8 == 0)
val bytes = Seq.tabulate(x.getWidth/8) { i => x(8*(i+1)-1, 8*i) }
val wires = bytes.map { b => Wire(init = b) }
x := Cat(wires.reverse)
Seq.tabulate(x.getWidth/8) { i =>
RegField(8, bytes(i), RegWriteFn { (valid, data) =>
when (valid) { wires(i) := data }
Bool(true)
})
}
}
// Divide a long sequence of RegFields into a maximum sized registers
// Your input RegFields may not cross a beatBytes boundary!
def split(fields: Seq[RegField], base: Int, beatBytes: Int = 4): Seq[RegField.Map] = {
val offsets = fields.map(_.width).scanLeft(0)(_ + _).init
(offsets zip fields).groupBy(_._1 / (beatBytes*8)).toList.map(r => (r._1 + base, r._2.map(_._2)))
}
} }
trait HasRegMap trait HasRegMap

View File

@ -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)

View File

@ -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

View File

@ -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),

View File

@ -5,13 +5,17 @@ import Chisel._
import cde.{Parameters} import cde.{Parameters}
/** This black-boxes an Async Reset /** This black-boxes an Async Reset
* Reg. * (or Set)
* Register.
* *
* Because Chisel doesn't support * Because Chisel doesn't support
* parameterized black boxes, * parameterized black boxes,
* we unfortunately have to * we unfortunately have to
* instantiate a number of these. * instantiate a number of these.
* *
* We also have to hard-code the set/
* reset behavior.
*
* Do not confuse an asynchronous * Do not confuse an asynchronous
* reset signal with an asynchronously * reset signal with an asynchronously
* reset reg. You should still * reset reg. You should still
@ -22,29 +26,25 @@ import cde.{Parameters}
* @param q Data Output * @param q Data Output
* @param clk Clock Input * @param clk Clock Input
* @param rst Reset Input * @param rst Reset Input
* * @param en Write Enable Input
* @param init Value to write at Reset.
* This is a constant,
* but this construction
* will likely make backend flows
* and lint tools unhappy.
* *
*/ */
class AsyncResetReg extends BlackBox { abstract class AbstractBBReg extends BlackBox {
val io = new Bundle { val io = new Bundle {
val d = Bool(INPUT) val d = Bool(INPUT)
val q = Bool(OUTPUT) val q = Bool(OUTPUT)
val en = Bool(INPUT)
val clk = Clock(INPUT) val clk = Clock(INPUT)
val rst = Bool(INPUT) val rst = Bool(INPUT)
val init = Bool(INPUT)
} }
} }
class AsyncResetReg extends AbstractBBReg
class AsyncSetReg extends AbstractBBReg
class SimpleRegIO(val w: Int) extends Bundle{ class SimpleRegIO(val w: Int) extends Bundle{
@ -55,29 +55,56 @@ class SimpleRegIO(val w: Int) extends Bundle{
} }
class AsyncResetRegVec(val w: Int, val init: Int) extends Module { class AsyncResetRegVec(val w: Int, val init: BigInt) extends Module {
val io = new SimpleRegIO(w) val io = new SimpleRegIO(w)
val bb_q = Wire(UInt(width = w)) val bb_d = Mux(io.en, io.d, io.q)
val bb_d = Wire(UInt(width = w))
val init_val = Wire(UInt(width = w)) val async_regs: List[AbstractBBReg] = List.tabulate(w)(
init_val := UInt(init, width = w) i => Module (
if (((init >> i) % 2) > 0)
val async_regs = List.fill(w)(Module (new AsyncResetReg)) new AsyncSetReg
else
bb_q := (async_regs.map(_.io.q)).asUInt() new AsyncResetReg)
bb_d := Mux(io.en , io.d , bb_q) )
io.q := bb_q
io.q := async_regs.map(_.io.q).asUInt
for ((reg, idx) <- async_regs.zipWithIndex) { for ((reg, idx) <- async_regs.zipWithIndex) {
reg.io.clk := clock reg.io.clk := clock
reg.io.rst := reset reg.io.rst := reset
reg.io.init := init_val(idx)
reg.io.d := bb_d(idx) reg.io.d := bb_d(idx)
reg.io.en := io.en
} }
} }
object AsyncResetReg {
def apply(d: Bool, clk: Clock, rst: Bool, init: Boolean): Bool = {
val reg: AbstractBBReg =
if (init) Module (new AsyncSetReg)
else Module(new AsyncResetReg)
reg.io.d := d
reg.io.clk := clk
reg.io.rst := rst
reg.io.en := Bool(true)
reg.io.q
}
def apply(d: Bool, clk: Clock, rst: Bool): Bool = apply(d, clk, rst, false)
def apply(updateData: UInt, resetData: BigInt, enable: Bool): UInt = {
val w = updateData.getWidth max resetData.bitLength
val reg = Module(new AsyncResetRegVec(w, resetData))
reg.io.d := updateData
reg.io.en := enable
reg.io.q
}
def apply(updateData: UInt, resetData: BigInt): UInt = apply(updateData, resetData, enable=Bool(true))
def apply(updateData: UInt, enable: Bool): UInt = apply(updateData, resetData=BigInt(0), enable)
def apply(updateData: UInt): UInt = apply(updateData, resetData=BigInt(0), enable=Bool(true))
}

View File

@ -11,10 +11,10 @@ class TestHarness(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 uncore.tilelink.TLId => "L1toL2" }) case uncore.tilelink.TLId => "L1toL2" })
val tests = Module(new UnitTestSuite()(l1params)) val tests = Module(new UnitTestSuite()(l1params))
io.success := tests.io.finished io.success := tests.io.finished

View File

@ -8,6 +8,7 @@ bb_vsrcs = $(base_dir)/vsrc/DebugTransportModuleJtag.v \
$(base_dir)/vsrc/jtag_vpi.v \ $(base_dir)/vsrc/jtag_vpi.v \
$(base_dir)/vsrc/AsyncMailbox.v \ $(base_dir)/vsrc/AsyncMailbox.v \
$(base_dir)/vsrc/AsyncResetReg.v \ $(base_dir)/vsrc/AsyncResetReg.v \
$(base_dir)/vsrc/AsyncSetReg.v \
$(base_dir)/vsrc/ClockDivider.v \ $(base_dir)/vsrc/ClockDivider.v \
$(base_dir)/vsrc/ClockToSignal.v \ $(base_dir)/vsrc/ClockToSignal.v \
$(base_dir)/vsrc/SignalToClock.v \ $(base_dir)/vsrc/SignalToClock.v \

View File

@ -8,6 +8,8 @@
* we unfortunately have to * we unfortunately have to
* instantiate a number of these. * instantiate a number of these.
* *
* We also have to hard-code the set/reset.
*
* Do not confuse an asynchronous * Do not confuse an asynchronous
* reset signal with an asynchronously * reset signal with an asynchronously
* reset reg. You should still * reset reg. You should still
@ -18,32 +20,25 @@
* @param q Data Output * @param q Data Output
* @param clk Clock Input * @param clk Clock Input
* @param rst Reset Input * @param rst Reset Input
* * @param en Write Enable Input
* @param init Value to write at Reset.
* This is a constant,
* but this construction
* will likely make backend flows
* and lint tools unhappy.
* *
*/ */
module AsyncResetReg ( module AsyncResetReg (
input d, input d,
output reg q, output reg q,
input en,
input clk, input clk,
input rst, input rst);
input init);
always @(posedge clk or posedge rst) begin always @(posedge clk or posedge rst) begin
if (rst) begin if (rst) begin
q <= init; q <= 1'b0;
end else begin end else if (en) begin
q <= d; q <= d;
end end
end end

47
vsrc/AsyncSetReg.v Normal file
View File

@ -0,0 +1,47 @@
/** This black-boxes an Async Set
* Reg.
*
* Because Chisel doesn't support
* parameterized black boxes,
* we unfortunately have to
* instantiate a number of these.
*
* We also have to hard-code the set/reset.
*
* Do not confuse an asynchronous
* reset signal with an asynchronously
* reset reg. You should still
* properly synchronize your reset
* deassertion.
*
* @param d Data input
* @param q Data Output
* @param clk Clock Input
* @param rst Reset Input
* @param en Write Enable Input
*
*/
module AsyncSetReg (
input d,
output reg q,
input en,
input clk,
input rst);
always @(posedge clk or posedge rst) begin
if (rst) begin
q <= 1'b1;
end else if (en) begin
q <= d;
end
end
endmodule // AsyncSetReg