TLB: add a helper API to determine homogeneous page permissions
This commit is contained in:
		
				
					committed by
					
						 Andrew Waterman
						Andrew Waterman
					
				
			
			
				
	
			
			
			
						parent
						
							fe287864ef
						
					
				
				
					commit
					c847559853
				
			
							
								
								
									
										97
									
								
								src/main/scala/rocket/TLBPermissions.scala
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								src/main/scala/rocket/TLBPermissions.scala
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| // See LICENSE.SiFive for license details. | ||||
|  | ||||
| package rocket | ||||
|  | ||||
| import Chisel._ | ||||
| import diplomacy._ | ||||
| import uncore.tilelink2._ | ||||
|  | ||||
| case class TLBPermissions( | ||||
|   homogeneous: Bool, // if false, the below are undefined | ||||
|   r: Bool, // readable | ||||
|   w: Bool, // writeable | ||||
|   x: Bool, // executable | ||||
|   c: Bool, // cacheable | ||||
|   a: Bool, // arithmetic ops | ||||
|   l: Bool) // logical ops | ||||
|  | ||||
| object TLBPageLookup | ||||
| { | ||||
|   private case class TLBFixedPermissions( | ||||
|     r: Boolean, // readable | ||||
|     w: Boolean, // writeable | ||||
|     x: Boolean, // executable | ||||
|     c: Boolean, // cacheable | ||||
|     a: Boolean, // arithmetic ops | ||||
|     l: Boolean) { // logical ops | ||||
|     val useful = r || w || x || c || a || l | ||||
|   } | ||||
|  | ||||
|   // Unmapped memory is considered to be inhomogeneous | ||||
|   def apply(managers: Seq[TLManagerParameters], xLen: Int, cacheBlockBytes: Int, pageSize: BigInt): UInt => TLBPermissions = { | ||||
|     require (isPow2(xLen) && xLen >= 8) | ||||
|     require (isPow2(cacheBlockBytes) && cacheBlockBytes >= xLen/8) | ||||
|     require (isPow2(pageSize) && pageSize >= cacheBlockBytes) | ||||
|  | ||||
|     val xferSizes = TransferSizes(cacheBlockBytes, cacheBlockBytes) | ||||
|     val allSizes = TransferSizes(1, cacheBlockBytes) | ||||
|     val amoSizes = TransferSizes(4, xLen/8) | ||||
|  | ||||
|     val permissions = managers.map { m => | ||||
|       require (!m.supportsGet        || m.supportsGet       .contains(allSizes),  s"MemoryMap region ${m.name} only supports ${m.supportsGet} Get, but must support ${allSizes}") | ||||
|       require (!m.supportsPutFull    || m.supportsPutFull   .contains(allSizes),  s"MemoryMap region ${m.name} only supports ${m.supportsPutFull} PutFull, but must support ${allSizes}") | ||||
|       require (!m.supportsAcquireB   || m.supportsAcquireB  .contains(xferSizes), s"MemoryMap region ${m.name} only supports ${m.supportsAcquireB} AcquireB, but must support ${xferSizes}") | ||||
|       require (!m.supportsAcquireT   || m.supportsAcquireT  .contains(xferSizes), s"MemoryMap region ${m.name} only supports ${m.supportsAcquireT} AcquireT, but must support ${xferSizes}") | ||||
|       require (!m.supportsLogical    || m.supportsLogical   .contains(amoSizes),  s"MemoryMap region ${m.name} only supports ${m.supportsLogical} Logical, but must support ${amoSizes}") | ||||
|       require (!m.supportsArithmetic || m.supportsArithmetic.contains(amoSizes),  s"MemoryMap region ${m.name} only supports ${m.supportsArithmetic} Arithmetic, but must support ${amoSizes}") | ||||
|       require (m.supportsAcquireT || !m.supportsAcquireB, s"MemoryMap region ${m.name} supports AcquireB (cached read) but not AcquireT (cached write)... and rocket assumes this") | ||||
|  | ||||
|       (m.address, TLBFixedPermissions( | ||||
|         r = m.supportsGet     || m.supportsAcquireB, // if cached, never uses Get | ||||
|         w = m.supportsPutFull || m.supportsAcquireT, // if cached, never uses Put | ||||
|         x = m.executable, | ||||
|         c = m.supportsAcquireB, | ||||
|         a = m.supportsArithmetic, | ||||
|         l = m.supportsLogical)) | ||||
|     } | ||||
|  | ||||
|     val grouped: Map[TLBFixedPermissions, Seq[AddressSet]] = permissions | ||||
|       .filter(_._2.useful) // get rid of no-permission devices | ||||
|       .groupBy(_._2) // group by permission type | ||||
|       .mapValues(seq =>  | ||||
|         AddressSet.unify(seq.flatMap(_._1)) // coalesce same-permission regions | ||||
|         .filter(_.alignment >= pageSize)) // discard any region that's not big enough | ||||
|  | ||||
|     def lowCostProperty(prop: TLBFixedPermissions => Boolean): UInt => Bool = { | ||||
|       val (yesm, nom) = grouped.partition { case (k, eq) => prop(k) } | ||||
|       val (yes, no) = (yesm.values.flatten.toList, nom.values.flatten.toList) | ||||
|       // Find the minimal bits needed to distinguish between yes and no | ||||
|       val decisionMask = AddressDecoder(Seq(yes, no)) | ||||
|       def simplify(x: Seq[AddressSet]) = AddressSet.unify(x.map(_.widen(~decisionMask)).distinct) | ||||
|       val (yesf, nof) = (simplify(yes), simplify(no)) | ||||
|       if (yesf.size < no.size) { | ||||
|         (x: UInt) => yesf.map(_.contains(x)).reduce(_ || _) | ||||
|       } else { | ||||
|         (x: UInt) => !nof.map(_.contains(x)).reduce(_ || _) | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     // Derive simplified property circuits (don't care when !homo) | ||||
|     val rfn = lowCostProperty(_.r) | ||||
|     val wfn = lowCostProperty(_.w) | ||||
|     val xfn = lowCostProperty(_.x) | ||||
|     val cfn = lowCostProperty(_.c) | ||||
|     val afn = lowCostProperty(_.a) | ||||
|     val lfn = lowCostProperty(_.l) | ||||
|  | ||||
|     val homo = AddressSet.unify(grouped.values.flatten.toList) | ||||
|     (x: UInt) => TLBPermissions( | ||||
|       homogeneous = homo.map(_.contains(x)).reduce(_ || _), | ||||
|       r = rfn(x), | ||||
|       w = wfn(x), | ||||
|       x = xfn(x), | ||||
|       c = cfn(x), | ||||
|       a = afn(x), | ||||
|       l = lfn(x)) | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user