1
0

Merge remote-tracking branch 'origin' into testharness-refactor

This commit is contained in:
Henry Cook 2016-09-20 13:03:21 -07:00
commit ed91e9a89b
30 changed files with 335 additions and 174 deletions

View File

@ -124,8 +124,7 @@ class BaseCoreplexConfig extends Config (
case UseCompressed => true case UseCompressed => true
case DMKey => new DefaultDebugModuleConfig(site(NTiles), site(XLen)) case DMKey => new DefaultDebugModuleConfig(site(NTiles), site(XLen))
case NCustomMRWCSRs => 0 case NCustomMRWCSRs => 0
case ResetVector => BigInt(0x1000) case MtvecInit => None
case MtvecInit => BigInt(0x1010)
case MtvecWritable => true case MtvecWritable => true
//Uncore Paramters //Uncore Paramters
case LNEndpoints => site(TLKey(site(TLId))).nManagers + site(TLKey(site(TLId))).nClients case LNEndpoints => site(TLKey(site(TLId))).nManagers + site(TLKey(site(TLId))).nClients

View File

@ -58,6 +58,7 @@ abstract class Coreplex(implicit val p: Parameters, implicit val c: CoreplexConf
val debug = new DebugBusIO()(p).flip val debug = new DebugBusIO()(p).flip
val clint = Vec(c.nTiles, new CoreplexLocalInterrupts).asInput val clint = Vec(c.nTiles, new CoreplexLocalInterrupts).asInput
val success = Bool(OUTPUT) val success = Bool(OUTPUT)
val resetVector = UInt(INPUT, p(XLen))
} }
val io = new CoreplexIO val io = new CoreplexIO
@ -155,6 +156,7 @@ class DefaultCoreplex(tp: Parameters, tc: CoreplexConfig) extends Coreplex()(tp,
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)
tile.io.hartid := i tile.io.hartid := i
tile.io.resetVector := io.resetVector
} }
val tileSlavePorts = (0 until tc.nTiles) map (i => s"int:dmem$i") filter (ioAddrMap contains _) val tileSlavePorts = (0 until tc.nTiles) map (i => s"int:dmem$i") filter (ioAddrMap contains _)

View File

@ -125,7 +125,7 @@ class AddrMap(
val brEnd = br.start + br.size val brEnd = br.start + br.size
val abOverlaps = ar.start < brEnd && br.start < arEnd val abOverlaps = ar.start < brEnd && br.start < arEnd
require(!abOverlaps, require(!abOverlaps,
"region $an@0x${ar.start.toString(16)} overlaps region $bn@0x${br.start.toString(16)}") s"region $an@0x${ar.start.toString(16)} overlaps region $bn@0x${br.start.toString(16)}")
} }
def toRange: MemRange = MemRange(start, size, attr) def toRange: MemRange = MemRange(start, size, attr)

View File

@ -227,7 +227,11 @@ class CSRFile(implicit p: Parameters) extends CoreModule()(p)
val reg_mcause = Reg(Bits(width = xLen)) val reg_mcause = Reg(Bits(width = xLen))
val reg_mbadaddr = Reg(UInt(width = vaddrBitsExtended)) val reg_mbadaddr = Reg(UInt(width = vaddrBitsExtended))
val reg_mscratch = Reg(Bits(width = xLen)) val reg_mscratch = Reg(Bits(width = xLen))
val reg_mtvec = Reg(init=UInt(p(MtvecInit), paddrBits min xLen)) val mtvecWidth = paddrBits min xLen
val reg_mtvec = p(MtvecInit) match {
case Some(addr) => Reg(init=UInt(addr, mtvecWidth))
case None => Reg(UInt(width = mtvecWidth))
}
val reg_mucounteren = Reg(UInt(width = 32)) val reg_mucounteren = Reg(UInt(width = 32))
val reg_mscounteren = Reg(UInt(width = 32)) val reg_mscounteren = Reg(UInt(width = 32))
val delegable_counters = (BigInt(1) << (nPerfCounters + CSR.firstHPM)) - 1 val delegable_counters = (BigInt(1) << (nPerfCounters + CSR.firstHPM)) - 1

View File

@ -35,6 +35,7 @@ class Frontend(implicit p: Parameters) extends CoreModule()(p) with HasL1CachePa
val cpu = new FrontendIO().flip val cpu = new FrontendIO().flip
val ptw = new TLBPTWIO() val ptw = new TLBPTWIO()
val mem = new ClientUncachedTileLinkIO val mem = new ClientUncachedTileLinkIO
val resetVector = UInt(INPUT, vaddrBitsExtended)
} }
val icache = Module(new ICache(latency = 2)) val icache = Module(new ICache(latency = 2))
@ -45,7 +46,7 @@ class Frontend(implicit p: Parameters) extends CoreModule()(p) with HasL1CachePa
val s1_speculative = Reg(Bool()) val s1_speculative = Reg(Bool())
val s1_same_block = Reg(Bool()) val s1_same_block = Reg(Bool())
val s2_valid = Reg(init=Bool(true)) val s2_valid = Reg(init=Bool(true))
val s2_pc = Reg(init=UInt(p(ResetVector))) val s2_pc = Reg(init=io.resetVector)
val s2_btb_resp_valid = Reg(init=Bool(false)) val s2_btb_resp_valid = Reg(init=Bool(false))
val s2_btb_resp_bits = Reg(new BTBResp) val s2_btb_resp_bits = Reg(new BTBResp)
val s2_xcpt_if = Reg(init=Bool(false)) val s2_xcpt_if = Reg(init=Bool(false))

View File

@ -27,8 +27,7 @@ case object FastJAL extends Field[Boolean]
case object CoreInstBits extends Field[Int] case object CoreInstBits extends Field[Int]
case object NCustomMRWCSRs extends Field[Int] case object NCustomMRWCSRs extends Field[Int]
case object MtvecWritable extends Field[Boolean] case object MtvecWritable extends Field[Boolean]
case object MtvecInit extends Field[BigInt] case object MtvecInit extends Field[Option[BigInt]]
case object ResetVector extends Field[BigInt]
case object NBreakpoints extends Field[Int] case object NBreakpoints extends Field[Int]
case object NPerfCounters extends Field[Int] case object NPerfCounters extends Field[Int]
case object NPerfEvents extends Field[Int] case object NPerfEvents extends Field[Int]

View File

@ -34,6 +34,7 @@ abstract class Tile(clockSignal: Clock = null, resetSignal: Bool = null)
val hartid = UInt(INPUT, p(XLen)) val hartid = UInt(INPUT, p(XLen))
val interrupts = new TileInterrupts().asInput val interrupts = new TileInterrupts().asInput
val slave = (p(DataScratchpadSize) > 0).option(new ClientUncachedTileLinkIO().flip) val slave = (p(DataScratchpadSize) > 0).option(new ClientUncachedTileLinkIO().flip)
val resetVector = UInt(INPUT, p(XLen))
} }
val io = new TileIO val io = new TileIO
@ -58,6 +59,7 @@ class RocketTile(clockSignal: Clock = null, resetSignal: Bool = null)
core.io.interrupts := io.interrupts core.io.interrupts := io.interrupts
core.io.hartid := io.hartid core.io.hartid := io.hartid
icache.io.cpu <> core.io.imem icache.io.cpu <> core.io.imem
icache.io.resetVector := io.resetVector
val fpuOpt = p(FPUKey).map(cfg => Module(new FPU(cfg))) val fpuOpt = p(FPUKey).map(cfg => Module(new FPU(cfg)))
fpuOpt.foreach(fpu => core.io.fpu <> fpu.io) fpuOpt.foreach(fpu => core.io.fpu <> fpu.io)

View File

