diplomacy: place Monitors inside LazyModules sinks
We used to place Monitors at the point of the ':='. This was problematic because the clock domain might be wrong. Thus, we needed to shove Monitors a lot. Furthermore, now that we have cross-module ':=', you might not even have access to the wires at the point where ':=' is invoked.
This commit is contained in:
		| @@ -1,10 +0,0 @@ | |||||||
| // See LICENSE.SiFive for license details. |  | ||||||
|  |  | ||||||
| package freechips.rocketchip.diplomacy |  | ||||||
|  |  | ||||||
| import chisel3.internal.sourceinfo.{SourceInfo, SourceLine} |  | ||||||
| import freechips.rocketchip.config.Parameters |  | ||||||
|  |  | ||||||
| abstract class MonitorBase(implicit val sourceInfo: SourceInfo, p: Parameters) extends LazyModule()(p) { |  | ||||||
|   override val module: LazyModuleImp |  | ||||||
| } |  | ||||||
| @@ -36,12 +36,9 @@ trait InwardNodeImp[DI, UI, EI, BI <: Data] | |||||||
| { | { | ||||||
|   def edgeI(pd: DI, pu: UI, p: Parameters, sourceInfo: SourceInfo): EI |   def edgeI(pd: DI, pu: UI, p: Parameters, sourceInfo: SourceInfo): EI | ||||||
|   def bundleI(ei: EI): BI |   def bundleI(ei: EI): BI | ||||||
|  |   def monitor(bundle: BI, edge: EI) {} | ||||||
|   def colour: String |   def colour: String | ||||||
|   def reverse: Boolean = false |   def reverse: Boolean = false | ||||||
|   def connect(edges: () => Seq[EI], bundles: () => Seq[(BI, BI)], enableMonitoring: Boolean) |  | ||||||
|               (implicit p: Parameters, sourceInfo: SourceInfo): (Option[MonitorBase], () => Unit) = { |  | ||||||
|     (None, () => bundles().foreach { case (i, o) => i <> o }) |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // optional methods to track node graph |   // optional methods to track node graph | ||||||
|   def mixI(pu: UI, node: InwardNode[DI, UI, BI]): UI = pu // insert node into parameters |   def mixI(pu: UI, node: InwardNode[DI, UI, BI]): UI = pu // insert node into parameters | ||||||
| @@ -104,14 +101,10 @@ case class NodeHandle[DI, UI, BI <: Data, DO, UO, BO <: Data] | |||||||
| trait InwardNodeHandle[DI, UI, BI <: Data] | trait InwardNodeHandle[DI, UI, BI <: Data] | ||||||
| { | { | ||||||
|   protected[diplomacy] val inward: InwardNode[DI, UI, BI] |   protected[diplomacy] val inward: InwardNode[DI, UI, BI] | ||||||
|   def := (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): Option[MonitorBase] = |   def := (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) { inward.:=(h)(p, sourceInfo) } | ||||||
|     inward.:=(h)(p, sourceInfo) |   def :*= (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) { inward.:*=(h)(p, sourceInfo) } | ||||||
|   def :*= (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): Option[MonitorBase] = |   def :=* (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) { inward.:=*(h)(p, sourceInfo) } | ||||||
|     inward.:*=(h)(p, sourceInfo) |   def :=? (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) { inward.:=?(h)(p, sourceInfo) } | ||||||
|   def :=* (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): Option[MonitorBase] = |  | ||||||
|     inward.:=*(h)(p, sourceInfo) |  | ||||||
|   def :=? (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): Option[MonitorBase] = |  | ||||||
|     inward.:=?(h)(p, sourceInfo) |  | ||||||
| } | } | ||||||
|  |  | ||||||
| sealed trait NodeBinding | sealed trait NodeBinding | ||||||
| @@ -267,13 +260,7 @@ sealed abstract class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( | |||||||
|       data   = bundleIn(i)) |       data   = bundleIn(i)) | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Used by LazyModules.module.instantiate |  | ||||||
|   private var bundlesSafeNow = false |   private var bundlesSafeNow = false | ||||||
|   protected[diplomacy] def instantiate() = { |  | ||||||
|     bundlesSafeNow = true |  | ||||||
|     danglesOut ++ danglesIn |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // Accessors to the result of negotiation to be used in LazyModuleImp: |   // Accessors to the result of negotiation to be used in LazyModuleImp: | ||||||
|   def out: Seq[(BO, EO)] = { |   def out: Seq[(BO, EO)] = { | ||||||
|     require(bundlesSafeNow, s"${name}.out should only be called from the context of its module implementation") |     require(bundlesSafeNow, s"${name}.out should only be called from the context of its module implementation") | ||||||
| @@ -284,9 +271,19 @@ sealed abstract class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( | |||||||
|     bundleIn zip edgesIn |     bundleIn zip edgesIn | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   // Used by LazyModules.module.instantiate | ||||||
|  |   protected val identity = false | ||||||
|  |   protected[diplomacy] def instantiate() = { | ||||||
|  |     bundlesSafeNow = true | ||||||
|  |     if (!identity) { | ||||||
|  |       (iPorts zip in) foreach { | ||||||
|  |         case ((_, _, p, _), (b, e)) => if (p(MonitorsEnabled)) inner.monitor(b, e) | ||||||
|  |     } } | ||||||
|  |     danglesOut ++ danglesIn | ||||||
|  |   } | ||||||
|  |  | ||||||
|   // connects the outward part of a node with the inward part of this node |   // connects the outward part of a node with the inward part of this node | ||||||
|   private def bind(h: OutwardNodeHandle[DI, UI, BI], binding: NodeBinding) |   private def bind(h: OutwardNodeHandle[DI, UI, BI], binding: NodeBinding)(implicit p: Parameters, sourceInfo: SourceInfo) { | ||||||
|                   (implicit p: Parameters, sourceInfo: SourceInfo): Option[MonitorBase] = { |  | ||||||
|     val x = this // x := y |     val x = this // x := y | ||||||
|     val y = h.outward |     val y = h.outward | ||||||
|     val info = sourceLine(sourceInfo, " at ", "") |     val info = sourceLine(sourceInfo, " at ", "") | ||||||
| @@ -298,13 +295,12 @@ sealed abstract class MixedNode[DI, UI, EI, BI <: Data, DO, UO, EO, BO <: Data]( | |||||||
|       case BIND_STAR  => BIND_QUERY |       case BIND_STAR  => BIND_QUERY | ||||||
|       case BIND_QUERY => BIND_STAR }) |       case BIND_QUERY => BIND_STAR }) | ||||||
|     x.iPush(o, y, binding) |     x.iPush(o, y, binding) | ||||||
|     None // !!! create monitors |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   override def :=  (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): Option[MonitorBase] = bind(h, BIND_ONCE) |   override def :=  (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) = bind(h, BIND_ONCE) | ||||||
|   override def :*= (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): Option[MonitorBase] = bind(h, BIND_STAR) |   override def :*= (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) = bind(h, BIND_STAR) | ||||||
|   override def :=* (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): Option[MonitorBase] = bind(h, BIND_QUERY) |   override def :=* (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) = bind(h, BIND_QUERY) | ||||||
|   override def :=? (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo): Option[MonitorBase] = { |   override def :=? (h: OutwardNodeHandle[DI, UI, BI])(implicit p: Parameters, sourceInfo: SourceInfo) = { | ||||||
|     p(CardinalityInferenceDirectionKey) match { |     p(CardinalityInferenceDirectionKey) match { | ||||||
|       case CardinalityInferenceDirection.SOURCE_TO_SINK => this :=* h |       case CardinalityInferenceDirection.SOURCE_TO_SINK => this :=* h | ||||||
|       case CardinalityInferenceDirection.SINK_TO_SOURCE => this :*= h |       case CardinalityInferenceDirection.SINK_TO_SOURCE => this :*= h | ||||||
| @@ -378,6 +374,7 @@ class AdapterNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])( | |||||||
| class IdentityNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])()(implicit valName: ValName) | class IdentityNode[D, U, EO, EI, B <: Data](imp: NodeImp[D, U, EO, EI, B])()(implicit valName: ValName) | ||||||
|   extends AdapterNode(imp)({ s => s }, { s => s }) |   extends AdapterNode(imp)({ s => s }, { s => s }) | ||||||
| { | { | ||||||
|  |   protected override val identity = true | ||||||
|   override protected[diplomacy] def instantiate() = { |   override protected[diplomacy] def instantiate() = { | ||||||
|     val dangles = super.instantiate() |     val dangles = super.instantiate() | ||||||
|     (out zip in) map { case ((o, _), (i, _)) => o <> i } |     (out zip in) map { case ((o, _), (i, _)) => o <> i } | ||||||
|   | |||||||
| @@ -94,9 +94,9 @@ class TLAsyncCrossing(depth: Int = 8, sync: Int = 3)(implicit p: Parameters) ext | |||||||
|   val source = LazyModule(new TLAsyncCrossingSource(sync)) |   val source = LazyModule(new TLAsyncCrossingSource(sync)) | ||||||
|   val sink = LazyModule(new TLAsyncCrossingSink(depth, sync)) |   val sink = LazyModule(new TLAsyncCrossingSink(depth, sync)) | ||||||
|  |  | ||||||
|   val _    = (sink.node := source.node) // no monitor |   sink.node := source.node | ||||||
|   val in   = (source.node := nodeIn) |   source.node := nodeIn | ||||||
|   val out  = (nodeOut := sink.node) |   nodeOut := sink.node | ||||||
|  |  | ||||||
|   lazy val module = new LazyModuleImp(this) { |   lazy val module = new LazyModuleImp(this) { | ||||||
|     val io = IO(new Bundle { |     val io = IO(new Bundle { | ||||||
| @@ -108,17 +108,8 @@ class TLAsyncCrossing(depth: Int = 8, sync: Int = 3)(implicit p: Parameters) ext | |||||||
|  |  | ||||||
|     source.module.clock := io.in_clock |     source.module.clock := io.in_clock | ||||||
|     source.module.reset := io.in_reset |     source.module.reset := io.in_reset | ||||||
|     in.foreach { lm => |  | ||||||
|       lm.module.clock := io.in_clock |  | ||||||
|       lm.module.reset := io.in_reset |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     sink.module.clock := io.out_clock |     sink.module.clock := io.out_clock | ||||||
|     sink.module.reset := io.out_reset |     sink.module.reset := io.out_reset | ||||||
|     out.foreach { lm => |  | ||||||
|       lm.module.clock := io.out_clock |  | ||||||
|       lm.module.reset := io.out_reset |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -133,7 +124,7 @@ class TLRAMAsyncCrossing(txns: Int)(implicit p: Parameters) extends LazyModule { | |||||||
|  |  | ||||||
|   model.node := fuzz.node |   model.node := fuzz.node | ||||||
|   cross.node := TLFragmenter(4, 256)(TLDelayer(0.1)(model.node)) |   cross.node := TLFragmenter(4, 256)(TLDelayer(0.1)(model.node)) | ||||||
|   val monitor = (ram.node := cross.node) |   ram.node := cross.node | ||||||
|  |  | ||||||
|   lazy val module = new LazyModuleImp(this) with UnitTestModule { |   lazy val module = new LazyModuleImp(this) with UnitTestModule { | ||||||
|     io.finished := fuzz.module.io.finished |     io.finished := fuzz.module.io.finished | ||||||
| @@ -147,12 +138,6 @@ class TLRAMAsyncCrossing(txns: Int)(implicit p: Parameters) extends LazyModule { | |||||||
|     cross.module.io.in_reset := reset |     cross.module.io.in_reset := reset | ||||||
|     cross.module.io.out_clock := clocks.io.clock_out |     cross.module.io.out_clock := clocks.io.clock_out | ||||||
|     cross.module.io.out_reset := reset |     cross.module.io.out_reset := reset | ||||||
|  |  | ||||||
|     // Push the Monitor into the right clock domain |  | ||||||
|     monitor.foreach { m => |  | ||||||
|       m.module.clock := clocks.io.clock_out |  | ||||||
|       m.module.reset := reset |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -240,7 +240,7 @@ class TLFuzzRAM(txns: Int)(implicit p: Parameters) extends LazyModule | |||||||
|   ram2.node := TLFragmenter(16, 256)(xbar2.node) |   ram2.node := TLFragmenter(16, 256)(xbar2.node) | ||||||
|   xbar.node := TLWidthWidget(16)(TLHintHandler()(xbar2.node)) |   xbar.node := TLWidthWidget(16)(TLHintHandler()(xbar2.node)) | ||||||
|   cross.node := TLFragmenter(4, 256)(TLBuffer()(xbar.node)) |   cross.node := TLFragmenter(4, 256)(TLBuffer()(xbar.node)) | ||||||
|   val monitor = (ram.node := cross.node) |   ram.node := cross.node | ||||||
|   gpio.node := TLFragmenter(4, 32)(TLBuffer()(xbar.node)) |   gpio.node := TLFragmenter(4, 32)(TLBuffer()(xbar.node)) | ||||||
|  |  | ||||||
|   lazy val module = new LazyModuleImp(this) with UnitTestModule { |   lazy val module = new LazyModuleImp(this) with UnitTestModule { | ||||||
| @@ -255,12 +255,6 @@ class TLFuzzRAM(txns: Int)(implicit p: Parameters) extends LazyModule | |||||||
|     cross.module.io.in_reset := reset |     cross.module.io.in_reset := reset | ||||||
|     cross.module.io.out_clock := clocks.io.clock_out |     cross.module.io.out_clock := clocks.io.clock_out | ||||||
|     cross.module.io.out_reset := reset |     cross.module.io.out_reset := reset | ||||||
|  |  | ||||||
|     // Push the Monitor into the right clock domain |  | ||||||
|     monitor.foreach { m => |  | ||||||
|       m.module.clock := clocks.io.clock_out |  | ||||||
|       m.module.reset := reset |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,26 +8,22 @@ import freechips.rocketchip.config.Parameters | |||||||
| import freechips.rocketchip.diplomacy._ | import freechips.rocketchip.diplomacy._ | ||||||
| import freechips.rocketchip.util.{HeterogeneousBag, PlusArg} | import freechips.rocketchip.util.{HeterogeneousBag, PlusArg} | ||||||
|  |  | ||||||
| case class TLMonitorArgs(edge: () => Seq[TLEdge], sourceInfo: SourceInfo, p: Parameters) | case class TLMonitorArgs(edge: TLEdge) | ||||||
|  |  | ||||||
| abstract class TLMonitorBase(args: TLMonitorArgs) extends MonitorBase()(args.sourceInfo, args.p) | abstract class TLMonitorBase(args: TLMonitorArgs) extends Module | ||||||
| { | { | ||||||
|   def legalize(bundle: TLBundleSnoop, edge: TLEdge, reset: Bool): Unit |   val io = new Bundle { | ||||||
|  |     val in = new TLBundleSnoop(args.edge.bundle).flip | ||||||
|   lazy val module = new LazyModuleImp(this) { |  | ||||||
|     val edges = args.edge() |  | ||||||
|     val io = IO(new Bundle { |  | ||||||
|       val in = HeterogeneousBag(edges.map(p => new TLBundleSnoop(p.bundle))).flip |  | ||||||
|     }) |  | ||||||
|  |  | ||||||
|     (edges zip io.in).foreach { case (e, in) => legalize(in, e, reset) } |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   def legalize(bundle: TLBundleSnoop, edge: TLEdge, reset: Bool): Unit | ||||||
|  |   legalize(io.in, args.edge, reset) | ||||||
| } | } | ||||||
|  |  | ||||||
| class TLMonitor(args: TLMonitorArgs) extends TLMonitorBase(args) | class TLMonitor(args: TLMonitorArgs) extends TLMonitorBase(args) | ||||||
| { | { | ||||||
|   def extra = { |   def extra = { | ||||||
|     sourceInfo match { |     args.edge.sourceInfo match { | ||||||
|       case SourceLine(filename, line, col) => s" (connected at $filename:$line:$col)" |       case SourceLine(filename, line, col) => s" (connected at $filename:$line:$col)" | ||||||
|       case _ => "" |       case _ => "" | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -10,7 +10,6 @@ import freechips.rocketchip.util.RationalDirection | |||||||
| import scala.collection.mutable.ListBuffer | import scala.collection.mutable.ListBuffer | ||||||
|  |  | ||||||
| case object TLMonitorBuilder extends Field[TLMonitorArgs => TLMonitorBase](args => new TLMonitor(args)) | case object TLMonitorBuilder extends Field[TLMonitorArgs => TLMonitorBase](args => new TLMonitor(args)) | ||||||
| case object TLCombinationalCheck extends Field[Boolean](false) |  | ||||||
|  |  | ||||||
| object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TLEdgeOut, TLEdgeIn, TLBundle] | object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TLEdgeOut, TLEdgeIn, TLBundle] | ||||||
| { | { | ||||||
| @@ -24,25 +23,9 @@ object TLImp extends NodeImp[TLClientPortParameters, TLManagerPortParameters, TL | |||||||
|   override def labelI(ei: TLEdgeIn)  = (ei.manager.beatBytes * 8).toString |   override def labelI(ei: TLEdgeIn)  = (ei.manager.beatBytes * 8).toString | ||||||
|   override def labelO(eo: TLEdgeOut) = (eo.manager.beatBytes * 8).toString |   override def labelO(eo: TLEdgeOut) = (eo.manager.beatBytes * 8).toString | ||||||
|  |  | ||||||
|   override def connect(edges: () => Seq[TLEdgeIn], bundles: () => Seq[(TLBundle, TLBundle)], enableMonitoring: Boolean) |   override def monitor(bundle: TLBundle, edge: TLEdgeIn) { | ||||||
|                       (implicit p: Parameters, sourceInfo: SourceInfo): (Option[TLMonitorBase], () => Unit) = { |     val monitor = Module(edge.params(TLMonitorBuilder)(TLMonitorArgs(edge))) | ||||||
|     val monitor = if (enableMonitoring) Some(LazyModule(p(TLMonitorBuilder)(TLMonitorArgs(edges, sourceInfo, p)))) else None |     monitor.io.in := TLBundleSnoop(bundle, bundle) | ||||||
|     (monitor, () => { |  | ||||||
|       val eval = bundles () |  | ||||||
|       monitor.foreach { m => (eval zip m.module.io.in) foreach { case ((i,o), m) => m := TLBundleSnoop(o,i) } } |  | ||||||
|       eval.foreach { case (bi, bo) => |  | ||||||
|         bi <> bo |  | ||||||
|         if (p(TLCombinationalCheck)) { |  | ||||||
|           // It is forbidden for valid to depend on ready in TL2 |  | ||||||
|           // If someone did that, then this will create a detectable combinational loop |  | ||||||
|           bo.a.ready := bi.a.ready && bo.a.valid |  | ||||||
|           bi.b.ready := bo.b.ready && bi.b.valid |  | ||||||
|           bo.c.ready := bi.c.ready && bo.c.valid |  | ||||||
|           bi.d.ready := bo.d.ready && bi.d.valid |  | ||||||
|           bo.e.ready := bi.e.ready && bo.e.valid |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     }) |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   override def mixO(pd: TLClientPortParameters, node: OutwardNode[TLClientPortParameters, TLManagerPortParameters, TLBundle]): TLClientPortParameters  = |   override def mixO(pd: TLClientPortParameters, node: OutwardNode[TLClientPortParameters, TLManagerPortParameters, TLBundle]): TLClientPortParameters  = | ||||||
|   | |||||||
| @@ -106,9 +106,9 @@ class TLRationalCrossing(direction: RationalDirection = Symmetric)(implicit p: P | |||||||
|   val source = LazyModule(new TLRationalCrossingSource) |   val source = LazyModule(new TLRationalCrossingSource) | ||||||
|   val sink = LazyModule(new TLRationalCrossingSink(direction)) |   val sink = LazyModule(new TLRationalCrossingSink(direction)) | ||||||
|  |  | ||||||
|   val _    = (sink.node := source.node) // no monitor |   sink.node := source.node | ||||||
|   val in   = (source.node := nodeIn) |   source.node := nodeIn | ||||||
|   val out  = (nodeOut := sink.node) |   nodeOut := sink.node | ||||||
|  |  | ||||||
|   lazy val module = new LazyModuleImp(this) { |   lazy val module = new LazyModuleImp(this) { | ||||||
|     val io = IO(new Bundle { |     val io = IO(new Bundle { | ||||||
| @@ -120,17 +120,8 @@ class TLRationalCrossing(direction: RationalDirection = Symmetric)(implicit p: P | |||||||
|  |  | ||||||
|     source.module.clock := io.in_clock |     source.module.clock := io.in_clock | ||||||
|     source.module.reset := io.in_reset |     source.module.reset := io.in_reset | ||||||
|     in.foreach { lm => |  | ||||||
|       lm.module.clock := io.in_clock |  | ||||||
|       lm.module.reset := io.in_reset |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     sink.module.clock := io.out_clock |     sink.module.clock := io.out_clock | ||||||
|     sink.module.reset := io.out_reset |     sink.module.reset := io.out_reset | ||||||
|     out.foreach { lm => |  | ||||||
|       lm.module.clock := io.out_clock |  | ||||||
|       lm.module.reset := io.out_reset |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user