From 48c7aed4e175871a9c5798272072ac0a4fbf328a Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 20 Mar 2017 11:34:19 -0700 Subject: [PATCH 1/6] Monitor: any probe supported by the client is legal --- src/main/scala/uncore/tilelink2/Monitor.scala | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Monitor.scala b/src/main/scala/uncore/tilelink2/Monitor.scala index 87ea1931..59f5ab1c 100644 --- a/src/main/scala/uncore/tilelink2/Monitor.scala +++ b/src/main/scala/uncore/tilelink2/Monitor.scala @@ -110,10 +110,9 @@ class TLMonitor(args: TLMonitorArgs) extends TLMonitorBase(args) when (bundle.opcode === TLMessages.Probe) { assert (edge.client.supportsProbe(bundle.source, bundle.size), "'B' channel carries Probe type unsupported by client" + extra) assert (address_ok, "'B' channel Probe carries unmanaged address" + extra) - assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'B' channel Probe smaller than a beat" + extra) assert (is_aligned, "'B' channel Probe address not aligned to size" + extra) assert (TLPermissions.isCap(bundle.param), "'B' channel Probe carries invalid cap param" + extra) - assert (~bundle.mask === UInt(0), "'B' channel Probe contains invalid mask" + extra) + assert (bundle.mask === mask, "'B' channel Probe contains invalid mask" + extra) } when (bundle.opcode === TLMessages.Get) { From 778e189bbad78a63f50b6c69c231bffb77ec2824 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 20 Mar 2017 11:44:13 -0700 Subject: [PATCH 2/6] Monitor: ProbeAckData and ReleaseData may carry an error --- src/main/scala/uncore/tilelink2/Monitor.scala | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Monitor.scala b/src/main/scala/uncore/tilelink2/Monitor.scala index 59f5ab1c..177e4d1d 100644 --- a/src/main/scala/uncore/tilelink2/Monitor.scala +++ b/src/main/scala/uncore/tilelink2/Monitor.scala @@ -185,7 +185,6 @@ class TLMonitor(args: TLMonitorArgs) extends TLMonitorBase(args) assert (bundle.size >= UInt(log2Ceil(edge.manager.beatBytes)), "'C' channel ProbeAckData smaller than a beat" + extra) assert (is_aligned, "'C' channel ProbeAckData address not aligned to size" + extra) assert (TLPermissions.isReport(bundle.param), "'C' channel ProbeAckData carries invalid report param" + extra) - assert (!bundle.error, "'C' channel ProbeData carries an error" + extra) } when (bundle.opcode === TLMessages.Release) { @@ -203,7 +202,6 @@ class TLMonitor(args: TLMonitorArgs) extends TLMonitorBase(args) 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 (TLPermissions.isShrink(bundle.param), "'C' channel ReleaseData carries invalid shrink param" + extra) - assert (!bundle.error, "'C' channel ReleaseData carries an error" + extra) } when (bundle.opcode === TLMessages.AccessAck) { From 278f6fea24239cafb77533b3ed56c4a9810c4f3a Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 20 Mar 2017 13:27:24 -0700 Subject: [PATCH 3/6] tilelink2: define is{Request,Response} based on spec --- src/main/scala/rocket/DCache.scala | 2 +- src/main/scala/rocket/NBDcache.scala | 2 +- src/main/scala/uncore/tilelink2/Edges.scala | 14 +++++++++++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/main/scala/rocket/DCache.scala b/src/main/scala/rocket/DCache.scala index 8ed9ba0f..ebb017fd 100644 --- a/src/main/scala/rocket/DCache.scala +++ b/src/main/scala/rocket/DCache.scala @@ -345,7 +345,7 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) { } // Finish TileLink transaction by issuing a GrantAck - grantackq.io.enq.valid := d_done && edge.hasFollowUp(tl_out.d.bits) + grantackq.io.enq.valid := d_done && edge.isRequest(tl_out.d.bits) grantackq.io.enq.bits := edge.GrantAck(tl_out.d.bits) tl_out.e <> grantackq.io.deq assert(!grantackq.io.enq.valid || grantackq.io.enq.ready, "Too many Grants received by dcache.") diff --git a/src/main/scala/rocket/NBDcache.scala b/src/main/scala/rocket/NBDcache.scala index 215d6f20..6a89896d 100644 --- a/src/main/scala/rocket/NBDcache.scala +++ b/src/main/scala/rocket/NBDcache.scala @@ -246,7 +246,7 @@ class MSHR(id: Int)(implicit edge: TLEdgeOut, p: Parameters) extends L1HellaCach val grantackq = Module(new Queue(io.mem_finish.bits, 1)) val can_finish = state.isOneOf(s_invalid, s_refill_req) - grantackq.io.enq.valid := refill_done && edge.hasFollowUp(io.mem_grant.bits) + grantackq.io.enq.valid := refill_done && edge.isRequest(io.mem_grant.bits) grantackq.io.enq.bits := edge.GrantAck(io.mem_grant.bits) io.mem_finish.valid := grantackq.io.deq.valid && can_finish io.mem_finish.bits := grantackq.io.deq.bits diff --git a/src/main/scala/uncore/tilelink2/Edges.scala b/src/main/scala/uncore/tilelink2/Edges.scala index 778eda60..5b8a13cd 100644 --- a/src/main/scala/uncore/tilelink2/Edges.scala +++ b/src/main/scala/uncore/tilelink2/Edges.scala @@ -57,7 +57,7 @@ class TLEdge( } } - def hasFollowUp(x: TLChannel): Bool = { + def isRequest(x: TLChannel): Bool = { x match { case a: TLBundleA => Bool(true) case b: TLBundleB => Bool(true) @@ -71,6 +71,18 @@ class TLEdge( } } + def isResponse(x: TLChannel): Bool = { + x match { + case a: TLBundleA => Bool(false) + case b: TLBundleB => Bool(false) + case c: TLBundleC => !c.opcode(2) || !c.opcode(1) + // opcode =/= TLMessages.Release && + // opcode =/= TLMessages.ReleaseData + case d: TLBundleD => Bool(true) // Grant isResponse + isRequest + case e: TLBundleE => Bool(true) + } + } + def hasData(x: TLChannel): Bool = { val opdata = x match { case a: TLBundleA => !a.opcode(2) From 04892fea013939b6a44ca9d9c2d75e5de5fe7381 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 20 Mar 2017 13:41:19 -0700 Subject: [PATCH 4/6] Monitor: support early ack --- src/main/scala/uncore/tilelink2/Monitor.scala | 60 ++++++++++++++----- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/src/main/scala/uncore/tilelink2/Monitor.scala b/src/main/scala/uncore/tilelink2/Monitor.scala index 177e4d1d..29583a82 100644 --- a/src/main/scala/uncore/tilelink2/Monitor.scala +++ b/src/main/scala/uncore/tilelink2/Monitor.scala @@ -408,34 +408,66 @@ class TLMonitor(args: TLMonitorArgs) extends TLMonitorBase(args) } } - def legalizeSourceUnique(bundle: TLBundleSnoop, edge: TLEdge)(implicit sourceInfo: SourceInfo) { + def legalizeADSource(bundle: TLBundleSnoop, edge: TLEdge)(implicit sourceInfo: SourceInfo) { val inflight = RegInit(UInt(0, width = edge.client.endSourceId)) - val a_last = edge.last(bundle.a.bits, bundle.a.fire()) - val d_last = edge.last(bundle.d.bits, bundle.d.fire()) - - if (edge.manager.minLatency > 0) { - assert(bundle.d.bits.opcode === TLMessages.ReleaseAck || bundle.a.bits.source =/= bundle.d.bits.source || !bundle.a.valid || !bundle.d.valid, s"'A' and 'D' concurrent, despite minlatency ${edge.manager.minLatency}" + extra) - } + val a_first = edge.first(bundle.a.bits, bundle.a.fire()) + val d_first = edge.first(bundle.d.bits, bundle.d.fire()) val a_set = Wire(init = UInt(0, width = edge.client.endSourceId)) - when (bundle.a.fire()) { - when (a_last) { a_set := UIntToOH(bundle.a.bits.source) } + when (bundle.a.fire() && a_first && edge.isRequest(bundle.a.bits)) { + a_set := UIntToOH(bundle.a.bits.source) assert(!inflight(bundle.a.bits.source), "'A' channel re-used a source ID" + extra) } val d_clr = Wire(init = UInt(0, width = edge.client.endSourceId)) - when (bundle.d.fire() && bundle.d.bits.opcode =/= TLMessages.ReleaseAck) { - when (d_last) { d_clr := UIntToOH(bundle.d.bits.source) } + val d_release_ack = bundle.d.bits.opcode === TLMessages.ReleaseAck + when (bundle.d.fire() && d_first && edge.isResponse(bundle.d.bits) && !d_release_ack) { + d_clr := UIntToOH(bundle.d.bits.source) assert((a_set | inflight)(bundle.d.bits.source), "'D' channel acknowledged for nothing inflight" + extra) } + if (edge.manager.minLatency > 0) { + assert(a_set =/= d_clr || !a_set.orR, s"'A' and 'D' concurrent, despite minlatency ${edge.manager.minLatency}" + extra) + } + inflight := (inflight | a_set) & ~d_clr } + def legalizeDESink(bundle: TLBundleSnoop, edge: TLEdge)(implicit sourceInfo: SourceInfo) { + val inflight = RegInit(UInt(0, width = edge.manager.endSinkId)) + + val d_first = edge.first(bundle.d.bits, bundle.d.fire()) + val e_first = Bool(true) + + val d_set = Wire(init = UInt(0, width = edge.manager.endSinkId)) + when (bundle.d.fire() && d_first && edge.isRequest(bundle.d.bits)) { + d_set := UIntToOH(bundle.d.bits.sink) + assert(!inflight(bundle.d.bits.sink), "'D' channel re-used a sink ID" + extra) + } + + val e_clr = Wire(init = UInt(0, width = edge.manager.endSinkId)) + when (bundle.e.fire() && e_first && edge.isResponse(bundle.e.bits)) { + e_clr := UIntToOH(bundle.e.bits.sink) + assert((d_set | inflight)(bundle.e.bits.sink), "'E' channel acknowledged for nothing inflight" + extra) + } + + // edge.client.minLatency applies to BC, not DE + + inflight := (inflight | d_set) & ~e_clr + } + + def legalizeUnique(bundle: TLBundleSnoop, edge: TLEdge)(implicit sourceInfo: SourceInfo) { + legalizeADSource(bundle, edge) + if (edge.client.anySupportProbe && edge.manager.anySupportAcquireB) { + // legalizeBCSourceAddress(bundle, edge) // too much state needed to synthesize... + legalizeDESink(bundle, edge) + } + } + def legalize(bundle: TLBundleSnoop, edge: TLEdge, reset: Bool) { - legalizeFormat (bundle, edge) - legalizeMultibeat (bundle, edge) - legalizeSourceUnique(bundle, edge) + legalizeFormat (bundle, edge) + legalizeMultibeat(bundle, edge) + legalizeUnique (bundle, edge) } } From 431cb41e270b9eceb345ba9203a2cb6c23e28bcf Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 20 Mar 2017 13:41:29 -0700 Subject: [PATCH 5/6] tilelink2 Parameters: clarify client minLatency is B=>C, not D=>E --- src/main/scala/uncore/tilelink2/Parameters.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/uncore/tilelink2/Parameters.scala b/src/main/scala/uncore/tilelink2/Parameters.scala index 01d2b620..26e531ed 100644 --- a/src/main/scala/uncore/tilelink2/Parameters.scala +++ b/src/main/scala/uncore/tilelink2/Parameters.scala @@ -189,7 +189,7 @@ case class TLClientParameters( case class TLClientPortParameters( clients: Seq[TLClientParameters], unsafeAtomics: Boolean = false, - minLatency: Int = 0) // Atomics are executed as get+put + minLatency: Int = 0) // Only applies to B=>C { require (!clients.isEmpty) require (minLatency >= 0) From 4eef317e8491b120d4fb9ec1f6cb2372a5209f4b Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 20 Mar 2017 14:48:51 -0700 Subject: [PATCH 6/6] RegisterRouter: support devices with gaps --- src/main/scala/uncore/devices/Clint.scala | 2 +- src/main/scala/uncore/devices/Plic.scala | 2 +- .../scala/uncore/tilelink2/RegisterRouter.scala | 17 +++++++++++------ 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/main/scala/uncore/devices/Clint.scala b/src/main/scala/uncore/devices/Clint.scala index 8e9427f8..673106d8 100644 --- a/src/main/scala/uncore/devices/Clint.scala +++ b/src/main/scala/uncore/devices/Clint.scala @@ -40,7 +40,7 @@ class CoreplexLocalInterrupter(address: BigInt = 0x02000000)(implicit p: Paramet } val node = TLRegisterNode( - address = AddressSet(address, size-1), + address = Seq(AddressSet(address, size-1)), device = device, beatBytes = p(XLen)/8) diff --git a/src/main/scala/uncore/devices/Plic.scala b/src/main/scala/uncore/devices/Plic.scala index 98e54f0c..6c95cca8 100644 --- a/src/main/scala/uncore/devices/Plic.scala +++ b/src/main/scala/uncore/devices/Plic.scala @@ -72,7 +72,7 @@ class TLPLIC(maxPriorities: Int, address: BigInt = 0xC000000)(implicit p: Parame } val node = TLRegisterNode( - address = AddressSet(address, PLICConsts.size-1), + address = Seq(AddressSet(address, PLICConsts.size-1)), device = device, beatBytes = p(XLen)/8, undefZero = false) diff --git a/src/main/scala/uncore/tilelink2/RegisterRouter.scala b/src/main/scala/uncore/tilelink2/RegisterRouter.scala index e46c2a56..fa5da920 100644 --- a/src/main/scala/uncore/tilelink2/RegisterRouter.scala +++ b/src/main/scala/uncore/tilelink2/RegisterRouter.scala @@ -9,7 +9,7 @@ import regmapper._ import scala.math.{min,max} class TLRegisterNode( - address: AddressSet, + address: Seq[AddressSet], device: Device, deviceKey: String = "reg", concurrency: Int = 0, @@ -18,7 +18,7 @@ class TLRegisterNode( executable: Boolean = false) extends TLManagerNode(Seq(TLManagerPortParameters( Seq(TLManagerParameters( - address = Seq(address), + address = address, resources = Seq(Resource(device, deviceKey)), executable = executable, supportsGet = TransferSizes(1, beatBytes), @@ -28,7 +28,12 @@ class TLRegisterNode( beatBytes = beatBytes, minLatency = min(concurrency, 1)))) // the Queue adds at most one cycle { - require (address.contiguous) + val size = 1 << log2Ceil(1 + address.map(_.max).max - address.map(_.base).min) + require (size >= beatBytes) + address.foreach { case a => + require (a.widen(size-1).base == address.head.widen(size-1).base, + s"TLRegisterNode addresses (${address}) must be aligned to its size ${size}") + } // Calling this method causes the matching TL2 bundle to be // configured to route all requests to the listed RegFields. @@ -43,7 +48,7 @@ class TLRegisterNode( val (sourceEnd, sourceOff) = (edge.bundle.sourceBits + sizeEnd, sizeEnd) val (addrLoEnd, addrLoOff) = (log2Up(beatBytes) + sourceEnd, sourceEnd) - val params = RegMapperParams(log2Up((address.mask+1)/beatBytes), beatBytes, addrLoEnd) + val params = RegMapperParams(log2Up(size/beatBytes), beatBytes, addrLoEnd) val in = Wire(Decoupled(new RegMapperInput(params))) in.bits.read := a.bits.opcode === TLMessages.Get in.bits.index := edge.addr_hi(a.bits) @@ -81,7 +86,7 @@ class TLRegisterNode( object TLRegisterNode { def apply( - address: AddressSet, + address: Seq[AddressSet], device: Device, deviceKey: String = "reg", concurrency: Int = 0, @@ -98,7 +103,7 @@ object TLRegisterNode abstract class TLRegisterRouterBase(devname: String, devcompat: Seq[String], val address: AddressSet, interrupts: Int, concurrency: Int, beatBytes: Int, undefZero: Boolean, executable: Boolean)(implicit p: Parameters) extends LazyModule { val device = new SimpleDevice(devname, devcompat) - val node = TLRegisterNode(address, device, "reg", concurrency, beatBytes, undefZero, executable) + val node = TLRegisterNode(Seq(address), device, "reg", concurrency, beatBytes, undefZero, executable) val intnode = IntSourceNode(IntSourcePortSimple(num = interrupts, resources = Seq(Resource(device, "int")))) }