diff --git a/src/main/scala/uncore/axi4/ToTL.scala b/src/main/scala/uncore/axi4/ToTL.scala index eda60a78..1921c37a 100644 --- a/src/main/scala/uncore/axi4/ToTL.scala +++ b/src/main/scala/uncore/axi4/ToTL.scala @@ -15,7 +15,7 @@ case class AXI4ToTLNode() extends MixedNode(AXI4Imp, TLImp)( nodePath = m.nodePath) })) }, - uFn = { case (1, Seq(TLManagerPortParameters(managers, beatBytes, _))) => + uFn = { case (1, Seq(TLManagerPortParameters(managers, beatBytes, _, _))) => Seq(AXI4SlavePortParameters(beatBytes = beatBytes, slaves = managers.map { m => AXI4SlaveParameters( address = m.address, diff --git a/src/main/scala/uncore/tilelink2/Broadcast.scala b/src/main/scala/uncore/tilelink2/Broadcast.scala new file mode 100644 index 00000000..e330e3d1 --- /dev/null +++ b/src/main/scala/uncore/tilelink2/Broadcast.scala @@ -0,0 +1,297 @@ +// See LICENSE for license details. + +package uncore.tilelink2 + +import Chisel._ +import diplomacy._ +import scala.math.{min,max} + +class TLBroadcast(lineBytes: Int, numTrackers: Int = 4) extends LazyModule +{ + require (lineBytes > 0 && isPow2(lineBytes)) + require (numTrackers > 0) + + val node = TLAdapterNode( + clientFn = { case Seq(cp) => + cp.copy(clients = Seq(TLClientParameters( + sourceId = IdRange(0, 1 << log2Ceil(cp.endSourceId*4))))) + }, + managerFn = { case Seq(mp) => + mp.copy( + endSinkId = numTrackers, + minLatency = 1, + managers = mp.managers.map { m => + // We are the last level manager + require (m.regionType != RegionType.CACHED) + require (m.regionType != RegionType.TRACKED) + require (!m.supportsAcquire) + // We only manage addresses which are uncached + if (m.regionType == RegionType.UNCACHED) { + // The device had better support line transfers + require (!m.supportsPutFull || m.supportsPutFull .contains(lineBytes)) + require (!m.supportsPutPartial || m.supportsPutPartial.contains(lineBytes)) + require (!m.supportsGet || m.supportsGet .contains(lineBytes)) + m.copy( + regionType = RegionType.TRACKED, + supportsAcquire = TransferSizes(1, lineBytes), + // truncate supported accesses to lineBytes (we only ever probe for one line) + supportsPutFull = TransferSizes(m.supportsPutFull .min, min(m.supportsPutFull .max, lineBytes)), + supportsPutPartial = TransferSizes(m.supportsPutPartial.min, min(m.supportsPutPartial.max, lineBytes)), + supportsGet = TransferSizes(m.supportsGet .min, min(m.supportsGet .max, lineBytes)), + fifoId = None // trackers do not respond in FIFO order! + ) + } else { + m + } + } + ) + } + ) + + lazy val module = new LazyModuleImp(this) { + val io = new Bundle { + val in = node.bundleIn + val out = node.bundleOut + } + + val in = io.in(0) + val out = io.out(0) + val edgeIn = node.edgesIn(0) + val edgeOut = node.edgesOut(0) + val clients = edgeIn.client.clients + val managers = edgeOut.manager.managers + val lineShift = log2Ceil(lineBytes) + + import TLBroadcastConstants._ + + require (lineBytes >= edgeOut.manager.beatBytes) + // For the probe walker, we need to identify all the caches + val caches = clients.filter(_.supportsProbe).map(_.sourceId) + val cache_targets = Vec(caches.map(c => UInt(c.start))) + + // Create the request tracker queues + val trackers = Seq.tabulate(numTrackers) { id => + Module(new TLBroadcastTracker(id, lineBytes, log2Up(caches.size), edgeIn, edgeOut)).io + } + + // We always accept E + in.e.ready := Bool(true) + (trackers zip UIntToOH(in.e.bits.sink).toBools) foreach { case (tracker, select) => + tracker.e_last := select && in.e.fire() + } + + // Depending on the high source bits, we might transform D + val d_high = 1 << log2Ceil(edgeIn.client.endSourceId) + val d_what = out.d.bits.source(d_high+1, d_high) + val d_drop = d_what === DROP + val d_hasData = edgeOut.hasData(out.d.bits) + val d_normal = Wire(in.d) + val d_trackerOH = Vec(trackers.map { t => !t.idle && t.source === d_normal.bits.source }).asUInt + + out.d.ready := d_normal.ready || d_drop + d_normal.valid := out.d.valid && !d_drop + d_normal.bits := out.d.bits // truncates source + when (d_what(1)) { // TRANSFORM_* + d_normal.bits.opcode := Mux(d_hasData, TLMessages.GrantData, TLMessages.ReleaseAck) + d_normal.bits.param := Mux(d_hasData, Mux(d_what(0), TLPermissions.toT, TLPermissions.toB), UInt(0)) + } + d_normal.bits.sink := OHToUInt(d_trackerOH) + assert (!d_normal.valid || d_trackerOH.orR()) + + // A tracker response is anything neither dropped nor a ReleaseAck + val d_response = d_hasData || !d_what(1) + val (_, d_last, _) = edgeIn.firstlast(d_normal) + (trackers zip d_trackerOH.toBools) foreach { case (tracker, select) => + tracker.d_last := select && d_normal.fire() && d_response && d_last + } + + // Incoming C can be: + // ProbeAck => decrement tracker, drop + // ProbeAckData => decrement tracker, send out A as PutFull(DROP) + // ReleaseData => send out A as PutFull(TRANSFORM) + // Release => send out D as ReleaseAck + + val c_probeack = in.c.bits.opcode === TLMessages.ProbeAck + val c_probeackdata = in.c.bits.opcode === TLMessages.ProbeAckData + val c_releasedata = in.c.bits.opcode === TLMessages.ReleaseData + val c_release = in.c.bits.opcode === TLMessages.Release + + // Decrement the tracker's outstanding probe counter + val c_decrement = in.c.fire() && (c_probeack || c_probeackdata) + val (_, c_last, _) = edgeIn.firstlast(in.c) + trackers foreach { tracker => + tracker.probeack := c_decrement && c_last && tracker.line === (in.c.bits.address >> lineShift) + } + + val releaseack = Wire(in.d) + val putfull = Wire(out.a) + + in.c.ready := c_probeack || Mux(c_release, releaseack.ready, putfull.ready) + + releaseack.valid := in.c.valid && c_release + releaseack.bits := edgeIn.ReleaseAck(in.c.bits.address, UInt(0), in.c.bits.source, in.c.bits.size) + + val put_what = Mux(c_releasedata, TRANSFORM_B, DROP) + putfull.valid := in.c.valid && (c_probeackdata || c_releasedata) + putfull.bits := edgeOut.Put(Cat(put_what, in.c.bits.source), in.c.bits.address, in.c.bits.size, in.c.bits.data)._2 + + // Combine ReleaseAck or the modified D + TLArbiter(TLArbiter.lowestIndexFirst)(in.d, (UInt(0), releaseack), (edgeOut.numBeats1(d_normal.bits), d_normal)) + // Combine the PutFull with the trackers + TLArbiter(TLArbiter.lowestIndexFirst)(out.a, + ((edgeOut.numBeats1(putfull.bits), putfull) +: + trackers.map { t => (edgeOut.numBeats1(t.out_a.bits), t.out_a) }):_*) + + // The Probe FSM walks all caches and probes them + val probe_todo = RegInit(UInt(0, width = caches.size)) + val probe_line = Reg(UInt()) + val probe_perms = Reg(UInt(width = 2)) + val probe_next = probe_todo & ~(leftOR(probe_todo) << 1) + val probe_busy = probe_todo.orR() + val probe_target = Mux1H(probe_next, cache_targets) + + // Probe whatever the FSM wants to do next + in.b.valid := probe_busy + in.b.bits := edgeIn.Probe(probe_line << lineShift, probe_target, UInt(lineShift), probe_perms)._2 + when (in.b.fire()) { probe_todo := probe_todo & ~probe_next } + + // Which cache does a request come from? + val a_cache = Vec(caches.map(_.contains(in.a.bits.source))).asUInt + val (a_first, _, _) = edgeIn.firstlast(in.a) + + // To accept a request from A, the probe FSM must be idle and there must be a matching tracker + val freeTrackers = Vec(trackers.map { t => t.idle }).asUInt + val freeTracker = freeTrackers.orR() + val matchTrackers = Vec(trackers.map { t => t.line === in.a.bits.address >> lineShift }).asUInt + val matchTracker = matchTrackers.orR() + val allocTracker = freeTrackers & ~(leftOR(freeTrackers) << 1) + val selectTracker = Mux(matchTracker, matchTrackers, allocTracker) + + val trackerReady = Vec(trackers.map(_.in_a.ready)).asUInt + in.a.ready := (!a_first || !probe_busy) && (selectTracker & trackerReady).orR() + (trackers zip selectTracker.toBools) foreach { case (t, select) => + t.in_a.valid := in.a.valid && select && (!a_first || !probe_busy) + t.in_a.bits := in.a.bits + t.in_a_first := a_first + t.probe := Mux(a_cache.orR(), UInt(caches.size-1), UInt(caches.size)) + } + + when (in.a.fire() && a_first) { + probe_todo := ~a_cache // probe all but the cache who poked us + probe_line := in.a.bits.address >> lineShift + probe_perms := MuxLookup(in.a.bits.opcode, Wire(UInt(width = 2)), Array( + TLMessages.PutFullData -> TLPermissions.toN, + TLMessages.PutPartialData -> TLPermissions.toN, + TLMessages.ArithmeticData -> TLPermissions.toN, + TLMessages.LogicalData -> TLPermissions.toN, + TLMessages.Get -> TLPermissions.toB, + TLMessages.Hint -> MuxLookup(in.a.bits.param, Wire(UInt(width = 2)), Array( + TLHints.PREFETCH_READ -> TLPermissions.toB, + TLHints.PREFETCH_WRITE -> TLPermissions.toN)), + TLMessages.Acquire -> MuxLookup(in.a.bits.param, Wire(UInt(width = 2)), Array( + TLPermissions.NtoB -> TLPermissions.toB, + TLPermissions.NtoT -> TLPermissions.toN, + TLPermissions.BtoT -> TLPermissions.toN)))) + } + + // The outer TL connections may not be cached + out.b.ready := Bool(true) + out.c.valid := Bool(false) + out.e.valid := Bool(false) + } +} + +class TLBroadcastTracker(id: Int, lineBytes: Int, probeCountBits: Int, edgeIn: TLEdgeIn, edgeOut: TLEdgeOut) extends Module +{ + val io = new Bundle { + val in_a_first = Bool(INPUT) + val in_a = Decoupled(new TLBundleA(edgeIn.bundle)).flip + val out_a = Decoupled(new TLBundleA(edgeOut.bundle)) + val probe = UInt(INPUT, width = probeCountBits) + val probeack = Bool(INPUT) + val d_last = Bool(INPUT) + val e_last = Bool(INPUT) + val source = UInt(OUTPUT) // the source awaiting D response + val line = UInt(OUTPUT) // the line waiting for probes + val idle = Bool(OUTPUT) + } + + val lineShift = log2Ceil(lineBytes) + import TLBroadcastConstants._ + + // Only one operation can be inflight per line, because we need to be sure + // we send the request after all the probes we sent and before all the next probes + val idle = RegInit(Bool(true)) + val opcode = Reg(io.in_a.bits.opcode) + val param = Reg(io.in_a.bits.param) + val size = Reg(io.in_a.bits.size) + val source = Reg(io.in_a.bits.source) + val address = RegInit(UInt(id << lineShift, width = io.in_a.bits.address.getWidth)) + val count = Reg(UInt(width = probeCountBits)) + + when (io.in_a.fire() && io.in_a_first) { + assert (idle) + idle := Bool(false) + opcode := io.in_a.bits.opcode + param := io.in_a.bits.param + size := io.in_a.bits.size + source := io.in_a.bits.source + address := io.in_a.bits.address + count := io.probe + } + when (io.d_last) { + assert (!idle) + idle := opcode =/= TLMessages.Acquire + } + when (io.e_last) { + assert (!idle) + idle := Bool(true) + } + when (io.probeack) { + assert (count > UInt(0)) + count := count - UInt(1) + } + + io.idle := idle + io.source := source + io.line := address >> lineShift + + class Data extends Bundle { + val mask = io.in_a.bits.mask.cloneType + val data = io.in_a.bits.data.cloneType + } + + val i_data = Wire(Decoupled(new Data)) + val o_data = Queue(i_data, lineBytes / edgeIn.manager.beatBytes) + + io.in_a.ready := (idle || !io.in_a_first) && i_data.ready + i_data.valid := (idle || !io.in_a_first) && io.in_a.valid + i_data.bits.mask := io.in_a.bits.mask + i_data.bits.data := io.in_a.bits.data + + val probe_done = count === UInt(0) + val acquire = opcode === TLMessages.Acquire + + val transform = MuxLookup(param, Wire(UInt(width = 2)), Array( + TLPermissions.NtoB -> TRANSFORM_B, + TLPermissions.NtoT -> TRANSFORM_T, + TLPermissions.BtoT -> TRANSFORM_T)) + + o_data.ready := io.out_a.ready && probe_done + io.out_a.valid := o_data.valid && probe_done + io.out_a.bits.opcode := Mux(acquire, TLMessages.Get, opcode) + io.out_a.bits.param := Mux(acquire, UInt(0), param) + io.out_a.bits.size := size + io.out_a.bits.source := Cat(Mux(acquire, transform, PASS), source) + io.out_a.bits.address := address + io.out_a.bits.mask := o_data.bits.mask + io.out_a.bits.data := o_data.bits.data +} + +object TLBroadcastConstants +{ + val TRANSFORM_T = UInt(3) + val TRANSFORM_B = UInt(2) + val DROP = UInt(1) + val PASS = UInt(0) +} diff --git a/src/main/scala/uncore/tilelink2/Bundles.scala b/src/main/scala/uncore/tilelink2/Bundles.scala index 0122b3d5..cee73942 100644 --- a/src/main/scala/uncore/tilelink2/Bundles.scala +++ b/src/main/scala/uncore/tilelink2/Bundles.scala @@ -88,6 +88,12 @@ object TLAtomics def isLogical(x: UInt) = x <= SWAP } +object TLHints +{ + val PREFETCH_READ = UInt(0) + val PREFETCH_WRITE = UInt(1) +} + sealed trait TLChannel extends TLBundleBase { val channelName: String } diff --git a/src/main/scala/uncore/tilelink2/HintHandler.scala b/src/main/scala/uncore/tilelink2/HintHandler.scala index 3ba187e0..213f7625 100644 --- a/src/main/scala/uncore/tilelink2/HintHandler.scala +++ b/src/main/scala/uncore/tilelink2/HintHandler.scala @@ -43,7 +43,7 @@ class TLHintHandler(supportManagers: Boolean = true, supportClients: Boolean = f out.a.valid := in.a.valid && !hintBitsAtA in.a.ready := Mux(hintBitsAtA, hint.ready, out.a.ready) - hint.bits := edgeIn.HintAck(in.a.bits, edgeOut.manager.findIdStartFast(address)) + hint.bits := edgeIn.HintAck(in.a.bits, UInt(0)) out.a.bits := in.a.bits TLArbiter(TLArbiter.lowestIndexFirst)(in.d, (edgeOut.numBeats1(out.d.bits), out.d), (UInt(0), Queue(hint, 1))) diff --git a/src/main/scala/uncore/tilelink2/Monitor.scala b/src/main/scala/uncore/tilelink2/Monitor.scala index 26c60d97..a8af77e3 100644 --- a/src/main/scala/uncore/tilelink2/Monitor.scala +++ b/src/main/scala/uncore/tilelink2/Monitor.scala @@ -216,7 +216,7 @@ class TLMonitor(gen: () => TLBundleSnoop, edge: () => TLEdge, sourceInfo: Source val source_ok = edge.client.contains(bundle.source) val is_aligned = edge.isAligned(bundle.addr_lo, bundle.size) - val sink_ok = edge.manager.containsById(bundle.sink) + val sink_ok = bundle.sink < UInt(edge.manager.endSinkId) when (bundle.opcode === TLMessages.ReleaseAck) { assert (source_ok, "'D' channel ReleaseAck carries invalid source ID" + extra) @@ -270,7 +270,8 @@ class TLMonitor(gen: () => TLBundleSnoop, edge: () => TLEdge, sourceInfo: Source } def legalizeFormatE(bundle: TLBundleE, edge: TLEdge)(implicit sourceInfo: SourceInfo) { - assert (edge.manager.containsById(bundle.sink), "'E' channels carries invalid sink ID" + extra) + val sink_ok = bundle.sink < UInt(edge.manager.endSinkId) + assert (sink_ok, "'E' channels carries invalid sink ID" + extra) } def legalizeFormat(bundle: TLBundleSnoop, edge: TLEdge)(implicit sourceInfo: SourceInfo) = { diff --git a/src/main/scala/uncore/tilelink2/Nodes.scala b/src/main/scala/uncore/tilelink2/Nodes.scala index 962517ba..07cbd94c 100644 --- a/src/main/scala/uncore/tilelink2/Nodes.scala +++ b/src/main/scala/uncore/tilelink2/Nodes.scala @@ -108,7 +108,7 @@ object TLClientNode object TLManagerNode { def apply(beatBytes: Int, params: TLManagerParameters) = - new TLManagerNode(TLManagerPortParameters(Seq(params), beatBytes, 0), 1 to 1) + new TLManagerNode(TLManagerPortParameters(Seq(params), beatBytes, minLatency = 0), 1 to 1) } case class TLAdapterNode( diff --git a/src/main/scala/uncore/tilelink2/Parameters.scala b/src/main/scala/uncore/tilelink2/Parameters.scala index 4499b852..8ffea166 100644 --- a/src/main/scala/uncore/tilelink2/Parameters.scala +++ b/src/main/scala/uncore/tilelink2/Parameters.scala @@ -8,7 +8,6 @@ import scala.math.max case class TLManagerParameters( address: Seq[AddressSet], - sinkId: IdRange = IdRange(0, 1), regionType: RegionType.T = RegionType.GET_EFFECTS, executable: Boolean = false, // processor can execute from this memory nodePath: Seq[BaseNode] = Seq(), @@ -59,22 +58,15 @@ case class TLManagerParameters( case class TLManagerPortParameters( managers: Seq[TLManagerParameters], beatBytes: Int, + endSinkId: Int = 1, minLatency: Int = 0) { require (!managers.isEmpty) require (isPow2(beatBytes)) + require (endSinkId > 0) require (minLatency >= 0) - // Require disjoint ranges for Ids and addresses - managers.combinations(2).foreach({ case Seq(x,y) => - require (!x.sinkId.overlaps(y.sinkId)) - x.address.foreach({ a => y.address.foreach({ b => - require (!a.overlaps(b)) - })}) - }) - // Bounds on required sizes - def endSinkId = managers.map(_.sinkId.end).max def maxAddress = managers.map(_.maxAddress).max def maxTransfer = managers.map(_.maxTransfer).max @@ -101,12 +93,6 @@ case class TLManagerPortParameters( // 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 findById(id: UInt) = Vec(managers.map(_.sinkId.contains(id))) - def findIdStartFast(address: UInt) = Mux1H(findFast(address), managers.map(m => UInt(m.sinkId.start))) - 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(_ || _))) @@ -119,8 +105,6 @@ case class TLManagerPortParameters( // Does this Port manage this ID/address? 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 safe_helper(member: TLManagerParameters => TransferSizes)(address: UInt, lgSize: UInt) = { val allSame = managers.map(member(_) == member(managers(0))).reduce(_ && _) diff --git a/src/main/scala/uncore/tilelink2/RAMModel.scala b/src/main/scala/uncore/tilelink2/RAMModel.scala index 7ba18da0..37dc2878 100644 --- a/src/main/scala/uncore/tilelink2/RAMModel.scala +++ b/src/main/scala/uncore/tilelink2/RAMModel.scala @@ -220,8 +220,6 @@ class TLRAMModel(log: String = "") extends LazyModule when (d_fire) { // Check the response is correct assert (d_size === d_flight.size) - 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) { diff --git a/src/main/scala/uncore/tilelink2/ToAXI4.scala b/src/main/scala/uncore/tilelink2/ToAXI4.scala index 509a663c..6b476815 100644 --- a/src/main/scala/uncore/tilelink2/ToAXI4.scala +++ b/src/main/scala/uncore/tilelink2/ToAXI4.scala @@ -19,10 +19,9 @@ case class TLToAXI4Node(idBits: Int) extends MixedNode(TLImp, AXI4Imp)( Seq(AXI4MasterPortParameters(masters)) }, uFn = { case (1, Seq(AXI4SlavePortParameters(slaves, beatBytes))) => - val managers = slaves.zipWithIndex.map { case (s, id) => + val managers = slaves.map { case s => TLManagerParameters( address = s.address, - sinkId = IdRange(id, id+1), regionType = s.regionType, executable = s.executable, nodePath = s.nodePath, @@ -31,7 +30,7 @@ case class TLToAXI4Node(idBits: Int) extends MixedNode(TLImp, AXI4Imp)( supportsPutPartial = s.supportsWrite) // AXI4 is NEVER fifo in TL sense (R+W are independent) } - Seq(TLManagerPortParameters(managers, beatBytes, 0)) + Seq(TLManagerPortParameters(managers, beatBytes, 1, 0)) }, numPO = 1 to 1, numPI = 1 to 1) @@ -64,7 +63,7 @@ class TLToAXI4(idBits: Int, combinational: Boolean = true) extends LazyModule // AR before working on AW might have an AW slipped between two AR fragments. val out_b = Queue.irrevocable(out.b, entries=edgeIn.client.endSourceId, flow=combinational) - // We need to keep the following state from A => D: (addr_lo, size, sink, source) + // We need to keep the following state from A => D: (addr_lo, size, source) // All of those fields could potentially require 0 bits (argh. Chisel.) // We will pack as many of the lowest bits of state as fit into the AXI ID. // Any bits left-over must be put into a bank of Queues. @@ -72,46 +71,39 @@ class TLToAXI4(idBits: Int, combinational: Boolean = true) extends LazyModule // The Queues are deep enough that every source has guaranteed space in its Queue. val sourceBits = log2Ceil(edgeIn.client.endSourceId) - val sinkBits = log2Ceil(edgeIn.manager.endSinkId) val sizeBits = log2Ceil(edgeIn.maxLgSize+1) val addrBits = log2Ceil(edgeIn.manager.beatBytes) - val stateBits = addrBits + sizeBits + sinkBits + sourceBits // could be 0 + val stateBits = addrBits + sizeBits + sourceBits // could be 0 val a_address = edgeIn.address(in.a.bits) val a_addr_lo = edgeIn.addr_lo(a_address) val a_source = in.a.bits.source - val a_sink = edgeIn.manager.findIdStartFast(a_address) val a_size = edgeIn.size(in.a.bits) val a_isPut = edgeIn.hasData(in.a.bits) val (_, a_last, _) = edgeIn.firstlast(in.a) // Make sure the fields are within the bounds we assumed assert (a_source < UInt(1 << sourceBits)) - assert (a_sink < UInt(1 << sinkBits)) assert (a_size < UInt(1 << sizeBits)) assert (a_addr_lo < UInt(1 << addrBits)) // Carefully pack/unpack fields into the state we send val baseEnd = 0 val (sourceEnd, sourceOff) = (sourceBits + baseEnd, baseEnd) - val (sinkEnd, sinkOff) = (sinkBits + sourceEnd, sourceEnd) - val (sizeEnd, sizeOff) = (sizeBits + sinkEnd, sinkEnd) + val (sizeEnd, sizeOff) = (sizeBits + sourceEnd, sourceEnd) val (addrEnd, addrOff) = (addrBits + sizeEnd, sizeEnd) require (addrEnd == stateBits) - val a_state = (a_source << sourceOff) | (a_sink << sinkOff) | - (a_size << sizeOff) | (a_addr_lo << addrOff) + val a_state = (a_source << sourceOff) | (a_size << sizeOff) | (a_addr_lo << addrOff) val a_id = if (idBits == 0) UInt(0) else a_state val r_state = Wire(UInt(width = stateBits)) val r_source = if (sourceBits > 0) r_state(sourceEnd-1, sourceOff) else UInt(0) - val r_sink = if (sinkBits > 0) r_state(sinkEnd -1, sinkOff) else UInt(0) val r_size = if (sizeBits > 0) r_state(sizeEnd -1, sizeOff) else UInt(0) val r_addr_lo = if (addrBits > 0) r_state(addrEnd -1, addrOff) else UInt(0) val b_state = Wire(UInt(width = stateBits)) val b_source = if (sourceBits > 0) b_state(sourceEnd-1, sourceOff) else UInt(0) - val b_sink = if (sinkBits > 0) b_state(sinkEnd -1, sinkOff) else UInt(0) val b_size = if (sizeBits > 0) b_state(sizeEnd -1, sizeOff) else UInt(0) val b_addr_lo = if (addrBits > 0) b_state(addrEnd -1, addrOff) else UInt(0) @@ -221,8 +213,8 @@ class TLToAXI4(idBits: Int, combinational: Boolean = true) extends LazyModule val r_error = out.r.bits.resp =/= AXI4Parameters.RESP_OKAY val b_error = out_b.bits.resp =/= AXI4Parameters.RESP_OKAY - val r_d = edgeIn.AccessAck(r_addr_lo, r_sink, r_source, r_size, UInt(0), r_error) - val b_d = edgeIn.AccessAck(b_addr_lo, b_sink, b_source, b_size, b_error) + val r_d = edgeIn.AccessAck(r_addr_lo, UInt(0), r_source, r_size, UInt(0), r_error) + val b_d = edgeIn.AccessAck(b_addr_lo, UInt(0), b_source, b_size, b_error) in.d.bits := Mux(r_wins, r_d, b_d) in.d.bits.data := out.r.bits.data // avoid a costly Mux diff --git a/src/main/scala/uncore/tilelink2/Xbar.scala b/src/main/scala/uncore/tilelink2/Xbar.scala index 058353a6..f4c6a82b 100644 --- a/src/main/scala/uncore/tilelink2/Xbar.scala +++ b/src/main/scala/uncore/tilelink2/Xbar.scala @@ -50,13 +50,14 @@ class TLXbar(policy: TLArbiter.Policy = TLArbiter.lowestIndexFirst) extends Lazy }, managerFn = { seq => val fifoIdFactory = relabeler() + val outputIdRanges = mapOutputIds(seq) seq(0).copy( minLatency = seq.map(_.minLatency).min, - managers = (mapOutputIds(seq) zip seq) flatMap { case (range, port) => + endSinkId = outputIdRanges.map(_.end).max, + managers = (outputIdRanges zip seq) flatMap { case (range, port) => require (port.beatBytes == seq(0).beatBytes) val fifoIdMapper = fifoIdFactory() port.managers map { manager => manager.copy( - sinkId = manager.sinkId.shift(range.start), fifoId = manager.fifoId.map(fifoIdMapper(_)) )} }