diplomacy: improve PMA circuit QoR
This commit is contained in:
		@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 =>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 =>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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?
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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(_ || _)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user