Merge pull request #312 from ucb-bar/tl2-cheap-address-decode
Tl2 cheap address decode
This commit is contained in:
		| @@ -77,7 +77,7 @@ object GenerateGlobalAddrMap { | ||||
|         (if (manager.executable)      AddrMapProt.X else 0), cacheable) | ||||
|       val multi = manager.address.size > 1 | ||||
|       manager.address.zipWithIndex.map { case (address, i) => | ||||
|         require (!address.strided) // TL1 can't do this | ||||
|         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)) | ||||
|       } | ||||
|   | ||||
| @@ -231,7 +231,7 @@ class TLEdgeOut( | ||||
|   // Transfers | ||||
|   def Acquire(fromSource: UInt, toAddress: UInt, lgSize: UInt, growPermissions: UInt) = { | ||||
|     require (manager.anySupportAcquire) | ||||
|     val legal = manager.supportsAcquire(toAddress, lgSize) | ||||
|     val legal = manager.supportsAcquireFast(toAddress, lgSize) | ||||
|     val a = Wire(new TLBundleA(bundle)) | ||||
|     a.opcode  := TLMessages.Acquire | ||||
|     a.param   := growPermissions | ||||
| @@ -245,7 +245,7 @@ class TLEdgeOut( | ||||
|  | ||||
|   def Release(fromSource: UInt, toAddress: UInt, lgSize: UInt, shrinkPermissions: UInt) = { | ||||
|     require (manager.anySupportAcquire) | ||||
|     val legal = manager.supportsAcquire(toAddress, lgSize) | ||||
|     val legal = manager.supportsAcquireFast(toAddress, lgSize) | ||||
|     val c = Wire(new TLBundleC(bundle)) | ||||
|     c.opcode  := TLMessages.Release | ||||
|     c.param   := shrinkPermissions | ||||
| @@ -260,7 +260,7 @@ class TLEdgeOut( | ||||
|  | ||||
|   def Release(fromSource: UInt, toAddress: UInt, lgSize: UInt, shrinkPermissions: UInt, data: UInt) = { | ||||
|     require (manager.anySupportAcquire) | ||||
|     val legal = manager.supportsAcquire(toAddress, lgSize) | ||||
|     val legal = manager.supportsAcquireFast(toAddress, lgSize) | ||||
|     val c = Wire(new TLBundleC(bundle)) | ||||
|     c.opcode  := TLMessages.ReleaseData | ||||
|     c.param   := shrinkPermissions | ||||
| @@ -308,7 +308,7 @@ class TLEdgeOut( | ||||
|   // Accesses | ||||
|   def Get(fromSource: UInt, toAddress: UInt, lgSize: UInt) = { | ||||
|     require (manager.anySupportGet) | ||||
|     val legal = manager.supportsGet(toAddress, lgSize) | ||||
|     val legal = manager.supportsGetFast(toAddress, lgSize) | ||||
|     val a = Wire(new TLBundleA(bundle)) | ||||
|     a.opcode  := TLMessages.Get | ||||
|     a.param   := UInt(0) | ||||
| @@ -322,7 +322,7 @@ class TLEdgeOut( | ||||
|  | ||||
|   def Put(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt) = { | ||||
|     require (manager.anySupportPutFull) | ||||
|     val legal = manager.supportsPutFull(toAddress, lgSize) | ||||
|     val legal = manager.supportsPutFullFast(toAddress, lgSize) | ||||
|     val a = Wire(new TLBundleA(bundle)) | ||||
|     a.opcode  := TLMessages.PutFullData | ||||
|     a.param   := UInt(0) | ||||
| @@ -336,7 +336,7 @@ class TLEdgeOut( | ||||
|  | ||||
|   def Put(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, mask : UInt) = { | ||||
|     require (manager.anySupportPutPartial) | ||||
|     val legal = manager.supportsPutPartial(toAddress, lgSize) | ||||
|     val legal = manager.supportsPutPartialFast(toAddress, lgSize) | ||||
|     val a = Wire(new TLBundleA(bundle)) | ||||
|     a.opcode  := TLMessages.PutPartialData | ||||
|     a.param   := UInt(0) | ||||
| @@ -350,7 +350,7 @@ class TLEdgeOut( | ||||
|  | ||||
|   def Arithmetic(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, atomic: UInt) = { | ||||
|     require (manager.anySupportArithmetic) | ||||
|     val legal = manager.supportsArithmetic(toAddress, lgSize) | ||||
|     val legal = manager.supportsArithmeticFast(toAddress, lgSize) | ||||
|     val a = Wire(new TLBundleA(bundle)) | ||||
|     a.opcode  := TLMessages.ArithmeticData | ||||
|     a.param   := atomic | ||||
| @@ -364,7 +364,7 @@ class TLEdgeOut( | ||||
|  | ||||
|   def Logical(fromSource: UInt, toAddress: UInt, lgSize: UInt, data: UInt, atomic: UInt) = { | ||||
|     require (manager.anySupportLogical) | ||||
|     val legal = manager.supportsLogical(toAddress, lgSize) | ||||
|     val legal = manager.supportsLogicalFast(toAddress, lgSize) | ||||
|     val a = Wire(new TLBundleA(bundle)) | ||||
|     a.opcode  := TLMessages.LogicalData | ||||
|     a.param   := atomic | ||||
| @@ -378,7 +378,7 @@ class TLEdgeOut( | ||||
|  | ||||
|   def Hint(fromSource: UInt, toAddress: UInt, lgSize: UInt, param: UInt) = { | ||||
|     require (manager.anySupportHint) | ||||
|     val legal = manager.supportsHint(toAddress, lgSize) | ||||
|     val legal = manager.supportsHintFast(toAddress, lgSize) | ||||
|     val a = Wire(new TLBundleA(bundle)) | ||||
|     a.opcode  := TLMessages.Hint | ||||
|     a.param   := param | ||||
| @@ -445,7 +445,7 @@ class TLEdgeIn( | ||||
|   // Transfers | ||||
|   def Probe(fromAddress: UInt, toSource: UInt, lgSize: UInt, capPermissions: UInt) = { | ||||
|     require (client.anySupportProbe) | ||||
|     val legal = client.supportsProbe(fromAddress, lgSize) | ||||
|     val legal = client.supportsProbe(toSource, lgSize) | ||||
|     val b = Wire(new TLBundleB(bundle)) | ||||
|     b.opcode  := TLMessages.Probe | ||||
|     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))) | ||||
|  | ||||
|     // 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 maxLgLogical     = Mux1H(find, maxLgLogicals) | ||||
|     val maxLgGet         = Mux1H(find, maxLgGets) | ||||
|   | ||||
| @@ -163,10 +163,12 @@ class TLFuzzer( | ||||
|                               edge.Hint(src, addr, size, UInt(0)) | ||||
|                             } else { (glegal, gbits) } | ||||
|  | ||||
|     val legal_dest = edge.manager.containsSafe(addr) | ||||
|  | ||||
|     // Pick a specific message to try to send | ||||
|     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("b001") -> pflegal, | ||||
|       UInt("b010") -> pplegal, | ||||
| @@ -218,14 +220,18 @@ class ClockDivider extends BlackBox { | ||||
| class TLFuzzRAM extends LazyModule | ||||
| { | ||||
|   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 xbar = LazyModule(new TLXbar) | ||||
|   val xbar2= LazyModule(new TLXbar) | ||||
|   val fuzz = LazyModule(new TLFuzzer(5000)) | ||||
|   val cross = LazyModule(new TLAsyncCrossing) | ||||
|  | ||||
|   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) | ||||
|   ram.node := cross.node | ||||
|   gpio.node := TLFragmenter(TLBuffer(xbar.node), 4, 32) | ||||
|   | ||||
| @@ -45,7 +45,7 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f | ||||
|  | ||||
|       // Who wants what? | ||||
|       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 hintWantsD = in.a.valid && hintBitsAtA | ||||
|       val outerWantsD = out.d.valid | ||||
| @@ -57,7 +57,7 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f | ||||
|       assert (!hintHoldsD || hintWantsD) | ||||
|  | ||||
|       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 | ||||
|  | ||||
|       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) | ||||
| } | ||||
|  | ||||
| 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]) | ||||
| { | ||||
|   val num = sources.map(_.range.size).sum | ||||
| @@ -32,6 +42,9 @@ case class IntSourcePortParameters(sources: Seq[IntSourceParameters]) | ||||
|   // The interrupts must perfectly cover the range | ||||
|   require (sources.map(_.range.end).max == num) | ||||
| } | ||||
|  | ||||
| case class IntSinkPortParameters(sinks: Seq[IntSinkParameters]) | ||||
|  | ||||
| case class IntEdge(source: IntSourcePortParameters, sink: IntSinkPortParameters) | ||||
|  | ||||
| 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 | ||||
|     (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 IntOutputNode() extends OutputNode(IntImp) | ||||
| case class IntInputNode() extends InputNode(IntImp) | ||||
|  | ||||
| case class IntSourceNode(device: String, num: Int) extends SourceNode(IntImp)( | ||||
|   IntSourcePortParameters(Seq(IntSourceParameters(device, num))), | ||||
|   (if (num == 0) 0 else 1) to 1) | ||||
| case class IntSinkNode() extends SinkNode(IntImp)(IntSinkPortParameters()) | ||||
| case class IntSourceNode(num: Int) extends SourceNode(IntImp)( | ||||
|   IntSourcePortParameters(Seq(IntSourceParameters(num))), (if (num == 0) 0 else 1) to 1) | ||||
| case class IntSinkNode() extends SinkNode(IntImp)( | ||||
|   IntSinkPortParameters(Seq(IntSinkParameters()))) | ||||
|  | ||||
| case class IntAdapterNode( | ||||
|   sourceFn:       Seq[IntSourcePortParameters] => IntSourcePortParameters, | ||||
| @@ -75,7 +93,7 @@ class IntXbar extends LazyModule | ||||
|   val intnode = IntAdapterNode( | ||||
|     numSourcePorts = 1 to 1, // does it make sense to have more than one interrupt sink? | ||||
|     numSinkPorts   = 1 to 128, | ||||
|     sinkFn         = { _ => IntSinkPortParameters() }, | ||||
|     sinkFn         = { _ => IntSinkPortParameters(Seq(IntSinkParameters())) }, | ||||
|     sourceFn       = { seq => | ||||
|       IntSourcePortParameters((seq zip seq.map(_.num).scanLeft(0)(_+_).init).map { | ||||
|         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) | ||||
|  | ||||
|     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 (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) | ||||
| @@ -33,7 +33,7 @@ object TLMonitor | ||||
|     } | ||||
|  | ||||
|     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 (is_aligned, "'A' channel Get address not aligned to size" + extra) | ||||
|       assert (bundle.param === UInt(0), "'A' channel Get carries invalid param" + extra) | ||||
| @@ -41,7 +41,7 @@ object TLMonitor | ||||
|     } | ||||
|  | ||||
|     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 (is_aligned, "'A' channel PutFull address not aligned to size" + extra) | ||||
|       assert (bundle.param === UInt(0), "'A' channel PutFull carries invalid param" + extra) | ||||
| @@ -49,7 +49,7 @@ object TLMonitor | ||||
|     } | ||||
|  | ||||
|     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 (is_aligned, "'A' channel PutPartial address not aligned to size" + extra) | ||||
|       assert (bundle.param === UInt(0), "'A' channel PutPartial carries invalid param" + extra) | ||||
| @@ -57,7 +57,7 @@ object TLMonitor | ||||
|     } | ||||
|  | ||||
|     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 (is_aligned, "'A' channel Arithmetic address not aligned to size" + 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) { | ||||
|       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 (is_aligned, "'A' channel Logical address not aligned to size" + 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) { | ||||
|       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 (is_aligned, "'A' channel Hint address not aligned to size" + 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) | ||||
|  | ||||
|     // 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 mask = edge.full_mask(bundle) | ||||
|  | ||||
| @@ -150,7 +150,7 @@ object TLMonitor | ||||
|  | ||||
|     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 address_ok = edge.manager.contains(bundle.source) | ||||
|     val address_ok = edge.manager.containsSafe(edge.address(bundle)) | ||||
|  | ||||
|     when (bundle.opcode === TLMessages.ProbeAck) { | ||||
|       assert (address_ok, "'C' channel ProbeAck carries unmanaged address" + extra) | ||||
| @@ -171,7 +171,7 @@ object TLMonitor | ||||
|     } | ||||
|  | ||||
|     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 (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) | ||||
| @@ -180,7 +180,7 @@ object TLMonitor | ||||
|     } | ||||
|  | ||||
|     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 (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) | ||||
|   | ||||
| @@ -82,26 +82,29 @@ case class AddressSet(base: BigInt, mask: BigInt) extends Ordered[AddressSet] | ||||
| { | ||||
|   // Forbid misaligned base address (and empty sets) | ||||
|   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: UInt) = ~(~(x ^ UInt(base)) | UInt(mask)) === UInt(0) | ||||
|   def contains(x: BigInt) = ((x ^ base) & ~mask) == 0 | ||||
|   def contains(x: UInt) = ((x ^ UInt(base)).zext() & SInt(~mask)) === SInt(0) | ||||
|  | ||||
|   // overlap iff bitwise: both care (~mask0 & ~mask1) => both equal (base0=base1) | ||||
|   def overlaps(x: AddressSet) = (~(mask | x.mask) & (base ^ x.base)) == 0 | ||||
|  | ||||
|   // contains iff bitwise: x.mask => mask && contains(x.base) | ||||
|   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 | ||||
|   def strided = alignment1 != mask | ||||
|   // The number of bytes to which the manager must be aligned | ||||
|   def alignment = ((mask + 1) & ~mask) | ||||
|   // Is this a contiguous memory range | ||||
|   def contiguous = alignment == mask+1 | ||||
|  | ||||
|   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) | ||||
|   // AddressSets have one natural Ordering (the containment order, if contiguous) | ||||
|   def compare(x: AddressSet) = { | ||||
|     val primary   = (this.base - x.base).signum // smallest address first | ||||
|     val secondary = (x.mask - this.mask).signum // largest mask first | ||||
| @@ -109,7 +112,13 @@ case class AddressSet(base: BigInt, mask: BigInt) extends Ordered[AddressSet] | ||||
|   } | ||||
|  | ||||
|   // 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( | ||||
| @@ -130,6 +139,7 @@ case class TLManagerParameters( | ||||
|   fifoId:             Option[Int]   = None, | ||||
|   customDTS:          Option[String]= None) | ||||
| { | ||||
|   address.foreach { a => require (a.finite) } | ||||
|   address.combinations(2).foreach({ case Seq(x,y) => | ||||
|     require (!x.overlaps(y)) | ||||
|   }) | ||||
| @@ -144,12 +154,13 @@ case class TLManagerParameters( | ||||
|     supportsPutFull.max, | ||||
|     supportsPutPartial.max).max | ||||
|  | ||||
|   val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected") | ||||
|  | ||||
|   // Generate the config string (in future device tree) | ||||
|   lazy val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected") | ||||
|   lazy val dts = customDTS.getOrElse { | ||||
|     val header = s"${name} {\n" | ||||
|     val middle = address.map { a => | ||||
|       require (!a.strided) // Config String does not support this | ||||
|       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" | ||||
| @@ -158,7 +169,7 @@ case class TLManagerParameters( | ||||
|  | ||||
|   // The device had better not support a transfer larger than it's alignment | ||||
|   address.foreach({ case a => | ||||
|     require (a.alignment1 >= maxTransfer-1) | ||||
|     require (a.alignment >= maxTransfer) | ||||
|   }) | ||||
| } | ||||
|  | ||||
| @@ -198,41 +209,59 @@ case class TLManagerPortParameters(managers: Seq[TLManagerParameters], beatBytes | ||||
|   val anySupportPutPartial = managers.map(!_.supportsPutPartial.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 | ||||
|   def find(address: BigInt) = managers.find(_.address.exists(_.contains(address))) | ||||
|   def findById(id: Int) = managers.find(_.sinkId.contains(id)) | ||||
|  | ||||
|   // 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 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 | ||||
|   def findFifoId(address: UInt) = Mux1H(find(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 findFifoIdSafe(address: UInt) = Mux1H(findSafe(address), managers.map(m => UInt(m.fifoId.map(_+1).getOrElse(0)))) | ||||
|   def findFifoIdFast(address: UInt) = Mux1H(findFast(address), managers.map(m => UInt(m.fifoId.map(_+1).getOrElse(0)))) | ||||
|   def hasFifoIdSafe(address: UInt) = Mux1H(findSafe(address), managers.map(m => Bool(m.fifoId.isDefined))) | ||||
|   def hasFifoIdFast(address: UInt) = Mux1H(findFast(address), managers.map(m => Bool(m.fifoId.isDefined))) | ||||
|  | ||||
|   lazy val addressMask = AddressDecoder(managers.map(_.address)) | ||||
|   // !!! need a cheaper version of find, where we assume a valid address match exists | ||||
|    | ||||
|   // Does this Port manage this ID/address? | ||||
|   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(_ || _) | ||||
|  | ||||
|   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(_ && _) | ||||
|     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 | ||||
|   val supportsAcquire    = safety_helper(_.supportsAcquire)    _ | ||||
|   val supportsArithmetic = safety_helper(_.supportsArithmetic) _ | ||||
|   val supportsLogical    = safety_helper(_.supportsLogical)    _ | ||||
|   val supportsGet        = safety_helper(_.supportsGet)        _ | ||||
|   val supportsPutFull    = safety_helper(_.supportsPutFull)    _ | ||||
|   val supportsPutPartial = safety_helper(_.supportsPutPartial) _ | ||||
|   val supportsHint       = safety_helper(_.supportsHint)       _ | ||||
|   val supportsAcquireSafe    = safety_helper(_.supportsAcquire,    findSafe) _ | ||||
|   val supportsArithmeticSafe = safety_helper(_.supportsArithmetic, findSafe) _ | ||||
|   val supportsLogicalSafe    = safety_helper(_.supportsLogical,    findSafe) _ | ||||
|   val supportsGetSafe        = safety_helper(_.supportsGet,        findSafe) _ | ||||
|   val supportsPutFullSafe    = safety_helper(_.supportsPutFull,    findSafe) _ | ||||
|   val supportsPutPartialSafe = safety_helper(_.supportsPutPartial, findSafe) _ | ||||
|   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( | ||||
| @@ -256,6 +285,8 @@ case class TLClientParameters( | ||||
|     supportsGet.max, | ||||
|     supportsPutFull.max, | ||||
|     supportsPutPartial.max).max | ||||
|  | ||||
|   val name = nodePath.lastOption.map(_.lazyModule.name).getOrElse("disconnected") | ||||
| } | ||||
|  | ||||
| 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_base = edge.address(a) | ||||
|     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 | ||||
|     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_addr_hi = d_base >> shift | (d_beats1 & ~d_counter1) | ||||
|     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 | ||||
|     val d_inc_bytes = inc_bytes.map(_.read(d_addr_hi)) | ||||
| @@ -222,7 +222,8 @@ class TLRAMModel extends LazyModule | ||||
|  | ||||
|       // Check the response is correct | ||||
|       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 | ||||
|  | ||||
|       when (d_flight.opcode === TLMessages.Hint) { | ||||
|   | ||||
| @@ -12,7 +12,7 @@ class TLRegisterNode(address: AddressSet, concurrency: Option[Int] = None, beatB | ||||
|     supportsPutFull    = TransferSizes(1, beatBytes), | ||||
|     fifoId             = Some(0))) // requests are handled in order | ||||
| { | ||||
|   require (!address.strided) | ||||
|   require (address.contiguous) | ||||
|  | ||||
|   // Calling this method causes the matching TL2 bundle to be | ||||
|   // configured to route all requests to the listed RegFields. | ||||
| @@ -75,7 +75,7 @@ object TLRegisterNode | ||||
| abstract class TLRegisterRouterBase(address: AddressSet, interrupts: Int, concurrency: Option[Int], beatBytes: Int, undefZero: Boolean) extends LazyModule | ||||
| { | ||||
|   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]) | ||||
|   | ||||
| @@ -75,6 +75,23 @@ class TLXbar(policy: (Vec[Bool], Bool) => Seq[Bool] = TLXbar.lowestIndex) extend | ||||
|     val inputIdRanges = mapInputIds(node.edgesIn.map(_.client)) | ||||
|     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 | ||||
|     val wide_bundle = io.in(0).params.union(io.out(0).params) | ||||
|  | ||||
| @@ -145,11 +162,15 @@ class TLXbar(policy: (Vec[Bool], Bool) => Seq[Bool] = TLXbar.lowestIndex) extend | ||||
|       in(i).e.ready := Mux1C(grantedEIO(i), out.map(_.e.ready)) | ||||
|     } | ||||
|  | ||||
|     val requestAIO = Vec(in.map  { i => Vec(node.edgesOut.map  { o => i.a.valid && o.manager.contains(o.address(i.a.bits)) }) }) | ||||
|     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 requestEIO = Vec(in.map  { i => Vec(outputIdRanges.map { o => i.e.valid && o        .contains(i.e.bits.sink)       }) }) | ||||
|     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 requestDOI = Vec(out.map { o => Vec(inputIdRanges.map  { i => o.d.valid && i.contains(o.d.bits.source) }) }) | ||||
|     val requestEIO = Vec(in.map  { i => Vec(outputIdRanges.map { o => i.e.valid && o.contains(i.e.bits.sink)   }) }) | ||||
|  | ||||
|     val beatsA = Vec((in  zip node.edgesIn)  map { case (i, e) => e.numBeats(i.a.bits) }) | ||||
|     val beatsB = Vec((out zip node.edgesOut) map { case (o, e) => e.numBeats(o.b.bits) }) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user