1
0

Merge pull request #775 from freechipsproject/unify-only-at-end

Unify only at end
This commit is contained in:
Wesley W. Terpstra 2017-06-01 17:16:48 -07:00 committed by GitHub
commit 38e6512c0f
10 changed files with 50 additions and 46 deletions

View File

@ -82,8 +82,10 @@ trait CoreplexNetwork extends HasCoreplexParameters {
} }
} }
// Make topManagers an Option[] so as to avoid LM name reflection evaluating it...
lazy val topManagers = Some(ManagerUnification(l1tol2.node.edgesIn.headOption.map(_.manager.managers).getOrElse(Nil)))
ResourceBinding { ResourceBinding {
val managers = l1tol2.node.edgesIn.headOption.map(_.manager.managers).getOrElse(Nil) val managers = topManagers.get
val max = managers.flatMap(_.address).map(_.max).max val max = managers.flatMap(_.address).map(_.max).max
val width = ResourceInt((log2Ceil(max)+31) / 32) val width = ResourceInt((log2Ceil(max)+31) / 32)
Resource(root, "width").bind(width) Resource(root, "width").bind(width)
@ -113,7 +115,7 @@ trait CoreplexNetworkModule extends HasCoreplexParameters {
val io: CoreplexNetworkBundle val io: CoreplexNetworkBundle
println("Generated Address Map") println("Generated Address Map")
val ranges = outer.l1tol2.node.edgesIn(0).manager.managers.flatMap { manager => val ranges = outer.topManagers.get.flatMap { manager =>
val prot = (if (manager.supportsGet) "R" else "") + val prot = (if (manager.supportsGet) "R" else "") +
(if (manager.supportsPutFull) "W" else "") + (if (manager.supportsPutFull) "W" else "") +
(if (manager.executable) "X" else "") + (if (manager.executable) "X" else "") +

View File

@ -110,7 +110,7 @@ class TLB(lgMaxSize: Int, nEntries: Int)(implicit edge: TLEdgeOut, p: Parameters
pmp.io.prv := Mux(Bool(usingVM) && (do_refill || io.req.bits.passthrough /* PTW */), PRV.S, priv) pmp.io.prv := Mux(Bool(usingVM) && (do_refill || io.req.bits.passthrough /* PTW */), PRV.S, priv)
val legal_address = edge.manager.findSafe(mpu_physaddr).reduce(_||_) val legal_address = edge.manager.findSafe(mpu_physaddr).reduce(_||_)
def fastCheck(member: TLManagerParameters => Boolean) = def fastCheck(member: TLManagerParameters => Boolean) =
legal_address && Mux1H(edge.manager.findFast(mpu_physaddr), edge.manager.managers.map(m => Bool(member(m)))) legal_address && edge.manager.fastProperty(mpu_physaddr, member, (b:Boolean) => Bool(b))
val cacheable = fastCheck(_.supportsAcquireB) val cacheable = fastCheck(_.supportsAcquireB)
val prot_r = fastCheck(_.supportsGet) && pmp.io.r val prot_r = fastCheck(_.supportsGet) && pmp.io.r
val prot_w = fastCheck(_.supportsPutFull) && pmp.io.w val prot_w = fastCheck(_.supportsPutFull) && pmp.io.w

View File

@ -33,10 +33,6 @@ case class APBSlavePortParameters(
val maxAddress = slaves.map(_.maxAddress).max val maxAddress = slaves.map(_.maxAddress).max
lazy val routingMask = AddressDecoder(slaves.map(_.address))
def findSafe(address: UInt) = Vec(slaves.map(_.address.map(_.contains(address)).reduce(_ || _)))
def findFast(address: UInt) = Vec(slaves.map(_.address.map(_.widen(~routingMask)).distinct.map(_.contains(address)).reduce(_ || _)))
// Require disjoint ranges for addresses // Require disjoint ranges for addresses
slaves.combinations(2).foreach { case Seq(x,y) => slaves.combinations(2).foreach { case Seq(x,y) =>
x.address.foreach { a => y.address.foreach { b => x.address.foreach { a => y.address.foreach { b =>

View File

@ -72,9 +72,12 @@ class AXI4Fragmenter()(implicit p: Parameters) extends LazyModule
val hi = addr >> lgBytes val hi = addr >> lgBytes
val alignment = hi(AXI4Parameters.lenBits-1,0) val alignment = hi(AXI4Parameters.lenBits-1,0)
val allSame = supportedSizes1.filter(_ >= 0).distinct.size <= 1 // We don't care about illegal addresses; bursts or no bursts... whatever circuit is simpler (AXI4ToTL will fix it)
val dynamic1 = Mux1H(slave.findFast(addr), supportedSizes1.map(s => UInt(max(0, s)))) val sizes1 = (supportedSizes1 zip slave.slaves.map(_.address)).filter(_._1 >= 0).groupBy(_._1).mapValues(_.flatMap(_._2))
val fixed1 = UInt(supportedSizes1.filter(_ >= 0).headOption.getOrElse(0)) val reductionMask = AddressDecoder(sizes1.values.toList)
val support1 = Mux1H(sizes1.toList.map { case (v, a) => // maximum supported size-1 based on target address
(AddressSet.unify(a.map(_.widen(~reductionMask)).distinct).map(_.contains(addr)).reduce(_||_), UInt(v))
})
/* We need to compute the largest transfer allowed by the AXI len. /* We need to compute the largest transfer allowed by the AXI len.
* len+1 is the number of beats to execute. * len+1 is the number of beats to execute.
@ -86,7 +89,6 @@ class AXI4Fragmenter()(implicit p: Parameters) extends LazyModule
val wipeHigh = ~leftOR(~len) // clear all bits in position >= a cleared bit val wipeHigh = ~leftOR(~len) // clear all bits in position >= a cleared bit
val remain1 = fillLow | wipeHigh // MSB(a.len+1)-1 val remain1 = fillLow | wipeHigh // MSB(a.len+1)-1
val align1 = ~leftOR(alignment) // transfer size limited by address alignment val align1 = ~leftOR(alignment) // transfer size limited by address alignment
val support1 = if (allSame) fixed1 else dynamic1 // maximum supported size-1 based on target address
val maxSupported1 = remain1 & align1 & support1 // Take the minimum of all the limits val maxSupported1 = remain1 & align1 & support1 // Take the minimum of all the limits
// Things that cause us to degenerate to a single beat // Things that cause us to degenerate to a single beat

View File

@ -49,10 +49,6 @@ case class AXI4SlavePortParameters(
require (maxTransfer <= limit, require (maxTransfer <= limit,
s"maxTransfer ($maxTransfer) cannot be larger than $limit on a $beatBytes*8 width bus") s"maxTransfer ($maxTransfer) cannot be larger than $limit on a $beatBytes*8 width bus")
lazy val routingMask = AddressDecoder(slaves.map(_.address))
def findSafe(address: UInt) = Vec(slaves.map(_.address.map(_.contains(address)).reduce(_ || _)))
def findFast(address: UInt) = Vec(slaves.map(_.address.map(_.widen(~routingMask)).distinct.map(_.contains(address)).reduce(_ || _)))
// Require disjoint ranges for addresses // Require disjoint ranges for addresses
slaves.combinations(2).foreach { case Seq(x,y) => slaves.combinations(2).foreach { case Seq(x,y) =>
x.address.foreach { a => y.address.foreach { b => x.address.foreach { a => y.address.foreach { b =>

View File

@ -13,12 +13,12 @@ object TLArbiter
val lowestIndexFirst: Policy = (width, valids, select) => ~(leftOR(valids) << 1)(width-1, 0) val lowestIndexFirst: Policy = (width, valids, select) => ~(leftOR(valids) << 1)(width-1, 0)
val roundRobin: Policy = (width, valids, select) => { val roundRobin: Policy = (width, valids, select) => if (width == 1) UInt(1, width=1) else {
val valid = valids(width-1, 0) val valid = valids(width-1, 0)
assert (valid === valids) assert (valid === valids)
val mask = RegInit(~UInt(0, width=width)) val mask = RegInit(~UInt(0, width=width))
val filter = Cat(valid & ~mask, valid) val filter = Cat(valid & ~mask, valid)
val unready = (rightOR(filter, width*2) >> 1) | (mask << width) // last right shift unneeded val unready = (rightOR(filter, width*2, width) >> 1) | (mask << width)
val readys = ~((unready >> width) & unready(width-1, 0)) val readys = ~((unready >> width) & unready(width-1, 0))
when (select && valid.orR) { when (select && valid.orR) {
mask := leftOR(readys & valid, width) mask := leftOR(readys & valid, width)

View File

@ -57,7 +57,7 @@ class TLAtomicAutomata(logical: Boolean = true, arithmetic: Boolean = true, conc
// Don't overprovision the CAM // Don't overprovision the CAM
val camSize = min(domainsNeedingHelp.size, concurrency) val camSize = min(domainsNeedingHelp.size, concurrency)
// Compact the fifoIds to only those we care about // Compact the fifoIds to only those we care about
val camFifoIds = managers.map(m => UInt(m.fifoId.map(id => max(0, domainsNeedingHelp.indexOf(id))).getOrElse(0))) def camFifoId(m: TLManagerParameters) = m.fifoId.map(id => max(0, domainsNeedingHelp.indexOf(id))).getOrElse(0)
// CAM entry state machine // CAM entry state machine
val FREE = UInt(0) // unused waiting on Atomic from A val FREE = UInt(0) // unused waiting on Atomic from A
@ -65,11 +65,6 @@ class TLAtomicAutomata(logical: Boolean = true, arithmetic: Boolean = true, conc
val AMO = UInt(2) // AccessDataAck sent up D waiting for A availability val AMO = UInt(2) // AccessDataAck sent up D waiting for A availability
val ACK = UInt(1) // Put sent down A waiting for PutAck from D val ACK = UInt(1) // Put sent down A waiting for PutAck from D
def helper(select: Seq[Bool], x: Seq[TransferSizes], lgSize: UInt) =
if (!passthrough) Bool(false) else
if (x.map(_ == x(0)).reduce(_ && _)) x(0).containsLg(lgSize) else
Mux1H(select, x.map(_.containsLg(lgSize)))
val params = TLAtomicAutomata.CAMParams(out.a.bits.params, domainsNeedingHelp.size) val params = TLAtomicAutomata.CAMParams(out.a.bits.params, domainsNeedingHelp.size)
// Do we need to do anything at all? // Do we need to do anything at all?
if (camSize > 0) { if (camSize > 0) {
@ -85,10 +80,10 @@ class TLAtomicAutomata(logical: Boolean = true, arithmetic: Boolean = true, conc
val cam_dmatch = cam_s.map(e => e.state =/= FREE) // D should inspect these entries val cam_dmatch = cam_s.map(e => e.state =/= FREE) // D should inspect these entries
// Can the manager already handle this message? // Can the manager already handle this message?
val a_address = edgeIn.address(in.a.bits)
val a_size = edgeIn.size(in.a.bits) val a_size = edgeIn.size(in.a.bits)
val a_select = edgeOut.manager.findFast(edgeIn.address(in.a.bits)) val a_canLogical = Bool(passthrough) && edgeOut.manager.supportsLogicalFast (a_address, a_size)
val a_canLogical = helper(a_select, managers.map(_.supportsLogical), a_size) val a_canArithmetic = Bool(passthrough) && edgeOut.manager.supportsArithmeticFast(a_address, a_size)
val a_canArithmetic = helper(a_select, managers.map(_.supportsArithmetic), a_size)
val a_isLogical = in.a.bits.opcode === TLMessages.LogicalData val a_isLogical = in.a.bits.opcode === TLMessages.LogicalData
val a_isArithmetic = in.a.bits.opcode === TLMessages.ArithmeticData val a_isArithmetic = in.a.bits.opcode === TLMessages.ArithmeticData
val a_isSupported = Mux(a_isLogical, a_canLogical, Mux(a_isArithmetic, a_canArithmetic, Bool(true))) val a_isSupported = Mux(a_isLogical, a_canLogical, Mux(a_isArithmetic, a_canArithmetic, Bool(true)))
@ -103,7 +98,7 @@ class TLAtomicAutomata(logical: Boolean = true, arithmetic: Boolean = true, conc
val a_d = a_cam_d.data val a_d = a_cam_d.data
// Does the A request conflict with an inflight AMO? // Does the A request conflict with an inflight AMO?
val a_fifoId = Mux1H(a_select, camFifoIds) val a_fifoId = edgeOut.manager.fastProperty(a_address, camFifoId _, (i:Int) => UInt(i))
val a_cam_busy = (cam_abusy zip cam_a.map(_.fifoId === a_fifoId)) map { case (a,b) => a&&b } reduce (_||_) val a_cam_busy = (cam_abusy zip cam_a.map(_.fifoId === a_fifoId)) map { case (a,b) => a&&b } reduce (_||_)
// (Where) are we are allocating in the CAM? // (Where) are we are allocating in the CAM?

View File

@ -101,20 +101,30 @@ case class TLManagerPortParameters(
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)))
// The safe version will check the entire address // The safe version will check the entire address
def findSafe(address: UInt) = Vec(managers.map(_.address.map(_.contains(address)).reduce(_ || _))) def findSafe(address: UInt) = Vec(managers.map(_.address.map(_.contains(address)).reduce(_ || _)))
// The fast version assumes the address is valid // The fast version assumes the address is valid (you probably want fastProperty instead of this function)
def findFast(address: UInt) = Vec(managers.map(_.address.map(_.widen(~routingMask)).distinct.map(_.contains(address)).reduce(_ || _))) def findFast(address: UInt) = {
val routingMask = AddressDecoder(managers.map(_.address))
Vec(managers.map(_.address.map(_.widen(~routingMask)).distinct.map(_.contains(address)).reduce(_ || _)))
}
// Compute the simplest AddressSets that decide a key
def fastPropertyGroup[K](p: TLManagerParameters => K): Map[K, Seq[AddressSet]] = {
val groups = managers.map(m => (p(m), m.address)).groupBy(_._1).mapValues(_.flatMap(_._2))
val reductionMask = AddressDecoder(groups.values.toList)
groups.mapValues(seq => AddressSet.unify(seq.map(_.widen(~reductionMask)).distinct))
}
// Select a property
def fastProperty[K, D <: Data](address: UInt, p: TLManagerParameters => K, d: K => D): D =
Mux1H(fastPropertyGroup(p).map { case (v, a) => (a.map(_.contains(address)).reduce(_||_), d(v)) })
// Note: returns the actual fifoId + 1 or 0 if None // Note: returns the actual fifoId + 1 or 0 if None
def findFifoIdFast(address: UInt) = Mux1H(findFast(address), managers.map(m => UInt(m.fifoId.map(_+1).getOrElse(0)))) def findFifoIdFast(address: UInt) = fastProperty(address, _.fifoId.map(_+1).getOrElse(0), (i:Int) => UInt(i))
def hasFifoIdFast(address: UInt) = Mux1H(findFast(address), managers.map(m => Bool(m.fifoId.isDefined))) def hasFifoIdFast(address: UInt) = fastProperty(address, _.fifoId.isDefined, (b:Boolean) => Bool(b))
// Does this Port manage this ID/address? // Does this Port manage this ID/address?
def containsSafe(address: UInt) = findSafe(address).reduce(_ || _) def containsSafe(address: UInt) = findSafe(address).reduce(_ || _)
@ -345,9 +355,9 @@ object ManagerUnification
def apply(managers: Seq[TLManagerParameters]) = { def apply(managers: Seq[TLManagerParameters]) = {
// To be unified, devices must agree on all of these terms // To be unified, devices must agree on all of these terms
case class TLManagerKey( case class TLManagerKey(
resources: Seq[Resource],
regionType: RegionType.T, regionType: RegionType.T,
executable: Boolean, executable: Boolean,
lastNode: BaseNode,
supportsAcquireT: TransferSizes, supportsAcquireT: TransferSizes,
supportsAcquireB: TransferSizes, supportsAcquireB: TransferSizes,
supportsArithmetic: TransferSizes, supportsArithmetic: TransferSizes,
@ -357,9 +367,9 @@ object ManagerUnification
supportsPutPartial: TransferSizes, supportsPutPartial: TransferSizes,
supportsHint: TransferSizes) supportsHint: TransferSizes)
def key(x: TLManagerParameters) = TLManagerKey( def key(x: TLManagerParameters) = TLManagerKey(
resources = x.resources,
regionType = x.regionType, regionType = x.regionType,
executable = x.executable, executable = x.executable,
lastNode = x.nodePath.last,
supportsAcquireT = x.supportsAcquireT, supportsAcquireT = x.supportsAcquireT,
supportsAcquireB = x.supportsAcquireB, supportsAcquireB = x.supportsAcquireB,
supportsArithmetic = x.supportsArithmetic, supportsArithmetic = x.supportsArithmetic,

View File

@ -57,14 +57,14 @@ class TLXbar(policy: TLArbiter.Policy = TLArbiter.lowestIndexFirst)(implicit p:
seq(0).copy( seq(0).copy(
minLatency = seq.map(_.minLatency).min, minLatency = seq.map(_.minLatency).min,
endSinkId = outputIdRanges.map(_.map(_.end).getOrElse(0)).max, endSinkId = outputIdRanges.map(_.map(_.end).getOrElse(0)).max,
managers = ManagerUnification(seq.flatMap { port => managers = seq.flatMap { port =>
require (port.beatBytes == seq(0).beatBytes, require (port.beatBytes == seq(0).beatBytes,
s"Xbar data widths don't match: ${port.managers.map(_.name)} has ${port.beatBytes}B vs ${seq(0).managers.map(_.name)} has ${seq(0).beatBytes}B") s"Xbar data widths don't match: ${port.managers.map(_.name)} has ${port.beatBytes}B vs ${seq(0).managers.map(_.name)} has ${seq(0).beatBytes}B")
val fifoIdMapper = fifoIdFactory() val fifoIdMapper = fifoIdFactory()
port.managers map { manager => manager.copy( port.managers map { manager => manager.copy(
fifoId = manager.fifoId.map(fifoIdMapper(_)) fifoId = manager.fifoId.map(fifoIdMapper(_))
)} )}
}) }
) )
}) })

View File

@ -5,6 +5,7 @@ package uncore
import Chisel._ import Chisel._
import diplomacy._ import diplomacy._
import util._ import util._
import scala.math.min
package object tilelink2 package object tilelink2
{ {
@ -19,18 +20,20 @@ package object tilelink2
def UIntToOH1(x: UInt, width: Int) = ~(SInt(-1, width=width).asUInt << x)(width-1, 0) def UIntToOH1(x: UInt, width: Int) = ~(SInt(-1, width=width).asUInt << x)(width-1, 0)
def trailingZeros(x: Int) = if (x > 0) Some(log2Ceil(x & -x)) else None def trailingZeros(x: Int) = if (x > 0) Some(log2Ceil(x & -x)) else None
// Fill 1s from low bits to high bits // Fill 1s from low bits to high bits
def leftOR(x: UInt): UInt = leftOR(x, x.getWidth) def leftOR(x: UInt): UInt = leftOR(x, x.getWidth, x.getWidth)
def leftOR(x: UInt, w: Integer): UInt = { def leftOR(x: UInt, width: Integer, cap: Integer = 999999): UInt = {
val stop = min(width, cap)
def helper(s: Int, x: UInt): UInt = def helper(s: Int, x: UInt): UInt =
if (s >= w) x else helper(s+s, x | (x << s)(w-1,0)) if (s >= stop) x else helper(s+s, x | (x << s)(width-1,0))
helper(1, x)(w-1, 0) helper(1, x)(width-1, 0)
} }
// Fill 1s form high bits to low bits // Fill 1s form high bits to low bits
def rightOR(x: UInt): UInt = rightOR(x, x.getWidth) def rightOR(x: UInt): UInt = rightOR(x, x.getWidth, x.getWidth)
def rightOR(x: UInt, w: Integer): UInt = { def rightOR(x: UInt, width: Integer, cap: Integer = 999999): UInt = {
val stop = min(width, cap)
def helper(s: Int, x: UInt): UInt = def helper(s: Int, x: UInt): UInt =
if (s >= w) x else helper(s+s, x | (x >> s)) if (s >= stop) x else helper(s+s, x | (x >> s))
helper(1, x)(w-1, 0) helper(1, x)(width-1, 0)
} }
// This gets used everywhere, so make the smallest circuit possible ... // This gets used everywhere, so make the smallest circuit possible ...
// Given an address and size, create a mask of beatBytes size // Given an address and size, create a mask of beatBytes size