Adding Static Delay in Arbiter and Debugging TIleLink

9 views
Skip to first unread message

Varun Gandhi

unread,
Dec 7, 2022, 1:39:00 PM12/7/22
to chisel...@googlegroups.com
Hi,
I’m trying to add static delay to the Arbiter object in TileLink: https://github.com/chipsalliance/rocket-chip/blob/86a2f2cca699f149bcc082ef2828654a0a4e3f4b/src/main/scala/tilelink/Arbiter.scala
Based on my current understanding, the Arbiter implements a latch in the applyCancel function (copied below) which is set to 1 whenever there are 0 remaining beats. This latch then triggers the round-robin logic to pick 1) a source from the list of sources, 2) check if it has non-zero beats to send, 3) if yes — it waits until beatsLeft is back to 0, 4) when beatsLeft = 0 the latch is set to 1, and it picks the next source. 
I have been trying different permutations of adding a conditional static delay to the latch mechanism using ShiftRegister, but when I test my code using the meta simulation in firesim my workload does not terminate. As a result, I am unable to retrieve the printf statements written to metasim_stderr.out (generated by firesim for every workload run).  What would be a good way to debug the TileLink protocol? 
Also, what are some other mechanisms to add a static delay that could be applied to the Arbiter?
I’d really some pointers on this problem.
Best,
Varun  

——— ApplyCancel Function ————
def applyCancel[T <: Data](policy: Policy)(sink: ReadyValidCancel[T], sources: (UInt, ReadyValidCancel[T])*): Unit = {
    if (sources.isEmpty) {
      sink.earlyValid := false.B
      sink.lateCancel := DontCare
      sink.bits       := DontCare
    } else if (sources.size == 1) {
      sink :<> sources.head._2
    } else {
      val pairs = sources.toList
      val beatsIn = pairs.map(_._1)
      val sourcesIn = pairs.map(_._2)

      // The number of beats which remain to be sent
      val beatsLeft = RegInit(0.U)
      val idle = beatsLeft === 0.U
      val latch = idle && sink.ready // winner (if any) claims sink

      // Who wants access to the sink?
      val earlyValids = sourcesIn.map(_.earlyValid)
      val validQuals  = sourcesIn.map(_.validQual)
      // Arbitrate amongst the requests
      val readys = VecInit(policy(earlyValids.size, Cat(earlyValids.reverse), latch).asBools)
      // Which request wins arbitration?
      val earlyWinner = VecInit((readys zip earlyValids) map { case (r,v) => r&&v })
      val winnerQual  = VecInit((readys zip validQuals)  map { case (r,v) => r&&v })

      // Confirm the policy works properly
      require (readys.size == earlyValids.size)
      require (readys.size == validQuals.size)
      // Never two winners
      val prefixOR = earlyWinner.scanLeft(false.B)(_||_).init
      assert((prefixOR zip earlyWinner) map { case (p,w) => !p || !w } reduce {_ && _})
      // If there was any request, there is a winner
      assert (!earlyValids.reduce(_||_) || earlyWinner.reduce(_||_))
      assert (!validQuals .reduce(_||_) || validQuals .reduce(_||_))

      // Track remaining beats
      val maskedBeats = (winnerQual zip beatsIn) map { case (w,b) => Mux(w, b, 0.U) }
      val initBeats = maskedBeats.reduce(_ | _) // no winner => 0 beats
      beatsLeft := Mux(latch, initBeats, beatsLeft - sink.fire())

      // The one-hot source granted access in the previous cycle
      val state = RegInit(VecInit(Seq.fill(sources.size)(false.B)))
      val muxStateEarly = Mux(idle, earlyWinner, state)
      val muxStateQual  = Mux(idle, winnerQual,  state)
      state := muxStateQual

      val allowed = Mux(idle, readys, state)
      (sourcesIn zip allowed) foreach { case (s, r) =>
        s.ready := sink.ready && r
      }
      sink.earlyValid := Mux(idle, earlyValids.reduce(_||_), Mux1H(state, earlyValids))
      sink.lateCancel := Mux1H(muxStateEarly, sourcesIn.map(_.lateCancel))
      sink.bits      :<= Mux1H(muxStateEarly, sourcesIn.map(_.bits))
    }
  }
}

Reply all
Reply to author
Forward
0 new messages