Merge remote-tracking branch 'origin' into testharness-refactor
This commit is contained in:
commit
ed91e9a89b
@ -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
|
||||||
|
@ -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 _)
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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))
|
||||||
|
@ -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]
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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")
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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"
|
||||||
|
}
|
||||||
|
@ -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)))
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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)))
|
||||||
|
@ -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)
|
||||||
|
@ -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)) }
|
||||||
|
@ -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)))
|
||||||
lazy val addressMask = AddressDecoder(managers.map(_.address))
|
def hasFifoIdFast(address: UInt) = Mux1H(findFast(address), managers.map(m => Bool(m.fifoId.isDefined)))
|
||||||
// !!! 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]) {
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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])
|
||||||
|
@ -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 = {
|
||||||
|
@ -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),
|
||||||
|
@ -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)
|
||||||
|
@ -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,9 +162,13 @@ 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 addressC = (in zip node.edgesIn) map { case (i, e) => (i.c.valid, e.address(i.c.bits)) }
|
||||||
|
|
||||||
|
val requestAIO = Vec(addressA.map { i => Vec(outputPorts.map { o => i._1 && o(i._2) }) })
|
||||||
|
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 requestBOI = Vec(out.map { o => Vec(inputIdRanges.map { i => o.b.valid && i.contains(o.b.bits.source) }) })
|
||||||
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 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 requestEIO = Vec(in.map { i => Vec(outputIdRanges.map { o => i.e.valid && o.contains(i.e.bits.sink) }) })
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user