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/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/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) diff --git a/src/main/scala/uncore/tilelink2/Monitor.scala b/src/main/scala/uncore/tilelink2/Monitor.scala index 87ea1931..29583a82 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) { @@ -186,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) { @@ -204,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) { @@ -411,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) } } 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) 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")))) }