@ -127,21 +127,28 @@ object Split
} }
// a counter that clock gates most of its MSBs using the LSB carry-out // a counter that clock gates most of its MSBs using the LSB carry-out
case class WideCounter(width: Int, inc: UInt = UInt(1)) case class WideCounter(width: Int, inc: UInt = UInt(1), reset: Boolean = true)
{ {
private val isWide = width > 2*inc.getWidth private val isWide = width > 2*inc.getWidth
private val smallWidth = if (isWide) inc.getWidth max log2Up(width) else width private val smallWidth = if (isWide) inc.getWidth max log2Up(width) else width
private val small = Reg(init=UInt(0, smallWidth)) private val small = if (reset) Reg(init=UInt(0, smallWidth)) else Reg(UInt(width = smallWidth))
private val nextSmall = small +& inc private val nextSmall = small +& inc
small := nextSmall small := nextSmall
private val large = if (isWide) { private val large = if (isWide) {
val r = Reg(init=UInt(0, width - smallWidth)) val r = if (reset) Reg(init=UInt(0, width - smallWidth)) else Reg(UInt(width = width - smallWidth))
when (nextSmall(smallWidth)) { r := r + UInt(1) } when (nextSmall(smallWidth)) { r := r +& UInt(1) }
r r
} else null } else null
val value = if (isWide) Cat(large, small) else small val value = if (isWide) Cat(large, small) else small
lazy val carryOut = {
val lo = (small ^ nextSmall) >> 1
if (!isWide) lo else {
val hi = Mux(nextSmall(smallWidth), large ^ (large +& UInt(1)), UInt(0)) >> 1
Cat(hi, lo)
}
}
def := (x: UInt) = { def := (x: UInt) = {
small := x small := x

View File

@ -27,6 +27,10 @@ abstract class BaseTop(q: Parameters) extends LazyModule {
val pBusMasters = new RangeManager val pBusMasters = new RangeManager
val pDevices = new ResourceManager[AddrMapEntry] val pDevices = new ResourceManager[AddrMapEntry]
// Add a peripheral bus
val peripheryBus = LazyModule(new TLXbar)
lazy val peripheryManagers = peripheryBus.node.edgesIn(0).manager.managers
lazy val c = CoreplexConfig( lazy val c = CoreplexConfig(
nTiles = q(NTiles), nTiles = q(NTiles),
nExtInterrupts = pInterrupts.sum, nExtInterrupts = pInterrupts.sum,
@ -36,16 +40,14 @@ abstract class BaseTop(q: Parameters) extends LazyModule {
hasExtMMIOPort = true hasExtMMIOPort = true
) )
lazy val genGlobalAddrMap = GenerateGlobalAddrMap(q, pDevices.get) lazy val genGlobalAddrMap = GenerateGlobalAddrMap(q, pDevices.get, peripheryManagers)
private val qWithMap = q.alterPartial({case GlobalAddrMap => genGlobalAddrMap}) private val qWithMap = q.alterPartial({case GlobalAddrMap => genGlobalAddrMap})
lazy val genConfigString = GenerateConfigString(qWithMap, c, pDevices.get) lazy val genConfigString = GenerateConfigString(qWithMap, c, pDevices.get, peripheryManagers)
implicit val p = qWithMap.alterPartial({ implicit val p = qWithMap.alterPartial({
case ConfigString => genConfigString case ConfigString => genConfigString
case NCoreplexExtClients => pBusMasters.sum}) case NCoreplexExtClients => pBusMasters.sum})
// Add a peripheral bus
val peripheryBus = LazyModule(new TLXbar)
val legacy = LazyModule(new TLLegacy()(p.alterPartial({ case TLId => "L2toMMIO" }))) val legacy = LazyModule(new TLLegacy()(p.alterPartial({ case TLId => "L2toMMIO" })))
peripheryBus.node := TLBuffer(TLWidthWidget(TLHintHandler(legacy.node), legacy.tlDataBytes)) peripheryBus.node := TLBuffer(TLWidthWidget(TLHintHandler(legacy.node), legacy.tlDataBytes))
@ -55,7 +57,7 @@ class BaseTopBundle(val p: Parameters, val c: Coreplex) extends ParameterizedBun
val success = Bool(OUTPUT) val success = Bool(OUTPUT)
} }
class BaseTopModule[+L <: BaseTop, +B <: BaseTopBundle](val p: Parameters, l: L, b: Coreplex => B) extends LazyModuleImp(l) { abstract 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 coreplex = p(BuildCoreplex)(p, outer.c) val coreplex = p(BuildCoreplex)(p, outer.c)
@ -72,7 +74,12 @@ class BaseTopModule[+L <: BaseTop, +B <: BaseTopBundle](val p: Parameters, l: L,
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
println(f"\t$name%s $start%x - $end%x") val prot = entry.region.attr.prot
val protStr = (if ((prot & AddrMapProt.R) > 0) "R" else "") +
(if ((prot & AddrMapProt.W) > 0) "W" else "") +
(if ((prot & AddrMapProt.X) > 0) "X" else "")
val cacheable = if (entry.region.attr.cacheable) " [C]" else ""
println(f"\t$name%s $start%x - $end%x, $protStr$cacheable")
} }
println("Generated Configuration String") println("Generated Configuration String")

View File

@ -21,6 +21,7 @@ class ExampleTopBundle(p: Parameters, c: Coreplex) extends BaseTopBundle(p, c)
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 PeripheryCoreplexLocalInterrupterModule with PeripheryBootROMModule with PeripheryDebugModule with PeripheryExtInterruptsModule with PeripheryCoreplexLocalInterrupterModule
with PeripheryMasterMemModule with PeripheryMasterMMIOModule with PeripherySlaveModule with PeripheryMasterMemModule with PeripheryMasterMMIOModule with PeripherySlaveModule
with HardwiredResetVector
/** Example Top with TestRAM */ /** Example Top with TestRAM */
class ExampleTopWithTestRAM(q: Parameters) extends ExampleTop(q) class ExampleTopWithTestRAM(q: Parameters) extends ExampleTop(q)

View File

@ -289,10 +289,6 @@ trait PeripheryCoreplexLocalInterrupter extends LazyModule with HasPeripheryPara
val clint = LazyModule(new CoreplexLocalInterrupter(clintConfig)(innerMMIOParams)) val clint = LazyModule(new CoreplexLocalInterrupter(clintConfig)(innerMMIOParams))
// The periphery bus is 32-bit, so we may need to adapt its width to XLen // 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) clint.node := TLFragmenter(TLWidthWidget(peripheryBus.node, 4), beatBytes, 256)
// TL1 legacy
val pDevices: ResourceManager[AddrMapEntry]
pDevices.add(AddrMapEntry("clint", MemRange(clintConfig.address, clintConfig.size, MemAttr(AddrMapProt.RW))))
} }
trait PeripheryCoreplexLocalInterrupterBundle { trait PeripheryCoreplexLocalInterrupterBundle {
@ -315,12 +311,10 @@ trait PeripheryBootROM extends LazyModule {
implicit val p: Parameters implicit val p: Parameters
val peripheryBus: TLXbar val peripheryBus: TLXbar
val rom = LazyModule(new TLROM(0x1000, 0x1000, GenerateBootROM(p))) val address = 0x1000
val size = 0x1000
val rom = LazyModule(new TLROM(address, size, GenerateBootROM(p, address)) { override def name = "bootrom" })
rom.node := TLFragmenter(peripheryBus.node, 4, 256) 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))))
} }
trait PeripheryBootROMBundle { trait PeripheryBootROMBundle {
@ -342,12 +336,8 @@ trait PeripheryTestRAM extends LazyModule {
val ramBase = 0x52000000 val ramBase = 0x52000000
val ramSize = 0x1000 val ramSize = 0x1000
val sram = LazyModule(new TLRAM(AddressSet(ramBase, ramSize-1))) val sram = LazyModule(new TLRAM(AddressSet(ramBase, ramSize-1)) { override def name = "testram" })
sram.node := TLFragmenter(peripheryBus.node, 4, 256) 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 {
@ -377,3 +367,10 @@ trait PeripheryTestBusMasterModule {
implicit val p: Parameters implicit val p: Parameters
val outer: PeripheryTestBusMaster val outer: PeripheryTestBusMaster
} }
/////
trait HardwiredResetVector {
val coreplex: Coreplex
coreplex.io.resetVector := UInt(0x1000) // boot ROM
}

View File

@ -8,6 +8,7 @@ import uncore.devices._
import rocket._ import rocket._
import rocket.Util._ import rocket.Util._
import coreplex._ import coreplex._
import uncore.tilelink2._
import java.nio.file.{Files, Paths} import java.nio.file.{Files, Paths}
import java.nio.{ByteBuffer, ByteOrder} import java.nio.{ByteBuffer, ByteOrder}
@ -51,7 +52,7 @@ class GlobalVariable[T] {
} }
object GenerateGlobalAddrMap { object GenerateGlobalAddrMap {
def apply(p: Parameters, pDevicesEntries: Seq[AddrMapEntry]) = { def apply(p: Parameters, pDevicesEntries: Seq[AddrMapEntry], peripheryManagers: Seq[TLManagerParameters]) = {
lazy val intIOAddrMap: AddrMap = { lazy val intIOAddrMap: AddrMap = {
val entries = collection.mutable.ArrayBuffer[AddrMapEntry]() val entries = collection.mutable.ArrayBuffer[AddrMapEntry]()
entries += AddrMapEntry("debug", MemSize(4096, MemAttr(AddrMapProt.RWX))) entries += AddrMapEntry("debug", MemSize(4096, MemAttr(AddrMapProt.RWX)))
@ -64,8 +65,26 @@ object GenerateGlobalAddrMap {
new AddrMap(entries) new AddrMap(entries)
} }
lazy val tl2AddrMap = new AddrMap(pDevicesEntries, collapse = true) lazy val tl2Devices = peripheryManagers.map { manager =>
lazy val extIOAddrMap = new AddrMap(AddrMapEntry("TL2", tl2AddrMap) +: p(ExtMMIOPorts), collapse = true) val cacheable = manager.regionType match {
case RegionType.CACHED => true
case RegionType.TRACKED => true
case _ => false
}
val attr = MemAttr(
(if (manager.supportsGet) AddrMapProt.R else 0) |
(if (manager.supportsPutFull) AddrMapProt.W else 0) |
(if (manager.executable) AddrMapProt.X else 0), cacheable)
val multi = manager.address.size > 1
manager.address.zipWithIndex.map { case (address, i) =>
require (address.contiguous) // TL1 needs this
val name = manager.name + (if (multi) ".%d".format(i) else "")
AddrMapEntry(name, MemRange(address.base, address.mask+1, attr))
}
}.flatten
lazy val tl2AddrMap = new AddrMap(tl2Devices, collapse = true)
lazy val extIOAddrMap = new AddrMap(AddrMapEntry("TL2", tl2AddrMap) +: (p(ExtMMIOPorts) ++ pDevicesEntries), collapse = true)
val memBase = 0x80000000L val memBase = 0x80000000L
val memSize = p(ExtMemSize) val memSize = p(ExtMemSize)
@ -80,7 +99,7 @@ object GenerateGlobalAddrMap {
} }
object GenerateConfigString { object GenerateConfigString {
def apply(p: Parameters, c: CoreplexConfig, pDevicesEntries: Seq[AddrMapEntry]) = { def apply(p: Parameters, c: CoreplexConfig, pDevicesEntries: Seq[AddrMapEntry], peripheryManagers: Seq[TLManagerParameters]) = {
val addrMap = p(GlobalAddrMap) val addrMap = p(GlobalAddrMap)
val plicAddr = addrMap("io:int:plic").start val plicAddr = addrMap("io:int:plic").start
val clint = CoreplexLocalInterrupterConfig(0, addrMap("io:ext:TL2:clint").start) val clint = CoreplexLocalInterrupterConfig(0, addrMap("io:ext:TL2:clint").start)
@ -136,33 +155,27 @@ object GenerateConfigString {
} }
res append "};\n" res append "};\n"
pDevicesEntries foreach { entry => pDevicesEntries foreach { entry =>
val region = addrMap("io:ext:TL2:" + entry.name) val region = addrMap("io:ext:" + 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"
res append "}\n" res append "}\n"
} }
peripheryManagers.foreach { manager => res append manager.dts }
res append '\u0000' res append '\u0000'
res.toString res.toString
} }
} }
object GenerateBootROM { object GenerateBootROM {
def apply(p: Parameters) = { def apply(p: Parameters, address: BigInt) = {
val romdata = Files.readAllBytes(Paths.get(p(BootROMFile))) val romdata = Files.readAllBytes(Paths.get(p(BootROMFile)))
val rom = ByteBuffer.wrap(romdata) val rom = ByteBuffer.wrap(romdata)
rom.order(ByteOrder.LITTLE_ENDIAN) rom.order(ByteOrder.LITTLE_ENDIAN)
// for now, have the reset vector jump straight to memory require(address == address.toInt)
val memBase = ( val configStringAddr = address.toInt + rom.capacity
if (p(GlobalAddrMap) contains "mem") p(GlobalAddrMap)("mem")
else p(GlobalAddrMap)("io:int:dmem0")
).start
val resetToMemDist = memBase - p(ResetVector)
require(resetToMemDist == (resetToMemDist.toInt >> 12 << 12))
val configStringAddr = p(ResetVector).toInt + rom.capacity
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)

View File

@ -87,3 +87,6 @@ class CoreplexLocalInterrupter(c: CoreplexLocalInterrupterConfig)(implicit val p
extends TLRegisterRouter(c.address, 0, c.size, None, c.beatBytes, false)( extends TLRegisterRouter(c.address, 0, c.size, None, c.beatBytes, false)(
new TLRegBundle((c, p), _) with CoreplexLocalInterrupterBundle)( new TLRegBundle((c, p), _) with CoreplexLocalInterrupterBundle)(
new TLRegModule((c, p), _, _) with CoreplexLocalInterrupterModule) new TLRegModule((c, p), _, _) with CoreplexLocalInterrupterModule)
{
override def name = "clint" // defaul is "CoreplexLocalInterrupter"
}

View File

@ -8,11 +8,12 @@ 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 class TLROM(val base: BigInt, val size: Int, contentsDelayed: => Seq[Byte], executable: Boolean = true, beatBytes: Int = 4) extends LazyModule
{ {
val node = TLManagerNode(beatBytes, TLManagerParameters( val node = TLManagerNode(beatBytes, TLManagerParameters(
address = List(AddressSet(base, size-1)), address = List(AddressSet(base, size-1)),
regionType = RegionType.UNCACHED, regionType = RegionType.UNCACHED,
executable = executable,
supportsGet = TransferSizes(1, beatBytes), supportsGet = TransferSizes(1, beatBytes),
fifoId = Some(0))) fifoId = Some(0)))

View File

@ -25,13 +25,25 @@ object AddressDecoder
// Verify the user did not give us an impossible problem // Verify the user did not give us an impossible problem
ports.combinations(2).foreach { case Seq(x, y) => ports.combinations(2).foreach { case Seq(x, y) =>
x.foreach { a => y.foreach { b => x.foreach { a => y.foreach { b =>
require (!a.overlaps(b)) // it must be possible to disambiguate addresses! require (!a.overlaps(b)) // it must be possible to disambiguate ports!
} } } }
} }
val maxBits = log2Ceil(ports.map(_.map(_.max).max).max + 1) val maxBits = log2Ceil(ports.map(_.map(_.max).max).max + 1)
val bits = (0 until maxBits).map(BigInt(1) << _).toSeq val bits = (0 until maxBits).map(BigInt(1) << _).toSeq
val selected = recurse(Seq(ports.map(_.sorted).sorted(portOrder)), bits) val selected = recurse(Seq(ports.map(_.sorted).sorted(portOrder)), bits)
selected.reduceLeft(_ | _) val output = selected.reduceLeft(_ | _)
// Modify the AddressSets to allow the new wider match functions
val widePorts = ports.map { _.map { _.widen(~output) } }
// Verify that it remains possible to disambiguate all ports
widePorts.combinations(2).foreach { case Seq(x, y) =>
x.foreach { a => y.foreach { b =>
require (!a.overlaps(b))
} }
}
output
} }
// A simpler version that works for a Seq[Int] // A simpler version that works for a Seq[Int]
@ -51,11 +63,12 @@ object AddressDecoder
// pick the bit which minimizes the number of ports in each partition // pick the bit which minimizes the number of ports in each partition
// as a secondary goal, reduce the number of AddressSets within a partition // as a secondary goal, reduce the number of AddressSets within a partition
val bigValue = 100000 def bitScore(partitions: Partitions): Seq[Int] = {
def bitScore(partitions: Partitions): Int = {
val maxPortsPerPartition = partitions.map(_.size).max val maxPortsPerPartition = partitions.map(_.size).max
val sumPortsPerPartition = partitions.map(_.size).sum
val maxSetsPerPartition = partitions.map(_.map(_.size).sum).max val maxSetsPerPartition = partitions.map(_.map(_.size).sum).max
maxPortsPerPartition * bigValue + maxSetsPerPartition val sumSetsPerPartition = partitions.map(_.map(_.size).sum).sum
Seq(maxPortsPerPartition, sumPortsPerPartition, maxSetsPerPartition, sumSetsPerPartition)
} }
def partitionPort(port: Port, bit: BigInt): (Port, Port) = { def partitionPort(port: Port, bit: BigInt): (Port, Port) = {
@ -77,8 +90,8 @@ object AddressDecoder
def partitionPartitions(partitions: Partitions, bit: BigInt): Partitions = { def partitionPartitions(partitions: Partitions, bit: BigInt): Partitions = {
val partitioned_partitions = partitions.map(p => partitionPorts(p, bit)) val partitioned_partitions = partitions.map(p => partitionPorts(p, bit))
val case_a_partitions = partitioned_partitions.map(_._1) val case_a_partitions = partitioned_partitions.map(_._1).filter(!_.isEmpty)
val case_b_partitions = partitioned_partitions.map(_._2) val case_b_partitions = partitioned_partitions.map(_._2).filter(!_.isEmpty)
val new_partitions = (case_a_partitions ++ case_b_partitions).sorted(partitionOrder) val new_partitions = (case_a_partitions ++ case_b_partitions).sorted(partitionOrder)
// Prevent combinational memory explosion; if two partitions are equal, keep only one // 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. // Note: AddressSets in a port are sorted, and ports in a partition are sorted.
@ -106,9 +119,9 @@ object AddressDecoder
val score = bitScore(result) val score = bitScore(result)
(score, bit, result) (score, bit, result)
} }
val (bestScore, bestBit, bestPartitions) = candidates.min(Ordering.by[(Int, BigInt, Partitions), Int](_._1)) val (bestScore, bestBit, bestPartitions) = candidates.min(Ordering.by[(Seq[Int], BigInt, Partitions), Iterable[Int]](_._1.toIterable))
if (debug) println("=> Selected bit 0x%x".format(bestBit)) if (debug) println("=> Selected bit 0x%x".format(bestBit))
if (bestScore < 2*bigValue) { if (bestScore(0) <= 1) {
if (debug) println("---") if (debug) println("---")
Seq(bestBit) Seq(bestBit)
} else { } else {

View File

@ -231,7 +231,7 @@ class TLEdgeOut(
// Transfers // Transfers
def Acquire(fromSource: UInt, toAddress: UInt, lgSize: UInt, growPermissions: UInt) = { def Acquire(fromSource: UInt, toAddress: UInt, lgSize: UInt, growPermissions: UInt) = {
require (manager.anySupportAcquire) require (manager.anySupportAcquire)
val legal = manager.supportsAcquire(toAddress, lgSize) val legal = manager.supportsAcquireFast(toAddress, lgSize)
val a = Wire(new TLBundleA(bundle)) val a = Wire(new TLBundleA(bundle))
a.opcode := TLMessages.Acquire a.opcode := TLMessages.Acquire
a.param := growPermissions a.param := growPermissions
@ -245,7 +245,7 @@ class TLEdgeOut(
def Release(fromSource: UInt, toAddress: UInt, lgSize: UInt, shrinkPermissions: UInt) = { def Release(fromSource: UInt, toAddress: UInt, lgSize: UInt, shrinkPermissions: UInt) = {
require (manager.anySupportAcquire) require (manager.anySupportAcquire)
val legal = manager.supportsAcquire(toAddress, lgSize) val legal = manager.supportsAcquireFast(toAddress, lgSize)
val c = Wire(new TLBundleC(bundle)) val c = Wire(new TLBundleC(bundle))
c.opcode := TLMessages.Release c.opcode := TLMessages.Release
c.param := shrinkPermissions c.param := shrinkPermissions
@ -260,7 +260,7 @@ class TLEdgeOut(
def Release(fromSource: UInt, toAddress: UInt, lgSize: UInt, shrinkPermissions: UInt, data: UInt) = { def Release(fromSource: UInt, toAddress: UInt, lgSize: UInt, shrinkPermissions: UInt, data: UInt) = {
require (manager.anySupportAcquire) require (manager.anySupportAcquire)
val legal = manager.supportsAcquire(toAddress, lgSize) val legal = manager.supportsAcquireFast(toAddress, lgSize)
val c = Wire(new TLBundleC(bundle)) val c = Wire(new TLBundleC(bundle))
c.opcode := TLMessages.ReleaseData c.opcode := TLMessages.ReleaseData
c.param := shrinkPermissions c.param := shrinkPermissions
@ -308,7 +308,7 @@ class TLEdgeOut(
// Accesses // Accesses
def Get(fromSource: UInt, toAddress: UInt, lgSize: UInt) = { def Get(fromSource: UInt, toAddress: UInt, lgSize: UInt) = {
require (manager.anySupportGet) require (manager.anySupportGet)
val legal = manager.supportsGet(toAddress, lgSize) val legal = manager.supportsGetFast(toAddress, lgSize)
val a = Wire(new TLBundleA(bundle)) val a = Wire(new TLBundleA(bundle))
a.opcode := TLMessages.Get a.opcode := TLMessages.Get
a.param := UInt(0) a.param := UInt(0)
@ -322,7 +322,7 @@ class TLEdgeOut(
def Put(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt) = { def Put(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt) = {
require (manager.anySupportPutFull) require (manager.anySupportPutFull)
val legal = manager.supportsPutFull(toAddress, lgSize) val legal = manager.supportsPutFullFast(toAddress, lgSize)
val a = Wire(new TLBundleA(bundle)) val a = Wire(new TLBundleA(bundle))
a.opcode := TLMessages.PutFullData a.opcode := TLMessages.PutFullData
a.param := UInt(0) a.param := UInt(0)
@ -336,7 +336,7 @@ class TLEdgeOut(
def Put(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, mask : UInt) = { def Put(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, mask : UInt) = {
require (manager.anySupportPutPartial) require (manager.anySupportPutPartial)
val legal = manager.supportsPutPartial(toAddress, lgSize) val legal = manager.supportsPutPartialFast(toAddress, lgSize)
val a = Wire(new TLBundleA(bundle)) val a = Wire(new TLBundleA(bundle))
a.opcode := TLMessages.PutPartialData a.opcode := TLMessages.PutPartialData
a.param := UInt(0) a.param := UInt(0)
@ -350,7 +350,7 @@ class TLEdgeOut(
def Arithmetic(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, atomic: UInt) = { def Arithmetic(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, atomic: UInt) = {
require (manager.anySupportArithmetic) require (manager.anySupportArithmetic)
val legal = manager.supportsArithmetic(toAddress, lgSize) val legal = manager.supportsArithmeticFast(toAddress, lgSize)
val a = Wire(new TLBundleA(bundle)) val a = Wire(new TLBundleA(bundle))
a.opcode := TLMessages.ArithmeticData a.opcode := TLMessages.ArithmeticData
a.param := atomic a.param := atomic
@ -364,7 +364,7 @@ class TLEdgeOut(
def Logical(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, atomic: UInt) = { def Logical(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, atomic: UInt) = {
require (manager.anySupportLogical) require (manager.anySupportLogical)
val legal = manager.supportsLogical(toAddress, lgSize) val legal = manager.supportsLogicalFast(toAddress, lgSize)
val a = Wire(new TLBundleA(bundle)) val a = Wire(new TLBundleA(bundle))
a.opcode := TLMessages.LogicalData a.opcode := TLMessages.LogicalData
a.param := atomic a.param := atomic
@ -378,7 +378,7 @@ class TLEdgeOut(
def Hint(fromSource: UInt, toAddress: UInt, lgSize: UInt, param: UInt) = { def Hint(fromSource: UInt, toAddress: UInt, lgSize: UInt, param: UInt) = {
require (manager.anySupportHint) require (manager.anySupportHint)
val legal = manager.supportsHint(toAddress, lgSize) val legal = manager.supportsHintFast(toAddress, lgSize)
val a = Wire(new TLBundleA(bundle)) val a = Wire(new TLBundleA(bundle))
a.opcode := TLMessages.Hint a.opcode := TLMessages.Hint
a.param := param a.param := param
@ -445,7 +445,7 @@ class TLEdgeIn(
// Transfers // Transfers
def Probe(fromAddress: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt) = { def Probe(fromAddress: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt) = {
require (client.anySupportProbe) require (client.anySupportProbe)
val legal = client.supportsProbe(fromAddress, lgSize) val legal = client.supportsProbe(toSource, lgSize)
val b = Wire(new TLBundleB(bundle)) val b = Wire(new TLBundleB(bundle))
b.opcode := TLMessages.Probe b.opcode := TLMessages.Probe
b.param := capPermissions b.param := capPermissions

View File

@ -189,7 +189,7 @@ class TLFragmenter(minSize: Int, maxSize: Int, alwaysMin: Boolean = false) exten
val maxLgHints = maxHints .map(m => if (m == 0) lgMinSize else UInt(log2Ceil(m))) val maxLgHints = maxHints .map(m => if (m == 0) lgMinSize else UInt(log2Ceil(m)))
// If this is infront of a single manager, these become constants // If this is infront of a single manager, these become constants
val find = manager.find(edgeIn.address(in.a.bits)) val find = manager.findFast(edgeIn.address(in.a.bits))
val maxLgArithmetic = Mux1H(find, maxLgArithmetics) val maxLgArithmetic = Mux1H(find, maxLgArithmetics)
val maxLgLogical = Mux1H(find, maxLgLogicals) val maxLgLogical = Mux1H(find, maxLgLogicals)
val maxLgGet = Mux1H(find, maxLgGets) val maxLgGet = Mux1H(find, maxLgGets)

View File

@ -163,10 +163,12 @@ class TLFuzzer(
edge.Hint(src, addr, size, UInt(0)) edge.Hint(src, addr, size, UInt(0))
} else { (glegal, gbits) } } else { (glegal, gbits) }
val legal_dest = edge.manager.containsSafe(addr)
// Pick a specific message to try to send // Pick a specific message to try to send
val a_type_sel = noiseMaker(3, inc) val a_type_sel = noiseMaker(3, inc)
val legal = MuxLookup(a_type_sel, glegal, Seq( val legal = legal_dest && MuxLookup(a_type_sel, glegal, Seq(
UInt("b000") -> glegal, UInt("b000") -> glegal,
UInt("b001") -> pflegal, UInt("b001") -> pflegal,
UInt("b010") -> pplegal, UInt("b010") -> pplegal,
@ -218,14 +220,18 @@ class ClockDivider extends BlackBox {
class TLFuzzRAM extends LazyModule class TLFuzzRAM extends LazyModule
{ {
val model = LazyModule(new TLRAMModel) val model = LazyModule(new TLRAMModel)
val ram = LazyModule(new TLRAM(AddressSet(0, 0x3ff))) val ram = LazyModule(new TLRAM(AddressSet(0x800, 0x7ff)))
val ram2 = LazyModule(new TLRAM(AddressSet(0, 0x3ff), beatBytes = 16))
val gpio = LazyModule(new RRTest1(0x400)) val gpio = LazyModule(new RRTest1(0x400))
val xbar = LazyModule(new TLXbar) val xbar = LazyModule(new TLXbar)
val xbar2= LazyModule(new TLXbar)
val fuzz = LazyModule(new TLFuzzer(5000)) val fuzz = LazyModule(new TLFuzzer(5000))
val cross = LazyModule(new TLAsyncCrossing) val cross = LazyModule(new TLAsyncCrossing)
model.node := fuzz.node model.node := fuzz.node
xbar.node := TLWidthWidget(TLHintHandler(model.node), 16) xbar2.node := model.node
ram2.node := TLFragmenter(xbar2.node, 16, 256)
xbar.node := TLWidthWidget(TLHintHandler(xbar2.node), 16)
cross.node := TLFragmenter(TLBuffer(xbar.node), 4, 256) cross.node := TLFragmenter(TLBuffer(xbar.node), 4, 256)
ram.node := cross.node ram.node := cross.node
gpio.node := TLFragmenter(TLBuffer(xbar.node), 4, 32) gpio.node := TLFragmenter(TLBuffer(xbar.node), 4, 32)

View File

@ -45,7 +45,7 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f
// Who wants what? // 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.supportsHintFast(address, edgeIn.size(in.a.bits)) else Bool(true)
val hintBitsAtA = handleA && in.a.bits.opcode === TLMessages.Hint val hintBitsAtA = handleA && in.a.bits.opcode === TLMessages.Hint
val hintWantsD = in.a.valid && hintBitsAtA val hintWantsD = in.a.valid && hintBitsAtA
val outerWantsD = out.d.valid val outerWantsD = out.d.valid
@ -57,7 +57,7 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f
assert (!hintHoldsD || hintWantsD) assert (!hintHoldsD || hintWantsD)
in.d.valid := Mux(hintWinsD, hintWantsD, outerWantsD) in.d.valid := Mux(hintWinsD, hintWantsD, outerWantsD)
in.d.bits := Mux(hintWinsD, edgeIn.HintAck(in.a.bits, edgeOut.manager.findId(address)), out.d.bits) in.d.bits := Mux(hintWinsD, edgeIn.HintAck(in.a.bits, edgeOut.manager.findIdStartFast(address)), out.d.bits)
out.d.ready := in.d.ready && !hintHoldsD out.d.ready := in.d.ready && !hintHoldsD
in.a.ready := Mux(hintBitsAtA, hintWinsD && in.d.ready, out.a.ready) in.a.ready := Mux(hintBitsAtA, hintWinsD && in.d.ready, out.a.ready)

View File

@ -21,9 +21,19 @@ object IntRange
implicit def apply(end: Int): IntRange = apply(0, end) implicit def apply(end: Int): IntRange = apply(0, end)
} }
case class IntSourceParameters(device: String, range: IntRange) case class IntSourceParameters(
range: IntRange,
nodePath: Seq[IntBaseNode] = Seq())
{
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
}
case class IntSinkParameters(
nodePath: Seq[IntBaseNode] = Seq())
{
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
}
case class IntSinkPortParameters()
case class IntSourcePortParameters(sources: Seq[IntSourceParameters]) case class IntSourcePortParameters(sources: Seq[IntSourceParameters])
{ {
val num = sources.map(_.range.size).sum val num = sources.map(_.range.size).sum
@ -32,6 +42,9 @@ case class IntSourcePortParameters(sources: Seq[IntSourceParameters])
// The interrupts must perfectly cover the range // The interrupts must perfectly cover the range
require (sources.map(_.range.end).max == num) require (sources.map(_.range.end).max == num)
} }
case class IntSinkPortParameters(sinks: Seq[IntSinkParameters])
case class IntEdge(source: IntSourcePortParameters, sink: IntSinkPortParameters) case class IntEdge(source: IntSourcePortParameters, sink: IntSinkPortParameters)
object IntImp extends NodeImp[IntSourcePortParameters, IntSinkPortParameters, IntEdge, IntEdge, Vec[Bool]] object IntImp extends NodeImp[IntSourcePortParameters, IntSinkPortParameters, IntEdge, IntEdge, Vec[Bool]]
@ -52,16 +65,21 @@ object IntImp extends NodeImp[IntSourcePortParameters, IntSinkPortParameters, In
// Cannot use bulk connect, because the widths could differ // Cannot use bulk connect, because the widths could differ
(bo zip bi) foreach { case (o, i) => i := o } (bo zip bi) foreach { case (o, i) => i := o }
} }
override def mixO(po: IntSourcePortParameters, node: IntBaseNode): IntSourcePortParameters =
po.copy(sources = po.sources.map { s => s.copy (nodePath = node +: s.nodePath) })
override def mixI(pi: IntSinkPortParameters, node: IntBaseNode): IntSinkPortParameters =
pi.copy(sinks = pi.sinks.map { s => s.copy (nodePath = node +: s.nodePath) })
} }
case class IntIdentityNode() extends IdentityNode(IntImp) case class IntIdentityNode() extends IdentityNode(IntImp)
case class IntOutputNode() extends OutputNode(IntImp) case class IntOutputNode() extends OutputNode(IntImp)
case class IntInputNode() extends InputNode(IntImp) case class IntInputNode() extends InputNode(IntImp)
case class IntSourceNode(device: String, num: Int) extends SourceNode(IntImp)( case class IntSourceNode(num: Int) extends SourceNode(IntImp)(
IntSourcePortParameters(Seq(IntSourceParameters(device, num))), IntSourcePortParameters(Seq(IntSourceParameters(num))), (if (num == 0) 0 else 1) to 1)
(if (num == 0) 0 else 1) to 1) case class IntSinkNode() extends SinkNode(IntImp)(
case class IntSinkNode() extends SinkNode(IntImp)(IntSinkPortParameters()) IntSinkPortParameters(Seq(IntSinkParameters())))
case class IntAdapterNode( case class IntAdapterNode(
sourceFn: Seq[IntSourcePortParameters] => IntSourcePortParameters, sourceFn: Seq[IntSourcePortParameters] => IntSourcePortParameters,
@ -75,7 +93,7 @@ class IntXbar extends LazyModule
val intnode = IntAdapterNode( val intnode = IntAdapterNode(
numSourcePorts = 1 to 1, // does it make sense to have more than one interrupt sink? numSourcePorts = 1 to 1, // does it make sense to have more than one interrupt sink?
numSinkPorts = 1 to 128, numSinkPorts = 1 to 128,
sinkFn = { _ => IntSinkPortParameters() }, sinkFn = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) },
sourceFn = { seq => sourceFn = { seq =>
IntSourcePortParameters((seq zip seq.map(_.num).scanLeft(0)(_+_).init).map { IntSourcePortParameters((seq zip seq.map(_.num).scanLeft(0)(_+_).init).map {
case (s, o) => s.sources.map(z => z.copy(range = z.range.offset(o))) case (s, o) => s.sources.map(z => z.copy(range = z.range.offset(o)))

View File

@ -24,7 +24,7 @@ object TLMonitor
val mask = edge.full_mask(bundle) val mask = edge.full_mask(bundle)
when (bundle.opcode === TLMessages.Acquire) { when (bundle.opcode === TLMessages.Acquire) {
assert (edge.manager.supportsAcquire(edge.address(bundle), bundle.size), "'A' channel carries Acquire type unsupported by manager" + extra) assert (edge.manager.supportsAcquireSafe(edge.address(bundle), bundle.size), "'A' channel carries Acquire type unsupported by manager" + extra)
assert (source_ok, "'A' channel Acquire carries invalid source ID" + extra) assert (source_ok, "'A' channel Acquire carries invalid source ID" + extra)
assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'A' channel Acquire smaller than a beat" + extra) assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'A' channel Acquire smaller than a beat" + extra)
assert (is_aligned, "'A' channel Acquire address not aligned to size" + extra) assert (is_aligned, "'A' channel Acquire address not aligned to size" + extra)
@ -33,7 +33,7 @@ object TLMonitor
} }
when (bundle.opcode === TLMessages.Get) { when (bundle.opcode === TLMessages.Get) {
assert (edge.manager.supportsGet(edge.address(bundle), bundle.size), "'A' channel carries Get type unsupported by manager" + extra) assert (edge.manager.supportsGetSafe(edge.address(bundle), bundle.size), "'A' channel carries Get type unsupported by manager" + extra)
assert (source_ok, "'A' channel Get carries invalid source ID" + extra) assert (source_ok, "'A' channel Get carries invalid source ID" + extra)
assert (is_aligned, "'A' channel Get address not aligned to size" + extra) assert (is_aligned, "'A' channel Get address not aligned to size" + extra)
assert (bundle.param === UInt(0), "'A' channel Get carries invalid param" + extra) assert (bundle.param === UInt(0), "'A' channel Get carries invalid param" + extra)
@ -41,7 +41,7 @@ object TLMonitor
} }
when (bundle.opcode === TLMessages.PutFullData) { when (bundle.opcode === TLMessages.PutFullData) {
assert (edge.manager.supportsPutFull(edge.address(bundle), bundle.size), "'A' channel carries PutFull type unsupported by manager" + extra) assert (edge.manager.supportsPutFullSafe(edge.address(bundle), bundle.size), "'A' channel carries PutFull type unsupported by manager" + extra)
assert (source_ok, "'A' channel PutFull carries invalid source ID" + extra) assert (source_ok, "'A' channel PutFull carries invalid source ID" + extra)
assert (is_aligned, "'A' channel PutFull address not aligned to size" + extra) assert (is_aligned, "'A' channel PutFull address not aligned to size" + extra)
assert (bundle.param === UInt(0), "'A' channel PutFull carries invalid param" + extra) assert (bundle.param === UInt(0), "'A' channel PutFull carries invalid param" + extra)
@ -49,7 +49,7 @@ object TLMonitor
} }
when (bundle.opcode === TLMessages.PutPartialData) { when (bundle.opcode === TLMessages.PutPartialData) {
assert (edge.manager.supportsPutPartial(edge.address(bundle), bundle.size), "'A' channel carries PutPartial type unsupported by manager" + extra) assert (edge.manager.supportsPutPartialSafe(edge.address(bundle), bundle.size), "'A' channel carries PutPartial type unsupported by manager" + extra)
assert (source_ok, "'A' channel PutPartial carries invalid source ID" + extra) assert (source_ok, "'A' channel PutPartial carries invalid source ID" + extra)
assert (is_aligned, "'A' channel PutPartial address not aligned to size" + extra) assert (is_aligned, "'A' channel PutPartial address not aligned to size" + extra)
assert (bundle.param === UInt(0), "'A' channel PutPartial carries invalid param" + extra) assert (bundle.param === UInt(0), "'A' channel PutPartial carries invalid param" + extra)
@ -57,7 +57,7 @@ object TLMonitor
} }
when (bundle.opcode === TLMessages.ArithmeticData) { when (bundle.opcode === TLMessages.ArithmeticData) {
assert (edge.manager.supportsArithmetic(edge.address(bundle), bundle.size), "'A' channel carries Arithmetic type unsupported by manager" + extra) assert (edge.manager.supportsArithmeticSafe(edge.address(bundle), bundle.size), "'A' channel carries Arithmetic type unsupported by manager" + extra)
assert (source_ok, "'A' channel Arithmetic carries invalid source ID" + extra) assert (source_ok, "'A' channel Arithmetic carries invalid source ID" + extra)
assert (is_aligned, "'A' channel Arithmetic address not aligned to size" + extra) assert (is_aligned, "'A' channel Arithmetic address not aligned to size" + extra)
assert (TLAtomics.isArithmetic(bundle.param), "'A' channel Arithmetic carries invalid opcode param" + extra) assert (TLAtomics.isArithmetic(bundle.param), "'A' channel Arithmetic carries invalid opcode param" + extra)
@ -65,7 +65,7 @@ object TLMonitor
} }
when (bundle.opcode === TLMessages.LogicalData) { when (bundle.opcode === TLMessages.LogicalData) {
assert (edge.manager.supportsLogical(edge.address(bundle), bundle.size), "'A' channel carries Logical type unsupported by manager" + extra) assert (edge.manager.supportsLogicalSafe(edge.address(bundle), bundle.size), "'A' channel carries Logical type unsupported by manager" + extra)
assert (source_ok, "'A' channel Logical carries invalid source ID" + extra) assert (source_ok, "'A' channel Logical carries invalid source ID" + extra)
assert (is_aligned, "'A' channel Logical address not aligned to size" + extra) assert (is_aligned, "'A' channel Logical address not aligned to size" + extra)
assert (TLAtomics.isLogical(bundle.param), "'A' channel Logical carries invalid opcode param" + extra) assert (TLAtomics.isLogical(bundle.param), "'A' channel Logical carries invalid opcode param" + extra)
@ -73,7 +73,7 @@ object TLMonitor
} }
when (bundle.opcode === TLMessages.Hint) { when (bundle.opcode === TLMessages.Hint) {
assert (edge.manager.supportsHint(edge.address(bundle), bundle.size), "'A' channel carries Hint type unsupported by manager" + extra) assert (edge.manager.supportsHintSafe(edge.address(bundle), bundle.size), "'A' channel carries Hint type unsupported by manager" + extra)
assert (source_ok, "'A' channel Hint carries invalid source ID" + extra) assert (source_ok, "'A' channel Hint carries invalid source ID" + extra)
assert (is_aligned, "'A' channel Hint address not aligned to size" + extra) assert (is_aligned, "'A' channel Hint address not aligned to size" + extra)
assert (bundle.mask === mask, "'A' channel Hint contains invalid mask" + extra) assert (bundle.mask === mask, "'A' channel Hint contains invalid mask" + extra)
@ -84,7 +84,7 @@ object TLMonitor
assert (TLMessages.isB(bundle.opcode), "'B' channel has invalid opcode" + extra) assert (TLMessages.isB(bundle.opcode), "'B' channel has invalid opcode" + extra)
// Reuse these subexpressions to save some firrtl lines // Reuse these subexpressions to save some firrtl lines
val address_ok = edge.manager.contains(bundle.source) val address_ok = edge.manager.containsSafe(edge.address(bundle))
val is_aligned = edge.isHiAligned(bundle.addr_hi, bundle.size) val is_aligned = edge.isHiAligned(bundle.addr_hi, bundle.size)
val mask = edge.full_mask(bundle) val mask = edge.full_mask(bundle)
@ -150,7 +150,7 @@ object TLMonitor
val source_ok = edge.client.contains(bundle.source) val source_ok = edge.client.contains(bundle.source)
val is_aligned = edge.isHiAligned(bundle.addr_hi, bundle.size) && edge.isLoAligned(bundle.addr_lo, bundle.size) val is_aligned = edge.isHiAligned(bundle.addr_hi, bundle.size) && edge.isLoAligned(bundle.addr_lo, bundle.size)
val address_ok = edge.manager.contains(bundle.source) val address_ok = edge.manager.containsSafe(edge.address(bundle))
when (bundle.opcode === TLMessages.ProbeAck) { when (bundle.opcode === TLMessages.ProbeAck) {
assert (address_ok, "'C' channel ProbeAck carries unmanaged address" + extra) assert (address_ok, "'C' channel ProbeAck carries unmanaged address" + extra)
@ -171,7 +171,7 @@ object TLMonitor
} }
when (bundle.opcode === TLMessages.Release) { when (bundle.opcode === TLMessages.Release) {
assert (edge.manager.supportsAcquire(edge.address(bundle), bundle.size), "'C' channel carries Release type unsupported by manager" + extra) assert (edge.manager.supportsAcquireSafe(edge.address(bundle), bundle.size), "'C' channel carries Release type unsupported by manager" + extra)
assert (source_ok, "'C' channel Release carries invalid source ID" + extra) assert (source_ok, "'C' channel Release carries invalid source ID" + extra)
assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel Release smaller than a beat" + extra) assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel Release smaller than a beat" + extra)
assert (is_aligned, "'C' channel Release address not aligned to size" + extra) assert (is_aligned, "'C' channel Release address not aligned to size" + extra)
@ -180,7 +180,7 @@ object TLMonitor
} }
when (bundle.opcode === TLMessages.ReleaseData) { when (bundle.opcode === TLMessages.ReleaseData) {
assert (edge.manager.supportsAcquire(edge.address(bundle), bundle.size), "'C' channel carries ReleaseData type unsupported by manager" + extra) assert (edge.manager.supportsAcquireSafe(edge.address(bundle), bundle.size), "'C' channel carries ReleaseData type unsupported by manager" + extra)
assert (source_ok, "'C' channel ReleaseData carries invalid source ID" + extra) assert (source_ok, "'C' channel ReleaseData carries invalid source ID" + extra)
assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ReleaseData smaller than a beat" + extra) assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ReleaseData smaller than a beat" + extra)
assert (is_aligned, "'C' channel ReleaseData address not aligned to size" + extra) assert (is_aligned, "'C' channel ReleaseData address not aligned to size" + extra)

View File

@ -17,6 +17,9 @@ abstract class NodeImp[PO, PI, EO, EI, B <: Data]
def bundleO(eo: Seq[EO]): Vec[B] def bundleO(eo: Seq[EO]): Vec[B]
def bundleI(ei: Seq[EI]): Vec[B] def bundleI(ei: Seq[EI]): Vec[B]
def connect(bo: B, eo: EO, bi: B, ei: EI)(implicit sourceInfo: SourceInfo): Unit def connect(bo: B, eo: EO, bi: B, ei: EI)(implicit sourceInfo: SourceInfo): Unit
// If you want to track parameters as they flow through nodes, overload these:
def mixO(po: PO, node: BaseNode[PO, PI, EO, EI, B]): PO = po
def mixI(pi: PI, node: BaseNode[PO, PI, EO, EI, B]): PI = pi
} }
class RootNode class RootNode
@ -59,12 +62,12 @@ class BaseNode[PO, PI, EO, EI, B <: Data](imp: NodeImp[PO, PI, EO, EI, B])(
private lazy val oParams : Seq[PO] = { private lazy val oParams : Seq[PO] = {
val o = oFn(oPorts.size, iPorts.map{ case (i, n) => n.oParams(i) }) val o = oFn(oPorts.size, iPorts.map{ case (i, n) => n.oParams(i) })
reqE(oPorts.size, o.size) reqE(oPorts.size, o.size)
o o.map(imp.mixO(_, this))
} }
private lazy val iParams : Seq[PI] = { private lazy val iParams : Seq[PI] = {
val i = iFn(iPorts.size, oPorts.map{ case (o, n) => n.iParams(o) }) val i = iFn(iPorts.size, oPorts.map{ case (o, n) => n.iParams(o) })
reqE(i.size, iPorts.size) reqE(i.size, iPorts.size)
i i.map(imp.mixI(_, this))
} }
lazy val edgesOut = (oPorts zip oParams).map { case ((i, n), o) => imp.edgeO(o, n.iParams(i)) } lazy val edgesOut = (oPorts zip oParams).map { case ((i, n), o) => imp.edgeO(o, n.iParams(i)) }

View File

@ -82,23 +82,29 @@ 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)
require (base >= 0) // TL2 address widths are not fixed => negative is ambiguous
// We do allow negative mask (=> ignore all high bits)
def contains(x: BigInt) = ~(~(x ^ base) | mask) == 0 def contains(x: BigInt) = ((x ^ base) & ~mask) == 0
def contains(x: UInt) = ~(~(x ^ UInt(base)) | UInt(mask)) === UInt(0) def contains(x: UInt) = ((x ^ UInt(base)).zext() & SInt(~mask)) === SInt(0)
// overlap iff bitwise: both care (~mask0 & ~mask1) => both equal (base0=base1) // overlap iff bitwise: both care (~mask0 & ~mask1) => both equal (base0=base1)
def overlaps(x: AddressSet) = (~(mask | x.mask) & (base ^ x.base)) == 0 def overlaps(x: AddressSet) = (~(mask | x.mask) & (base ^ x.base)) == 0
// contains iff bitwise: x.mask => mask && contains(x.base) // contains iff bitwise: x.mask => mask && contains(x.base)
def contains(x: AddressSet) = ((x.mask | (base ^ x.base)) & ~mask) == 0 def contains(x: AddressSet) = ((x.mask | (base ^ x.base)) & ~mask) == 0
// 1 less than the number of bytes to which the manager should be aligned
def alignment1 = ((mask + 1) & ~mask) - 1
def max = base | mask
// A strided slave serves discontiguous ranges // The number of bytes to which the manager must be aligned
def strided = alignment1 != mask def alignment = ((mask + 1) & ~mask)
// Is this a contiguous memory range
def contiguous = alignment == mask+1
// AddressSets have one natural Ordering (the containment order) def finite = mask >= 0
def max = { require (finite); base | mask }
// Widen the match function to ignore all bits in imask
def widen(imask: BigInt) = AddressSet(base & ~imask, mask | imask)
// AddressSets have one natural Ordering (the containment order, if contiguous)
def compare(x: AddressSet) = { def compare(x: AddressSet) = {
val primary = (this.base - x.base).signum // smallest address first val primary = (this.base - x.base).signum // smallest address first
val secondary = (x.mask - this.mask).signum // largest mask first val secondary = (x.mask - this.mask).signum // largest mask first
@ -106,7 +112,13 @@ case class AddressSet(base: BigInt, mask: BigInt) extends Ordered[AddressSet]
} }
// We always want to see things in hex // We always want to see things in hex
override def toString() = "AddressSet(0x%x, 0x%x)".format(base, mask) override def toString() = {
if (mask >= 0) {
"AddressSet(0x%x, 0x%x)".format(base, mask)
} else {
"AddressSet(0x%x, ~0x%x)".format(base, ~mask)
}
}
} }
case class TLManagerParameters( case class TLManagerParameters(
@ -124,8 +136,10 @@ case class TLManagerParameters(
supportsPutPartial: TransferSizes = TransferSizes.none, supportsPutPartial: TransferSizes = TransferSizes.none,
supportsHint: TransferSizes = TransferSizes.none, supportsHint: TransferSizes = TransferSizes.none,
// If fifoId=Some, all accesses sent to the same fifoId are executed and ACK'd in FIFO order // If fifoId=Some, all accesses sent to the same fifoId are executed and ACK'd in FIFO order
fifoId: Option[Int] = None) fifoId: Option[Int] = None,
customDTS: Option[String]= None)
{ {
address.foreach { a => require (a.finite) }
address.combinations(2).foreach({ case Seq(x,y) => address.combinations(2).foreach({ case Seq(x,y) =>
require (!x.overlaps(y)) require (!x.overlaps(y))
}) })
@ -140,9 +154,22 @@ case class TLManagerParameters(
supportsPutFull.max, supportsPutFull.max,
supportsPutPartial.max).max supportsPutPartial.max).max
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
// Generate the config string (in future device tree)
lazy val dts = customDTS.getOrElse {
val header = s"${name} {\n"
val middle = address.map { a =>
require (a.contiguous) // Config String is not so flexible
" addr 0x%x;\n size 0x%x;\n".format(a.base, a.mask+1)
}
val footer = "}\n"
header + middle.reduce(_ + _) + footer
}
// The device had better not support a transfer larger than it's alignment // The device had better not support a transfer larger than it's alignment
address.foreach({ case a => address.foreach({ case a =>
require (a.alignment1 >= maxTransfer-1) require (a.alignment >= maxTransfer)
}) })
} }
@ -182,41 +209,59 @@ case class TLManagerPortParameters(managers: Seq[TLManagerParameters], beatBytes
val anySupportPutPartial = managers.map(!_.supportsPutPartial.none).reduce(_ || _) val anySupportPutPartial = managers.map(!_.supportsPutPartial.none).reduce(_ || _)
val anySupportHint = managers.map(!_.supportsHint.none) .reduce(_ || _) val anySupportHint = managers.map(!_.supportsHint.none) .reduce(_ || _)
// Which bits suffice to distinguish between all managers
lazy val routingMask = AddressDecoder(managers.map(_.address))
// These return Option[TLManagerParameters] for your convenience // These return Option[TLManagerParameters] for your convenience
def find(address: BigInt) = managers.find(_.address.exists(_.contains(address))) def find(address: BigInt) = managers.find(_.address.exists(_.contains(address)))
def findById(id: Int) = managers.find(_.sinkId.contains(id)) def findById(id: Int) = managers.find(_.sinkId.contains(id))
// Synthesizable lookup methods // Synthesizable lookup methods
def find(address: UInt) = Vec(managers.map(_.address.map(_.contains(address)).reduce(_ || _)))
def findById(id: UInt) = Vec(managers.map(_.sinkId.contains(id))) def findById(id: UInt) = Vec(managers.map(_.sinkId.contains(id)))
def findId(address: UInt) = Mux1H(find(address), managers.map(m => UInt(m.sinkId.start))) def findIdStartSafe(address: UInt) = Mux1H(findSafe(address), managers.map(m => UInt(m.sinkId.start)))
def findIdStartFast(address: UInt) = Mux1H(findFast(address), managers.map(m => UInt(m.sinkId.start)))
def findIdEndSafe(address: UInt) = Mux1H(findSafe(address), managers.map(m => UInt(m.sinkId.end)))
def findIdEndFast(address: UInt) = Mux1H(findFast(address), managers.map(m => UInt(m.sinkId.end)))
// The safe version will check the entire address
def findSafe(address: UInt) = Vec(managers.map(_.address.map(_.contains(address)).reduce(_ || _)))
// The fast version assumes the address is valid
def findFast(address: UInt) = Vec(managers.map(_.address.map(_.widen(~routingMask)).distinct.map(_.contains(address)).reduce(_ || _)))
// Note: returns the actual fifoId + 1 or 0 if None // Note: returns the actual fifoId + 1 or 0 if None
def findFifoId(address: UInt) = Mux1H(find(address), managers.map(m => UInt(m.fifoId.map(_+1).getOrElse(0)))) def findFifoIdSafe(address: UInt) = Mux1H(findSafe(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 findFifoIdFast(address: UInt) = Mux1H(findFast(address), managers.map(m => UInt(m.fifoId.map(_+1).getOrElse(0))))
def hasFifoIdSafe(address: UInt) = Mux1H(findSafe(address), managers.map(m => Bool(m.fifoId.isDefined)))
def hasFifoIdFast(address: UInt) = Mux1H(findFast(address), managers.map(m => Bool(m.fifoId.isDefined)))
lazy val addressMask = AddressDecoder(managers.map(_.address))
// !!! need a cheaper version of find, where we assume a valid address match exists
// Does this Port manage this ID/address? // Does this Port manage this ID/address?
def contains(address: UInt) = find(address).reduce(_ || _) def containsSafe(address: UInt) = findSafe(address).reduce(_ || _)
// containsFast would be useless; it could always be true
def containsById(id: UInt) = findById(id).reduce(_ || _) def containsById(id: UInt) = findById(id).reduce(_ || _)
private def safety_helper(member: TLManagerParameters => TransferSizes)(address: UInt, lgSize: UInt) = { private def safety_helper(member: TLManagerParameters => TransferSizes, select: UInt => Vec[Bool])(address: UInt, lgSize: UInt) = {
val allSame = managers.map(member(_) == member(managers(0))).reduce(_ && _) val allSame = managers.map(member(_) == member(managers(0))).reduce(_ && _)
if (allSame) member(managers(0)).containsLg(lgSize) else { if (allSame) member(managers(0)).containsLg(lgSize) else {
Mux1H(find(address), managers.map(member(_).containsLg(lgSize))) Mux1H(select(address), managers.map(member(_).containsLg(lgSize)))
} }
} }
// Check for support of a given operation at a specific address // Check for support of a given operation at a specific address
val supportsAcquire = safety_helper(_.supportsAcquire) _ val supportsAcquireSafe = safety_helper(_.supportsAcquire, findSafe) _
val supportsArithmetic = safety_helper(_.supportsArithmetic) _ val supportsArithmeticSafe = safety_helper(_.supportsArithmetic, findSafe) _
val supportsLogical = safety_helper(_.supportsLogical) _ val supportsLogicalSafe = safety_helper(_.supportsLogical, findSafe) _
val supportsGet = safety_helper(_.supportsGet) _ val supportsGetSafe = safety_helper(_.supportsGet, findSafe) _
val supportsPutFull = safety_helper(_.supportsPutFull) _ val supportsPutFullSafe = safety_helper(_.supportsPutFull, findSafe) _
val supportsPutPartial = safety_helper(_.supportsPutPartial) _ val supportsPutPartialSafe = safety_helper(_.supportsPutPartial, findSafe) _
val supportsHint = safety_helper(_.supportsHint) _ val supportsHintSafe = safety_helper(_.supportsHint, findSafe) _
val supportsAcquireFast = safety_helper(_.supportsAcquire, findFast) _
val supportsArithmeticFast = safety_helper(_.supportsArithmetic, findFast) _
val supportsLogicalFast = safety_helper(_.supportsLogical, findFast) _
val supportsGetFast = safety_helper(_.supportsGet, findFast) _
val supportsPutFullFast = safety_helper(_.supportsPutFull, findFast) _
val supportsPutPartialFast = safety_helper(_.supportsPutPartial, findFast) _
val supportsHintFast = safety_helper(_.supportsHint, findFast) _
} }
case class TLClientParameters( case class TLClientParameters(
@ -240,6 +285,8 @@ case class TLClientParameters(
supportsGet.max, supportsGet.max,
supportsPutFull.max, supportsPutFull.max,
supportsPutPartial.max).max supportsPutPartial.max).max
val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected")
} }
case class TLClientPortParameters(clients: Seq[TLClientParameters]) { case class TLClientPortParameters(clients: Seq[TLClientParameters]) {

View File

@ -119,7 +119,7 @@ class TLRAMModel extends LazyModule
val a_addr_hi = a.addr_hi | (a_beats1 & ~a_counter1) val a_addr_hi = a.addr_hi | (a_beats1 & ~a_counter1)
val a_base = edge.address(a) val a_base = edge.address(a)
val a_mask = edge.mask(a_base, a_size) val a_mask = edge.mask(a_base, a_size)
val a_fifo = edge.manager.hasFifoId(a_base) val a_fifo = edge.manager.hasFifoIdFast(a_base)
// Grab the concurrency state we need // Grab the concurrency state we need
val a_inc_bytes = inc_bytes.map(_.read(a_addr_hi)) val a_inc_bytes = inc_bytes.map(_.read(a_addr_hi))
@ -203,7 +203,7 @@ class TLRAMModel extends LazyModule
val d_base = d_flight.base val d_base = d_flight.base
val d_addr_hi = d_base >> shift | (d_beats1 & ~d_counter1) val d_addr_hi = d_base >> shift | (d_beats1 & ~d_counter1)
val d_mask = edge.mask(d_base, d_size) val d_mask = edge.mask(d_base, d_size)
val d_fifo = edge.manager.hasFifoId(d_flight.base) val d_fifo = edge.manager.hasFifoIdFast(d_flight.base)
// Grab the concurrency state we need // Grab the concurrency state we need
val d_inc_bytes = inc_bytes.map(_.read(d_addr_hi)) val d_inc_bytes = inc_bytes.map(_.read(d_addr_hi))
@ -222,7 +222,8 @@ class TLRAMModel extends LazyModule
// Check the response is correct // Check the response is correct
assert (d_size === d_flight.size) assert (d_size === d_flight.size)
assert (edge.manager.findId(d_flight.base) === d.sink) assert (edge.manager.findIdStartFast(d_flight.base) <= d.sink)
assert (edge.manager.findIdEndFast (d_flight.base) > d.sink)
// addr_lo is allowed to differ // addr_lo is allowed to differ
when (d_flight.opcode === TLMessages.Hint) { when (d_flight.opcode === TLMessages.Hint) {

View File

@ -2,8 +2,8 @@
package uncore.tilelink2 package uncore.tilelink2
import Chisel._ import chisel3._
import chisel3.util.{Irrevocable, IrrevocableIO} import chisel3.util._
// A bus agnostic register interface to a register-based device // A bus agnostic register interface to a register-based device
@ -36,6 +36,23 @@ object RegMapper
regmap.combinations(2).foreach { case Seq((reg1, _), (reg2, _)) => regmap.combinations(2).foreach { case Seq((reg1, _), (reg2, _)) =>
require (reg1 != reg2) require (reg1 != reg2)
} }
// Don't be an asshole...
regmap.foreach { reg => require (reg._1 >= 0) }
// Make sure registers fit
val inParams = in.bits.params
val inBits = inParams.indexBits
assert (regmap.map(_._1).max < (1 << inBits))
val out = Wire(Irrevocable(new RegMapperOutput(inParams)))
val front = Wire(Irrevocable(new RegMapperInput(inParams)))
front.bits := in.bits
// Must this device pipeline the control channel?
val pipelined = regmap.map(_._2.map(_.pipelined)).flatten.reduce(_ || _)
val depth = concurrency.getOrElse(if (pipelined) 1 else 0)
require (depth >= 0)
require (!pipelined || depth > 0)
val back = if (depth > 0) Queue(front, depth, pipe = depth == 1) else front
// Convert to and from Bits // Convert to and from Bits
def toBits(x: Int, tail: List[Boolean] = List.empty): List[Boolean] = def toBits(x: Int, tail: List[Boolean] = List.empty): List[Boolean] =
@ -44,36 +61,33 @@ object RegMapper
// Find the minimal mask that can decide the register map // Find the minimal mask that can decide the register map
val mask = AddressDecoder(regmap.map(_._1)) val mask = AddressDecoder(regmap.map(_._1))
val maskMatch = ~UInt(mask, width = inBits)
val maskFilter = toBits(mask) val maskFilter = toBits(mask)
val maskBits = maskFilter.filter(x => x).size val maskBits = maskFilter.filter(x => x).size
// Calculate size and indexes into the register map // Calculate size and indexes into the register map
val endIndex = 1 << log2Ceil(regmap.map(_._1).max+1)
val params = RegMapperParams(log2Up(endIndex), bytes, in.bits.params.extraBits)
val regSize = 1 << maskBits val regSize = 1 << maskBits
def regIndexI(x: Int) = ofBits((maskFilter zip toBits(x)).filter(_._1).map(_._2)) def regIndexI(x: Int) = ofBits((maskFilter zip toBits(x)).filter(_._1).map(_._2))
def regIndexU(x: UInt) = if (maskBits == 0) UInt(0) else def regIndexU(x: UInt) = if (maskBits == 0) UInt(0) else
Cat((maskFilter zip x.toBools).filter(_._1).map(_._2).reverse) Cat((maskFilter zip x.toBools).filter(_._1).map(_._2).reverse)
// Protection flag for undefined registers
val iRightReg = Array.fill(regSize) { Bool(true) }
val oRightReg = Array.fill(regSize) { Bool(true) }
// Flatten the regmap into (RegIndex:Int, Offset:Int, field:RegField) // Flatten the regmap into (RegIndex:Int, Offset:Int, field:RegField)
val flat = regmap.map { case (reg, fields) => val flat = regmap.map { case (reg, fields) =>
val offsets = fields.scanLeft(0)(_ + _.width).init val offsets = fields.scanLeft(0)(_ + _.width).init
val index = regIndexI(reg) val index = regIndexI(reg)
val uint = UInt(reg, width = inBits)
if (undefZero) {
iRightReg(index) = ((front.bits.index ^ uint) & maskMatch) === UInt(0)
oRightReg(index) = ((back .bits.index ^ uint) & maskMatch) === UInt(0)
}
// println("mapping 0x%x -> 0x%x for 0x%x/%d".format(reg, index, mask, maskBits)) // 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) } (offsets zip fields) map { case (o, f) => (index, o, f) }
}.flatten }.flatten
val out = Wire(Irrevocable(new RegMapperOutput(params)))
val front = Wire(Irrevocable(new RegMapperInput(params)))
front.bits := in.bits
// Must this device pipeline the control channel?
val pipelined = flat.map(_._3.pipelined).reduce(_ || _)
val depth = concurrency.getOrElse(if (pipelined) 1 else 0)
require (depth >= 0)
require (!pipelined || depth > 0)
val back = if (depth > 0) Queue(front, depth, pipe = depth == 1) else front
// Forward declaration of all flow control signals // Forward declaration of all flow control signals
val rivalid = Wire(Vec(flat.size, Bool())) val rivalid = Wire(Vec(flat.size, Bool()))
val wivalid = Wire(Vec(flat.size, Bool())) val wivalid = Wire(Vec(flat.size, Bool()))
@ -122,10 +136,10 @@ object RegMapper
} }
// Is the selected register ready? // Is the selected register ready?
val rifireMux = Vec(rifire.map(_.reduce(_ && _))) val rifireMux = Vec(rifire.zipWithIndex.map { case (seq, i) => !iRightReg(i) || seq.reduce(_ && _)})
val wifireMux = Vec(wifire.map(_.reduce(_ && _))) val wifireMux = Vec(wifire.zipWithIndex.map { case (seq, i) => !iRightReg(i) || seq.reduce(_ && _)})
val rofireMux = Vec(rofire.map(_.reduce(_ && _))) val rofireMux = Vec(rofire.zipWithIndex.map { case (seq, i) => !oRightReg(i) || seq.reduce(_ && _)})
val wofireMux = Vec(wofire.map(_.reduce(_ && _))) val wofireMux = Vec(wofire.zipWithIndex.map { case (seq, i) => !oRightReg(i) || seq.reduce(_ && _)})
val iindex = regIndexU(front.bits.index) val iindex = regIndexU(front.bits.index)
val oindex = regIndexU(back .bits.index) val oindex = regIndexU(back .bits.index)
val iready = Mux(front.bits.read, rifireMux(iindex), wifireMux(iindex)) val iready = Mux(front.bits.read, rifireMux(iindex), wifireMux(iindex))
@ -138,8 +152,8 @@ object RegMapper
out.valid := back.valid && oready out.valid := back.valid && oready
// Which register is touched? // Which register is touched?
val frontSel = UIntToOH(iindex) val frontSel = UIntToOH(iindex) & Cat(iRightReg.reverse)
val backSel = UIntToOH(oindex) val backSel = UIntToOH(oindex) & Cat(oRightReg.reverse)
// Include the per-register one-hot selected criteria // Include the per-register one-hot selected criteria
for (reg <- 0 until regSize) { for (reg <- 0 until regSize) {
@ -159,9 +173,9 @@ object RegMapper
} }
out.bits.read := back.bits.read out.bits.read := back.bits.read
out.bits.data := Vec(dataOut)(oindex) out.bits.data := Mux(Vec(oRightReg)(oindex), Vec(dataOut)(oindex), UInt(0))
out.bits.extra := back.bits.extra out.bits.extra := back.bits.extra
(endIndex, out) out
} }
} }

View File

@ -12,7 +12,7 @@ class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatB
supportsPutFull = TransferSizes(1, beatBytes), supportsPutFull = TransferSizes(1, beatBytes),
fifoId = Some(0))) // requests are handled in order fifoId = Some(0))) // requests are handled in order
{ {
require (!address.strided) require (address.contiguous)
// Calling this method causes the matching TL2 bundle to be // Calling this method causes the matching TL2 bundle to be
// configured to route all requests to the listed RegFields. // configured to route all requests to the listed RegFields.
@ -27,7 +27,7 @@ class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatB
val (sourceEnd, sourceOff) = (edge.bundle.sourceBits + sizeEnd, sizeEnd) val (sourceEnd, sourceOff) = (edge.bundle.sourceBits + sizeEnd, sizeEnd)
val (addrLoEnd, addrLoOff) = (log2Up(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), beatBytes, addrLoEnd)
val in = Wire(Decoupled(new RegMapperInput(params))) val in = Wire(Decoupled(new RegMapperInput(params)))
in.bits.read := a.bits.opcode === TLMessages.Get in.bits.read := a.bits.opcode === TLMessages.Get
in.bits.index := a.bits.addr_hi in.bits.index := a.bits.addr_hi
@ -36,10 +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, undefZero, in, mapping:_*) val out = RegMapper(beatBytes, concurrency, undefZero, in, mapping:_*)
// All registers must fit inside the device address space
require (address.mask >= (endIndex-1)*beatBytes)
// No flow control needed // No flow control needed
in.valid := a.valid in.valid := a.valid
@ -78,7 +75,7 @@ object TLRegisterNode
abstract class TLRegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Option[Int], beatBytes: Int, undefZero: Boolean) extends LazyModule abstract class TLRegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Option[Int], beatBytes: Int, undefZero: Boolean) extends LazyModule
{ {
val node = TLRegisterNode(address, concurrency, beatBytes, undefZero) val node = TLRegisterNode(address, concurrency, beatBytes, undefZero)
val intnode = IntSourceNode(name + s" @ ${address.base}", interrupts) val intnode = IntSourceNode(interrupts)
} }
case class TLRegBundleArg(interrupts: Vec[Vec[Bool]], in: Vec[TLBundle]) case class TLRegBundleArg(interrupts: Vec[Vec[Bool]], in: Vec[TLBundle])

View File

@ -26,15 +26,15 @@ class RRTestCombinational(val bits: Int, rvalid: Bool => Bool, wready: Bool => B
val wdata = UInt(INPUT, width = bits) val wdata = UInt(INPUT, width = bits)
} }
val rfire = io.rvalid && io.rready
val wfire = io.wvalid && io.wready
val reg = Reg(UInt(width = bits)) val reg = Reg(UInt(width = bits))
io.rvalid := rvalid(rfire) val rvalid_s = rvalid(io.rready)
io.wready := wready(wfire) val wready_s = wready(io.wvalid)
io.rvalid := rvalid_s
io.wready := wready_s
io.rdata := reg io.rdata := reg
when (wfire) { reg := io.wdata } when (io.wvalid && wready_s) { reg := io.wdata }
} }
object RRTestCombinational object RRTestCombinational
@ -43,19 +43,19 @@ object RRTestCombinational
def always: Bool => Bool = _ => Bool(true) def always: Bool => Bool = _ => Bool(true)
def random: Bool => Bool = { fire => def random: Bool => Bool = { ready =>
seed = seed + 1 seed = seed + 1
val lfsr = LFSR16Seed(seed) val lfsr = LFSR16Seed(seed)
val reg = RegInit(Bool(true)) val valid = RegInit(Bool(true))
reg := Mux(reg, !fire, lfsr(0) && lfsr(1)) valid := Mux(valid, !ready, lfsr(0) && lfsr(1))
reg valid
} }
def delay(x: Int): Bool => Bool = { fire => def delay(x: Int): Bool => Bool = { ready =>
val reg = RegInit(UInt(0, width = log2Ceil(x+1))) val reg = RegInit(UInt(0, width = log2Ceil(x+1)))
val ready = reg === UInt(0) val valid = reg === UInt(0)
reg := Mux(fire, UInt(x), Mux(ready, UInt(0), reg - UInt(1))) reg := Mux(ready && valid, UInt(x), Mux(valid, UInt(0), reg - UInt(1)))
ready valid
} }
def combo(bits: Int, rvalid: Bool => Bool, wready: Bool => Bool): RegField = { def combo(bits: Int, rvalid: Bool => Bool, wready: Bool => Bool): RegField = {

View File

@ -4,12 +4,12 @@ package uncore.tilelink2
import Chisel._ import Chisel._
class TLRAM(address: AddressSet, beatBytes: Int = 4) extends LazyModule class TLRAM(address: AddressSet, executable: Boolean = true, 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, executable = executable,
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

@ -24,6 +24,11 @@ object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TL
TLMonitor.legalize(bo, eo) TLMonitor.legalize(bo, eo)
bi <> bo bi <> bo
} }
override def mixO(po: TLClientPortParameters, node: TLBaseNode): TLClientPortParameters =
po.copy(clients = po.clients.map { c => c.copy (nodePath = node +: c.nodePath) })
override def mixI(pi: TLManagerPortParameters, node: TLBaseNode): TLManagerPortParameters =
pi.copy(managers = pi.managers.map { m => m.copy (nodePath = node +: m.nodePath) })
} }
case class TLIdentityNode() extends IdentityNode(TLImp) case class TLIdentityNode() extends IdentityNode(TLImp)

View File

@ -75,6 +75,23 @@ class TLXbar(policy: (Vec[Bool], Bool) => Seq[Bool] = TLXbar.lowestIndex) extend
val inputIdRanges = mapInputIds(node.edgesIn.map(_.client)) val inputIdRanges = mapInputIds(node.edgesIn.map(_.client))
val outputIdRanges = mapOutputIds(node.edgesOut.map(_.manager)) val outputIdRanges = mapOutputIds(node.edgesOut.map(_.manager))
// Find a good mask for address decoding
val port_addrs = node.edgesOut.map(_.manager.managers.map(_.address).flatten)
val routingMask = AddressDecoder(port_addrs)
val route_addrs = port_addrs.map(_.map(_.widen(~routingMask)).distinct)
val outputPorts = route_addrs.map(seq => (addr: UInt) => seq.map(_.contains(addr)).reduce(_ || _))
// Print the mapping
if (false) {
println("Xbar mapping:")
route_addrs.foreach { p =>
print(" ")
p.foreach { a => print(s" ${a}") }
println("")
}
println("--")
}
// We need an intermediate size of bundle with the widest possible identifiers // We need an intermediate size of bundle with the widest possible identifiers
val wide_bundle = io.in(0).params.union(io.out(0).params) val wide_bundle = io.in(0).params.union(io.out(0).params)
@ -145,11 +162,15 @@ class TLXbar(policy: (Vec[Bool], Bool) => Seq[Bool] = TLXbar.lowestIndex) extend
in(i).e.ready := Mux1C(grantedEIO(i), out.map(_.e.ready)) in(i).e.ready := Mux1C(grantedEIO(i), out.map(_.e.ready))
} }
val requestAIO = Vec(in.map { i => Vec(node.edgesOut.map { o => i.a.valid && o.manager.contains(o.address(i.a.bits)) }) }) val addressA = (in zip node.edgesIn) map { case (i, e) => (i.a.valid, e.address(i.a.bits)) }
val requestBOI = Vec(out.map { o => Vec(inputIdRanges.map { i => o.b.valid && i .contains(o.b.bits.source) }) }) val addressC = (in zip node.edgesIn) map { case (i, e) => (i.c.valid, e.address(i.c.bits)) }
val requestCIO = Vec(in.map { i => Vec(node.edgesOut.map { o => i.c.valid && o.manager.contains(o.address(i.c.bits)) }) })
val requestDOI = Vec(out.map { o => Vec(inputIdRanges.map { i => o.d.valid && i .contains(o.d.bits.source) }) }) val requestAIO = Vec(addressA.map { i => Vec(outputPorts.map { o => i._1 && o(i._2) }) })
val requestEIO = Vec(in.map { i => Vec(outputIdRanges.map { o => i.e.valid && o .contains(i.e.bits.sink) }) }) val requestCIO = Vec(addressC.map { i => Vec(outputPorts.map { o => i._1 && o(i._2) }) })
val requestBOI = Vec(out.map { o => Vec(inputIdRanges.map { i => o.b.valid && i.contains(o.b.bits.source) }) })
val requestDOI = Vec(out.map { o => Vec(inputIdRanges.map { i => o.d.valid && i.contains(o.d.bits.source) }) })
val requestEIO = Vec(in.map { i => Vec(outputIdRanges.map { o => i.e.valid && o.contains(i.e.bits.sink) }) })
val beatsA = Vec((in zip node.edgesIn) map { case (i, e) => e.numBeats(i.a.bits) }) val beatsA = Vec((in zip node.edgesIn) map { case (i, e) => e.numBeats(i.a.bits) })
val beatsB = Vec((out zip node.edgesOut) map { case (o, e) => e.numBeats(o.b.bits) }) val beatsB = Vec((out zip node.edgesOut) map { case (o, e) => e.numBeats(o.b.bits) })