From cd0653f95c6a597e93b124b0d8530a331d062ddf Mon Sep 17 00:00:00 2001 From: Henry Cook Date: Wed, 6 May 2020 18:39:44 -0700 Subject: [PATCH 1/7] tilelink: AddressAdjuster can be supplied localBaseAddressDefault --- src/main/scala/tilelink/AddressAdjuster.scala | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/main/scala/tilelink/AddressAdjuster.scala b/src/main/scala/tilelink/AddressAdjuster.scala index f51f4fef740..7b3d18c06a5 100644 --- a/src/main/scala/tilelink/AddressAdjuster.scala +++ b/src/main/scala/tilelink/AddressAdjuster.scala @@ -7,8 +7,11 @@ import chisel3.util._ import freechips.rocketchip.config._ import freechips.rocketchip.diplomacy._ -// forceLocal -> used to ensure special devices (like debug) remain reacheable at chip_id=0 even if in params.region -class AddressAdjuster(val params: ReplicatedRegion, val forceLocal: Seq[AddressSet] = Nil)(implicit p: Parameters) extends LazyModule { +class AddressAdjuster( + val params: ReplicatedRegion, // only devices in this region get adjusted + val forceLocal: Seq[AddressSet] = Nil, // ensure special devices (e.g. debug) remain reacheable at id=0 even if in params.region + val localBaseAddressDefault: Option[BigInt] = None // default local base address used for reporting manager address metadata + )(implicit p: Parameters) extends LazyModule { val mask = params.replicationMask // Which bits are in the mask? val bits = AddressSet.enumerateBits(mask) @@ -16,9 +19,15 @@ class AddressAdjuster(val params: ReplicatedRegion, val forceLocal: Seq[AddressS private def prefix0(region: Seq[AddressSet]): Seq[AddressSet] = { region.flatMap { _.intersect(params.local) } } - private def prefixNot0(region: Seq[AddressSet]): Seq[AddressSet] = { - region.flatMap { _.subtract(params.local) } + // Default region is used to display address map metadata which corresponds to the expected default choice of prefix value + private val defaultRegion: AddressSet = params.local.copy(base = params.local.base + localBaseAddressDefault.getOrElse(0)) + private def prefixDefault(region: Seq[AddressSet]): Seq[AddressSet] = { + region.flatMap { _.intersect(defaultRegion) } } + private def prefixNotDefault(region: Seq[AddressSet]): Seq[AddressSet] = { + region.flatMap { _.subtract(defaultRegion) } + } + // forceLocal better only go one place (the low index) forceLocal.foreach { as => require((as.max & mask) == 0) } @@ -167,12 +176,13 @@ class AddressAdjuster(val params: ReplicatedRegion, val forceLocal: Seq[AddressS val r = container.get requireContainerSupport(l, r) - // The address can be dynamically adjusted to anywhere in the adjustable region, but we take the 0 setting as default for DTS output + // The local address can be dynamically adjusted to any masked location in the adjustable region. + // We can report a particular local base address for DTS output, or default to reporting the 0th region. // Any address space holes in the local adjustable region will be plugged with the error device. - // All other PMAs are replaced with the capabilities of the remote path, since that's all we can know statically. - // Capabilities supported by the remote but not the local will result in dynamic re-reouting to the error device. + // All device PMAs are replaced with the capabilities of the remote path, since that's all we can know statically. + // Capabilities supported by the remote but not the local device will result in dynamic re-rerouting to the error device. l.v1copy( - address = AddressSet.unify(prefix0(l.address) ++ (if (Some(l) == errorDev) holes else Nil)), + address = AddressSet.unify(prefixDefault(l.address ++ (if (Some(l) == errorDev) holes else Nil))), regionType = r.regionType, executable = r.executable, supportsAcquireT = r.supportsAcquireT, @@ -192,7 +202,7 @@ class AddressAdjuster(val params: ReplicatedRegion, val forceLocal: Seq[AddressS // Actually rewrite the PMAs for the adjustable remote region too, to account for the differing FIFO domains under the mask val newRemotes = adjustableRemoteManagers.map { r => r.v1copy( - address = prefixNot0(r.address), + address = prefixNotDefault(r.address), fifoId = Some(0)) } From 10618970b8bbdca0444c19f251e50dc38ca851e9 Mon Sep 17 00:00:00 2001 From: Henry Cook Date: Wed, 6 May 2020 19:13:51 -0700 Subject: [PATCH 2/7] tilelink: plumb localBaseAddressDefault through AddressAdjusterWrapper --- src/main/scala/tilelink/BusWrapper.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/scala/tilelink/BusWrapper.scala b/src/main/scala/tilelink/BusWrapper.scala index 56648d1e7aa..a2d12516251 100644 --- a/src/main/scala/tilelink/BusWrapper.scala +++ b/src/main/scala/tilelink/BusWrapper.scala @@ -356,7 +356,8 @@ case class AddressAdjusterWrapperParams( blockBytes: Int, beatBytes: Int, replication: Option[ReplicatedRegion], - forceLocal: Seq[AddressSet] = Nil + forceLocal: Seq[AddressSet] = Nil, + localBaseAddressDefault: Option[BigInt] = None ) extends HasTLBusParams with TLBusWrapperInstantiationLike @@ -371,7 +372,7 @@ case class AddressAdjusterWrapperParams( } class AddressAdjusterWrapper(params: AddressAdjusterWrapperParams, name: String)(implicit p: Parameters) extends TLBusWrapper(params, name) { - private val address_adjuster = params.replication.map { r => LazyModule(new AddressAdjuster(r, params.forceLocal)) } + private val address_adjuster = params.replication.map { r => LazyModule(new AddressAdjuster(r, params.forceLocal, params.localBaseAddressDefault)) } private val viewNode = TLIdentityNode() val inwardNode: TLInwardNode = address_adjuster.map(_.node :*=* viewNode).getOrElse(viewNode) def outwardNode: TLOutwardNode = address_adjuster.map(_.node).getOrElse(viewNode) From 276dbd00d121a200b7306e5bce1b0a4066c56411 Mon Sep 17 00:00:00 2001 From: Henry Cook Date: Fri, 15 May 2020 17:04:11 -0700 Subject: [PATCH 3/7] tilelink: address adjust has liberal use of :<= to deal with divergent user bits --- src/main/scala/tilelink/AddressAdjuster.scala | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/scala/tilelink/AddressAdjuster.scala b/src/main/scala/tilelink/AddressAdjuster.scala index 7b3d18c06a5..9999734eda0 100644 --- a/src/main/scala/tilelink/AddressAdjuster.scala +++ b/src/main/scala/tilelink/AddressAdjuster.scala @@ -258,8 +258,8 @@ class AddressAdjuster( parent.a.ready := Mux(a_local, local.a.ready, remote.a.ready) && !a_stall local .a.valid := parent.a.valid && a_local && !a_stall remote.a.valid := parent.a.valid && !a_local && !a_stall - local .a.bits := parent.a.bits - remote.a.bits := parent.a.bits + local .a.bits :<= parent.a.bits + remote.a.bits :<= parent.a.bits // Count beats val a_first = parentEdge.first(parent.a) @@ -321,11 +321,11 @@ class AddressAdjuster( val local_d = Wire(chiselTypeOf(parent.d)) // type-cast, because 'sink' width differs local.d.ready := local_d.ready local_d.valid := local.d.valid - local_d.bits := local.d.bits + local_d.bits :<= local.d.bits val remote_d = Wire(chiselTypeOf(parent.d)) remote.d.ready := remote_d.ready remote_d.valid := remote.d.valid - remote_d.bits := remote.d.bits + remote_d.bits :<= remote.d.bits remote_d.bits.sink := remote.d.bits.sink +& sink_threshold TLArbiter.robin(parentEdge, parent.d, local_d, remote_d) @@ -340,16 +340,16 @@ class AddressAdjuster( parent.c.ready := Mux(c_local, local.c.ready, remote.c.ready) local .c.valid := parent.c.valid && c_local remote.c.valid := parent.c.valid && !c_local - local .c.bits := parent.c.bits - remote.c.bits := parent.c.bits + local .c.bits :<= parent.c.bits + remote.c.bits :<= parent.c.bits // Route E by sink val e_local = parent.e.bits.sink < sink_threshold parent.e.ready := Mux(e_local, local.e.ready, remote.e.ready) local .e.valid := parent.e.valid && e_local remote.e.valid := parent.e.valid && !e_local - local .e.bits := parent.e.bits - remote.e.bits := parent.e.bits + local .e.bits :<= parent.e.bits + remote.e.bits :<= parent.e.bits remote.e.bits.sink := parent.e.bits.sink - sink_threshold } } From ccfd1e3483accfe2fad5332e2fcb2a98da78d9a9 Mon Sep 17 00:00:00 2001 From: Henry Cook Date: Mon, 18 May 2020 09:46:43 -0700 Subject: [PATCH 4/7] tilelink: AddressAdjuster has more/more verbose requires --- src/main/scala/tilelink/AddressAdjuster.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/tilelink/AddressAdjuster.scala b/src/main/scala/tilelink/AddressAdjuster.scala index 9999734eda0..2da9decf21c 100644 --- a/src/main/scala/tilelink/AddressAdjuster.scala +++ b/src/main/scala/tilelink/AddressAdjuster.scala @@ -28,8 +28,8 @@ class AddressAdjuster( region.flatMap { _.subtract(defaultRegion) } } - // forceLocal better only go one place (the low index) - forceLocal.foreach { as => require((as.max & mask) == 0) } + localBaseAddressDefault.foreach { x => require((x & ~mask) == 0, s"localBaseAddressDefault $localBaseAddressDefault was not aligned to region") } + forceLocal.foreach { as => require((as.max & mask) == 0, s"forceLocal $forceLocal must be contained within the lowest index region") } // Address Adjustment requires many things about the downstream devices, captured here as helper functions: From 6beb45b8f2bd56d09a6c4a828ec89a8d8b9a9b3f Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 18 May 2020 12:20:54 -0700 Subject: [PATCH 5/7] AddressAdjuster: only FIFO fix the replicated region If you have fixed slaves on local/remote side, do not require FIFO uniformity or flatten their fifoIds. --- src/main/scala/tilelink/AddressAdjuster.scala | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/main/scala/tilelink/AddressAdjuster.scala b/src/main/scala/tilelink/AddressAdjuster.scala index 2da9decf21c..84a205c87d0 100644 --- a/src/main/scala/tilelink/AddressAdjuster.scala +++ b/src/main/scala/tilelink/AddressAdjuster.scala @@ -128,10 +128,6 @@ class AddressAdjuster( val local = mp(0) val remote = mp(1) - // Confirm that the two manager paths have homogeneous FIFO ids - requireFifoHomogeneity(local.managers) - requireFifoHomogeneity(remote.managers) - // Subdivide the managers into four cases: (adjustable vs fixed) x (local vs remote) val adjustableLocalManagers = local.managers.filter(m => isDeviceContainedBy(Seq(params.region), m)) val fixedLocalManagers = local.managers.filter(m => !isDeviceContainedBy(Seq(params.region), m)) @@ -146,6 +142,10 @@ class AddressAdjuster( if (subtraction.isEmpty) None else Some(m.v1copy(address = subtraction)) } + // Confirm that the two manager paths have homogeneous FIFO ids + requireFifoHomogeneity(adjustableLocalManagers) + requireFifoHomogeneity(adjustableRemoteManagers) + if (false) { printManagers("Adjustable Local", adjustableLocalManagers) printManagers("Adjustable Remote",adjustableRemoteManagers) @@ -206,11 +206,17 @@ class AddressAdjuster( fifoId = Some(0)) } + // Relable the FIFO domains for certain manager subsets + val fifoIdFactory = TLXbar.relabeler() + def relabelFifo(managers: Seq[TLSlaveParameters]): Seq[TLSlaveParameters] = { + val fifoIdMapper = fifoIdFactory() + managers.map(m => m.v1copy(fifoId = m.fifoId.map(fifoIdMapper(_)))) + } + val newManagerList = - newLocals ++ - newRemotes ++ - fixedLocalManagers ++ - fixedRemoteManagers + relabelFifo(newLocals ++ newRemotes) ++ + relabelFifo(fixedLocalManagers) ++ + relabelFifo(fixedRemoteManagers) Seq(local.v1copy( managers = newManagerList, @@ -247,14 +253,16 @@ class AddressAdjuster( def containsAddress(region: Seq[AddressSet], addr: UInt): Bool = region.foldLeft(false.B)(_ || _.contains(addr)) val totalContainment = parentEdge.slave.slaves.forall(_.address.forall(params.region contains _)) def isAdjustable(addr: UInt) = params.region.contains(addr) || totalContainment.B - def isDynamicallyLocal(addr: UInt) = local_prefix === (addr & mask.U) || containsAddress(forceLocal, addr) + def isDynamicallyLocal(addr: UInt) = (local_prefix & mask.U) === (addr & mask.U) || containsAddress(forceLocal, addr) val staticLocal = AddressSet.unify(fixedLocalManagers.flatMap(_.address)) def isStaticallyLocal(addr: UInt) = containsAddress(staticLocal, addr) def routeLocal(addr: UInt): Bool = Mux(isAdjustable(addr), isDynamicallyLocal(addr), isStaticallyLocal(addr)) // Route A by address, but reroute unsupported operations val a_stall = Wire(Bool()) - val a_local = routeLocal(parent.a.bits.address) + val a_adjustable = isAdjustable(parent.a.bits.address) + val a_dynamic_local = isDynamicallyLocal(parent.a.bits.address) + val a_local = Mux(a_adjustable, a_dynamic_local, isStaticallyLocal(parent.a.bits.address)) parent.a.ready := Mux(a_local, local.a.ready, remote.a.ready) && !a_stall local .a.valid := parent.a.valid && a_local && !a_stall remote.a.valid := parent.a.valid && !a_local && !a_stall @@ -267,19 +275,20 @@ class AddressAdjuster( // Keep one bit for each source recording if there is an outstanding request that must be made FIFO // Sources unused in the stall signal calculation should be pruned by DCE + // Only fix-up order when crossing local/remote boundaries val flight = RegInit(VecInit(Seq.fill(parentEdge.client.endSourceId) { false.B })) - when (a_first && parent.a.fire()) { flight(parent.a.bits.source) := true.B } - when (d_first && parent.d.fire()) { flight(parent.d.bits.source) := false.B } + when (a_first && parent.a.fire() && a_adjustable) { flight(parent.a.bits.source) := true.B } + when (d_first && parent.d.fire()) { flight(parent.d.bits.source) := false.B } val stalls = parentEdge.client.clients.filter(c => c.requestFifo && c.sourceId.size > 1).map { c => val a_sel = c.sourceId.contains(parent.a.bits.source) - val local = RegEnable(a_local, parent.a.fire() && a_sel) + val local = RegEnable(a_dynamic_local, parent.a.fire() && a_sel) val track = flight.slice(c.sourceId.start, c.sourceId.end) - a_sel && a_first && track.reduce(_ || _) && (local =/= a_local) + a_sel && a_first && track.reduce(_ || _) && (local =/= a_dynamic_local) } - a_stall := stalls.foldLeft(false.B)(_||_) + a_stall := a_adjustable && stalls.foldLeft(false.B)(_||_) val (allSame, holes) = sameSupport(adjustableLocalManagers, adjustableRemoteManagers) From 3ba61749471bc8fe17aa30af40b2ca341b6ffd12 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 18 May 2020 12:42:40 -0700 Subject: [PATCH 6/7] AddressAdjuster: make it possible to have no replicated order requirements In that situation, there is no need to track transactions. --- src/main/scala/tilelink/AddressAdjuster.scala | 51 +++++++++++-------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/src/main/scala/tilelink/AddressAdjuster.scala b/src/main/scala/tilelink/AddressAdjuster.scala index 84a205c87d0..bac37e417b6 100644 --- a/src/main/scala/tilelink/AddressAdjuster.scala +++ b/src/main/scala/tilelink/AddressAdjuster.scala @@ -10,7 +10,8 @@ import freechips.rocketchip.diplomacy._ class AddressAdjuster( val params: ReplicatedRegion, // only devices in this region get adjusted val forceLocal: Seq[AddressSet] = Nil, // ensure special devices (e.g. debug) remain reacheable at id=0 even if in params.region - val localBaseAddressDefault: Option[BigInt] = None // default local base address used for reporting manager address metadata + val localBaseAddressDefault: Option[BigInt] = None, // default local base address used for reporting manager address metadata + val ordered: Boolean = true // the replicated region should present with FIFO ordering )(implicit p: Parameters) extends LazyModule { val mask = params.replicationMask // Which bits are in the mask? @@ -142,9 +143,11 @@ class AddressAdjuster( if (subtraction.isEmpty) None else Some(m.v1copy(address = subtraction)) } - // Confirm that the two manager paths have homogeneous FIFO ids - requireFifoHomogeneity(adjustableLocalManagers) - requireFifoHomogeneity(adjustableRemoteManagers) + if (ordered) { + // Confirm that the two manager paths have homogeneous FIFO ids + requireFifoHomogeneity(adjustableLocalManagers) + requireFifoHomogeneity(adjustableRemoteManagers) + } if (false) { printManagers("Adjustable Local", adjustableLocalManagers) @@ -196,14 +199,14 @@ class AddressAdjuster( mayDenyGet = r.mayDenyGet, mayDenyPut = r.mayDenyPut, alwaysGrantsT = r.alwaysGrantsT, - fifoId = Some(0)) + fifoId = if (ordered) Some(0) else None) } // Actually rewrite the PMAs for the adjustable remote region too, to account for the differing FIFO domains under the mask val newRemotes = adjustableRemoteManagers.map { r => r.v1copy( address = prefixNotDefault(r.address), - fifoId = Some(0)) + fifoId = if (ordered) Some(0) else None) } // Relable the FIFO domains for certain manager subsets @@ -269,26 +272,30 @@ class AddressAdjuster( local .a.bits :<= parent.a.bits remote.a.bits :<= parent.a.bits - // Count beats - val a_first = parentEdge.first(parent.a) - val d_first = parentEdge.first(parent.d) && parent.d.bits.opcode =/= TLMessages.ReleaseAck + if (ordered) { + // Count beats + val a_first = parentEdge.first(parent.a) + val d_first = parentEdge.first(parent.d) && parent.d.bits.opcode =/= TLMessages.ReleaseAck - // Keep one bit for each source recording if there is an outstanding request that must be made FIFO - // Sources unused in the stall signal calculation should be pruned by DCE - // Only fix-up order when crossing local/remote boundaries - val flight = RegInit(VecInit(Seq.fill(parentEdge.client.endSourceId) { false.B })) - when (a_first && parent.a.fire() && a_adjustable) { flight(parent.a.bits.source) := true.B } - when (d_first && parent.d.fire()) { flight(parent.d.bits.source) := false.B } + // Keep one bit for each source recording if there is an outstanding request that must be made FIFO + // Sources unused in the stall signal calculation should be pruned by DCE + // Only fix-up order when crossing local/remote boundaries + val flight = RegInit(VecInit(Seq.fill(parentEdge.client.endSourceId) { false.B })) + when (a_first && parent.a.fire() && a_adjustable) { flight(parent.a.bits.source) := true.B } + when (d_first && parent.d.fire()) { flight(parent.d.bits.source) := false.B } - val stalls = parentEdge.client.clients.filter(c => c.requestFifo && c.sourceId.size > 1).map { c => - val a_sel = c.sourceId.contains(parent.a.bits.source) - val local = RegEnable(a_dynamic_local, parent.a.fire() && a_sel) - val track = flight.slice(c.sourceId.start, c.sourceId.end) + val stalls = parentEdge.client.clients.filter(c => c.requestFifo && c.sourceId.size > 1).map { c => + val a_sel = c.sourceId.contains(parent.a.bits.source) + val local = RegEnable(a_dynamic_local, parent.a.fire() && a_sel) + val track = flight.slice(c.sourceId.start, c.sourceId.end) - a_sel && a_first && track.reduce(_ || _) && (local =/= a_dynamic_local) - } + a_sel && a_first && track.reduce(_ || _) && (local =/= a_dynamic_local) + } - a_stall := a_adjustable && stalls.foldLeft(false.B)(_||_) + a_stall := a_adjustable && stalls.foldLeft(false.B)(_||_) + } else { + a_stall := false.B + } val (allSame, holes) = sameSupport(adjustableLocalManagers, adjustableRemoteManagers) From 35249bc8e92dd43c92ac7e234c1ba9debfd9e1f4 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Mon, 18 May 2020 12:43:51 -0700 Subject: [PATCH 7/7] AddressAdjusterWrapper: add back a FIFOFixer for fixed local/remote slaves --- src/main/scala/tilelink/BusWrapper.scala | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/scala/tilelink/BusWrapper.scala b/src/main/scala/tilelink/BusWrapper.scala index a2d12516251..875ba6ac982 100644 --- a/src/main/scala/tilelink/BusWrapper.scala +++ b/src/main/scala/tilelink/BusWrapper.scala @@ -357,7 +357,9 @@ case class AddressAdjusterWrapperParams( beatBytes: Int, replication: Option[ReplicatedRegion], forceLocal: Seq[AddressSet] = Nil, - localBaseAddressDefault: Option[BigInt] = None + localBaseAddressDefault: Option[BigInt] = None, + policy: TLFIFOFixer.Policy = TLFIFOFixer.allVolatile, + ordered: Boolean = true ) extends HasTLBusParams with TLBusWrapperInstantiationLike @@ -372,9 +374,9 @@ case class AddressAdjusterWrapperParams( } class AddressAdjusterWrapper(params: AddressAdjusterWrapperParams, name: String)(implicit p: Parameters) extends TLBusWrapper(params, name) { - private val address_adjuster = params.replication.map { r => LazyModule(new AddressAdjuster(r, params.forceLocal, params.localBaseAddressDefault)) } + private val address_adjuster = params.replication.map { r => LazyModule(new AddressAdjuster(r, params.forceLocal, params.localBaseAddressDefault, params.ordered)) } private val viewNode = TLIdentityNode() - val inwardNode: TLInwardNode = address_adjuster.map(_.node :*=* viewNode).getOrElse(viewNode) + val inwardNode: TLInwardNode = address_adjuster.map(_.node :*=* TLFIFOFixer(params.policy) :*=* viewNode).getOrElse(viewNode) def outwardNode: TLOutwardNode = address_adjuster.map(_.node).getOrElse(viewNode) def busView: TLEdge = viewNode.edges.in.head val prefixNode = address_adjuster.map(_.prefix)