From c8a76481692cea2f9de1947ce9fa943598666ec0 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 12 Jul 2017 15:03:17 -0700 Subject: [PATCH 1/4] diplomacy: only evaluate a Nexus node's map function once --- src/main/scala/diplomacy/Nodes.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/scala/diplomacy/Nodes.scala b/src/main/scala/diplomacy/Nodes.scala index 1a04d33f..bf895685 100644 --- a/src/main/scala/diplomacy/Nodes.scala +++ b/src/main/scala/diplomacy/Nodes.scala @@ -343,8 +343,8 @@ class MixedNexusNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( require (oStars == 0, s"${name} (a nexus) appears right of a :=* (perhaps you should flip the '*' to :*=?)${lazyModule.line}") (0, 0) } - protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] = Seq.fill(n) { dFn(p) } - protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI] = Seq.fill(n) { uFn(p) } + protected[diplomacy] def mapParamsD(n: Int, p: Seq[DI]): Seq[DO] = { val a = dFn(p); Seq.fill(n)(a) } + protected[diplomacy] def mapParamsU(n: Int, p: Seq[UO]): Seq[UI] = { val a = uFn(p); Seq.fill(n)(a) } } class AdapterNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])( From b363a94480380c0fde9974777ac267d4bd0a4e8e Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 12 Jul 2017 16:19:19 -0700 Subject: [PATCH 2/4] diplomacy: add a new UNCACHEABLE RegionType --- src/main/scala/diplomacy/Parameters.scala | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/scala/diplomacy/Parameters.scala b/src/main/scala/diplomacy/Parameters.scala index c641116c..3521f300 100644 --- a/src/main/scala/diplomacy/Parameters.scala +++ b/src/main/scala/diplomacy/Parameters.scala @@ -6,13 +6,18 @@ import Chisel._ /** Options for memory regions */ object RegionType { - sealed trait T + // Define the 'more relaxed than' ordering + val cases = Seq(CACHED, TRACKED, UNCACHED, UNCACHEABLE, PUT_EFFECTS, GET_EFFECTS) + sealed trait T extends Ordered[T] { + def compare(that: T): Int = cases.indexOf(that) compare cases.indexOf(this) + } + case object CACHED extends T case object TRACKED extends T - case object UNCACHED extends T - case object PUT_EFFECTS extends T + case object UNCACHED extends T // not cached yet, but could be + case object UNCACHEABLE extends T // may spontaneously change contents + case object PUT_EFFECTS extends T // PUT_EFFECTS => UNCACHEABLE case object GET_EFFECTS extends T // GET_EFFECTS => PUT_EFFECTS - val cases = Seq(CACHED, TRACKED, UNCACHED, PUT_EFFECTS, GET_EFFECTS) } // A non-empty half-open range; [start, end) From 09b9d33a9a762b7f5e01b5aa2ee5c059c6bc6d40 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 12 Jul 2017 13:55:31 -0700 Subject: [PATCH 3/4] tilelink: FIFOFixer now has a policy parameter --- src/main/scala/tilelink/FIFOFixer.scala | 89 +++++++++++++++++++------ 1 file changed, 70 insertions(+), 19 deletions(-) diff --git a/src/main/scala/tilelink/FIFOFixer.scala b/src/main/scala/tilelink/FIFOFixer.scala index 9160acb2..40f91e6d 100644 --- a/src/main/scala/tilelink/FIFOFixer.scala +++ b/src/main/scala/tilelink/FIFOFixer.scala @@ -8,11 +8,37 @@ import freechips.rocketchip.config.Parameters import freechips.rocketchip.diplomacy._ import scala.math.max -class TLFIFOFixer(implicit p: Parameters) extends LazyModule +class TLFIFOFixer(policy: TLFIFOFixer.Policy = TLFIFOFixer.all)(implicit p: Parameters) extends LazyModule { + private def fifoMap(seq: Seq[TLManagerParameters]) = { + val (flatManagers, keepManagers) = seq.partition(policy) + // We need to be careful if one flatManager and one keepManager share an existing domain + // Erring on the side of caution, we will also flatten the keepManager in this case + val flatDomains = Set(flatManagers.flatMap(_.fifoId):_*) // => ID 0 + val keepDomains = Set(keepManagers.flatMap(_.fifoId):_*) -- flatDomains // => IDs compacted + // Calculate what the FIFO domains look like after the fixer is applied + val flatMap = flatDomains.map { x => (x, 0) }.toMap + val keepMap = keepDomains.scanLeft((-1,0)) { case ((_,s),x) => (x, s+1) }.toMap + val map = flatMap ++ keepMap + val fixMap = seq.map { m => m.fifoId match { + case None => if (policy(m)) Some(0) else None + case Some(id) => Some(map(id)) // also flattens some who did not ask + } } + // Compress the FIFO domain space of those we are combining + val reMap = flatDomains.scanLeft((-1,-1)) { case ((_,s),x) => (x, s+1) }.toMap + val splatMap = seq.map { m => m.fifoId match { + case None => None + case Some(id) => reMap.lift(id) + } } + (fixMap, splatMap) + } + val node = TLAdapterNode( clientFn = { cp => cp }, - managerFn = { mp => mp.copy(managers = mp.managers.map(m => m.copy(fifoId = Some(0)))) }) + managerFn = { mp => + val (fixMap, _) = fifoMap(mp.managers) + mp.copy(managers = (fixMap zip mp.managers) map { case (id, m) => m.copy(fifoId = id) }) + }) lazy val module = new LazyModuleImp(this) { val io = new Bundle { @@ -21,33 +47,50 @@ class TLFIFOFixer(implicit p: Parameters) extends LazyModule } ((io.in zip io.out) zip (node.edgesIn zip node.edgesOut)) foreach { case ((in, out), (edgeIn, edgeOut)) => - val maxId = edgeOut.manager.managers.flatMap(_.fifoId).foldLeft(0)(max) - val a_id = edgeOut.manager.findFifoIdFast(in.a.bits.address) - val a_nid = a_id === UInt(0) // no id = not FIFO + val (fixMap, splatMap) = fifoMap(edgeOut.manager.managers) + // Do we need to serialize the request to this manager? + // println(s"make FIFO: ${edgeIn.manager.managers.filter(_.fifoId==Some(0)).map(_.name).mkString(", ")}") + // println(s"not FIFO: ${edgeIn.manager.managers.filter(_.fifoId!=Some(0)).map(_.name).mkString(", ")}") + val a_notFIFO = edgeIn.manager.fastProperty(in.a.bits.address, _.fifoId != Some(0), (b:Boolean) => Bool(b)) + // Does this manager have an existing FIFO domain? (don't care about unserialized cases) + val hackExist = ((fixMap zip splatMap) zip edgeOut.manager.managers) flatMap { + case ((f, s), m) => if (f == Some(0)) Some(m.copy(fifoId = s)) else None + } + // println(s"has domain: ${hackExist.filter( _.fifoId.isDefined).map(_.name).mkString(", ")}") + // println(s"no domain: ${hackExist.filter(!_.fifoId.isDefined).map(_.name).mkString(", ")}") + val a_noDomain = edgeOut.manager.copy(managers = hackExist).fastProperty(in.a.bits.address, !_.fifoId.isDefined, (b:Boolean) => Bool(b)) + // What is that domain? (don't care about noDomain cases) + val hackDomain = hackExist.filter(_.fifoId.isDefined) + // println(s"domains: ${hackDomain.groupBy(_.name).mapValues(_.map(_.fifoId))}") + // println("") + val a_id = edgeOut.manager.copy(managers = hackDomain).fastProperty(in.a.bits.address, _.fifoId.get, (id:Int) => UInt(id)) + val maxId = hackDomain.flatMap(_.fifoId).foldLeft(0)(max) + + // Count beats val a_first = edgeIn.first(in.a) val d_first = edgeOut.first(out.d) && out.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 + val flight = RegInit(Vec.fill(edgeIn.client.endSourceId) { Bool(false) }) + when (d_first && in.d.fire()) { flight(in.d.bits.source) := Bool(false) } + when (a_first && in.a.fire()) { flight(in.a.bits.source) := !a_notFIFO } + val stalls = edgeIn.client.clients.filter(c => c.requestFifo && c.sourceId.size > 1).map { c => val a_sel = c.sourceId.contains(in.a.bits.source) - val d_sel = c.sourceId.contains(in.d.bits.source) - val id = RegInit(UInt(0, width = log2Up(maxId+1))) // TODO zero-width - val count = RegInit(UInt(0, width = log2Up(c.sourceId.size+1))) // TODO zero-width + val id = RegEnable(a_id, in.a.fire() && a_sel && !a_notFIFO) + val track = flight.slice(c.sourceId.start, c.sourceId.end) - val a_inc = in.a.fire() && a_first && a_sel - val d_dec = in.d.fire() && d_first && d_sel - count := count + a_inc.asUInt - d_dec.asUInt - when (in.a.fire() && a_sel) { id := a_id } - - a_sel && a_first && count =/= UInt(0) && (a_nid || id =/= a_id) + a_sel && a_first && track.reduce(_ || _) && (a_noDomain || id =/= a_id) } val stall = stalls.foldLeft(Bool(false))(_||_) out.a <> in.a in.d <> out.d - out.a.valid := in.a.valid && !stall - in.a.ready := out.a.ready && !stall + out.a.valid := in.a.valid && (a_notFIFO || !stall) + in.a.ready := out.a.ready && (a_notFIFO || !stall) if (edgeOut.manager.anySupportAcquireB && edgeOut.client.anySupportProbe) { in .b <> out.b @@ -67,11 +110,19 @@ class TLFIFOFixer(implicit p: Parameters) extends LazyModule object TLFIFOFixer { + // Which slaves should have their FIFOness combined? + // NOTE: this transformation is still only applied for masters with requestFifo + type Policy = TLManagerParameters => Boolean + import RegionType._ + + val all: Policy = m => true + val allFIFO: Policy = m => m.fifoId.isDefined + val allUncacheable: Policy = m => m.regionType <= UNCACHEABLE + // applied to the TL source node; y.node := TLFIFOFixer()(x.node) - def apply()(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = { - val fixer = LazyModule(new TLFIFOFixer) + def apply(policy: Policy = all)(x: TLOutwardNode)(implicit p: Parameters, sourceInfo: SourceInfo): TLOutwardNode = { + val fixer = LazyModule(new TLFIFOFixer(policy)) fixer.node := x fixer.node } } - From 4eface8a9e9a3599c4fcb2f096ed581cc5a7d253 Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Wed, 12 Jul 2017 16:20:22 -0700 Subject: [PATCH 4/4] rocket: do not require FIFO order for memory-like regions --- src/main/scala/coreplex/RocketTiles.scala | 6 +++--- src/main/scala/rocket/HellaCache.scala | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/scala/coreplex/RocketTiles.scala b/src/main/scala/coreplex/RocketTiles.scala index fbacc17b..ffe79ef2 100644 --- a/src/main/scala/coreplex/RocketTiles.scala +++ b/src/main/scala/coreplex/RocketTiles.scala @@ -61,7 +61,7 @@ trait HasRocketTiles extends CoreplexRISCVPlatform { case SynchronousCrossing(params) => { val wrapper = LazyModule(new SyncRocketTile(c, i)(pWithExtra)) val buffer = LazyModule(new TLBuffer(params)) - val fixer = LazyModule(new TLFIFOFixer) + val fixer = LazyModule(new TLFIFOFixer(TLFIFOFixer.allUncacheable)) buffer.node :=* wrapper.masterNode fixer.node :=* buffer.node tile_splitter.node :=* fixer.node @@ -79,7 +79,7 @@ trait HasRocketTiles extends CoreplexRISCVPlatform { val wrapper = LazyModule(new AsyncRocketTile(c, i)(pWithExtra)) val sink = LazyModule(new TLAsyncCrossingSink(depth, sync)) val source = LazyModule(new TLAsyncCrossingSource(sync)) - val fixer = LazyModule(new TLFIFOFixer) + val fixer = LazyModule(new TLFIFOFixer(TLFIFOFixer.allUncacheable)) sink.node :=* wrapper.masterNode fixer.node :=* sink.node tile_splitter.node :=* fixer.node @@ -99,7 +99,7 @@ trait HasRocketTiles extends CoreplexRISCVPlatform { val wrapper = LazyModule(new RationalRocketTile(c, i)(pWithExtra)) val sink = LazyModule(new TLRationalCrossingSink(direction)) val source = LazyModule(new TLRationalCrossingSource) - val fixer = LazyModule(new TLFIFOFixer) + val fixer = LazyModule(new TLFIFOFixer(TLFIFOFixer.allUncacheable)) sink.node :=* wrapper.masterNode fixer.node :=* sink.node tile_splitter.node :=* fixer.node diff --git a/src/main/scala/rocket/HellaCache.scala b/src/main/scala/rocket/HellaCache.scala index 8adc2dd8..e7d506a8 100644 --- a/src/main/scala/rocket/HellaCache.scala +++ b/src/main/scala/rocket/HellaCache.scala @@ -183,8 +183,10 @@ class HellaCacheModule(outer: HellaCache) extends LazyModuleImp(outer) val io = new HellaCacheBundle(outer) val tl_out = io.mem(0) - // IOMSHRs must be FIFO - edge.manager.requireFifo() + // IOMSHRs must be FIFO for all regions with effects + edge.manager.managers.foreach { m => + require (m.fifoId == Some(0) || !TLFIFOFixer.allUncacheable(m)) + } } object HellaCache {