1
0

rational: adjust comments and add a case for N:M

This commit is contained in:
Wesley W. Terpstra 2017-05-14 15:11:29 -07:00
parent 2119df5a60
commit 3e2b477c0a
2 changed files with 28 additions and 8 deletions

View File

@ -212,10 +212,13 @@ class TLRAMRationalCrossing(implicit p: Parameters) extends LazyModule {
// Generate slower clock // Generate slower clock
val slow = Module(new util.Pow2ClockDivider(2)) val slow = Module(new util.Pow2ClockDivider(2))
sym_slow_source.module.clock := slow.io.clock_out
sym_slow_sink .module.clock := slow.io.clock_out
fix_slow_source.module.clock := slow.io.clock_out fix_slow_source.module.clock := slow.io.clock_out
fix_slow_sink .module.clock := slow.io.clock_out fix_slow_sink .module.clock := slow.io.clock_out
val odd = Module(new util.ClockDivider3)
odd.io.clk_in := clock
sym_slow_source.module.clock := odd.io.clk_out
sym_slow_sink .module.clock := odd.io.clk_out
} }
} }

View File

@ -1,8 +1,8 @@
// See LICENSE.SiFive for license details. // See LICENSE.SiFive for license details.
// If you know two clocks are related with a N:1 or 1:N relationship, you // If you know two clocks are related with an N:M relationship, you
// can cross the clock domains with lower latency than an AsyncQueue. This // can cross the clock domains with lower latency than an AsyncQueue.
// crossing adds 1 cycle in the target clock domain. // This crossing adds 1 cycle in the target clock domain.
package util package util
import Chisel._ import Chisel._
@ -18,17 +18,30 @@ sealed trait RationalDirection {
// place registers on both sides of the crossing, by splitting // place registers on both sides of the crossing, by splitting
// a Queue into flow and pipe parts on either side. This is safe // a Queue into flow and pipe parts on either side. This is safe
// for all possible clock ratios, but has the downside that the // for all possible clock ratios, but has the downside that the
// path from the slow domain must close timing in the fast domain. // timing must be met for the least-common-multiple of the clocks.
case object Symmetric extends RationalDirection { case object Symmetric extends RationalDirection {
def flip = Symmetric def flip = Symmetric
} }
// If the source is fast, place the registers at the sink. // Like Symmetric, this crossing works for all ratios N:M.
// However, unlike the other crossing options, this varient adds
// a full flow+pipe buffer on both sides of the crossing. This
// ends up costing potentially two cycles of delay, but gives
// both clock domains a full clock period to close timing.
case object Flexible extends RationalDirection {
def flip = Flexible
}
// If the source is N:1 of the sink, place the registers at the sink.
// This imposes only a single clock cycle of delay and both side of
// the crossing have a full clock period to close timing.
case object FastToSlow extends RationalDirection { case object FastToSlow extends RationalDirection {
def flip = SlowToFast def flip = SlowToFast
} }
// If the source is slow, place the registers at the source. // If the source is 1:N of the sink, place the registers at the source.
// This imposes only a single clock cycle of delay and both side of
// the crossing have a full clock period to close timing.
case object SlowToFast extends RationalDirection { case object SlowToFast extends RationalDirection {
def flip = FastToSlow def flip = FastToSlow
} }
@ -59,6 +72,7 @@ class RationalCrossingSource[T <: Data](gen: T, direction: RationalDirection = S
val deq = io.deq val deq = io.deq
val enq = direction match { val enq = direction match {
case Symmetric => Queue(io.enq, 1, flow=true) case Symmetric => Queue(io.enq, 1, flow=true)
case Flexible => Queue(io.enq, 2)
case FastToSlow => io.enq case FastToSlow => io.enq
case SlowToFast => Queue(io.enq, 2) case SlowToFast => Queue(io.enq, 2)
} }
@ -76,6 +90,7 @@ class RationalCrossingSource[T <: Data](gen: T, direction: RationalDirection = S
// Ensure the clocking is setup correctly // Ensure the clocking is setup correctly
direction match { direction match {
case Symmetric => () // always safe case Symmetric => () // always safe
case Flexible => ()
case FastToSlow => assert (equal || count(1) === deq.sink(0)) case FastToSlow => assert (equal || count(1) === deq.sink(0))
case SlowToFast => assert (equal || count(1) =/= deq.sink(0)) case SlowToFast => assert (equal || count(1) =/= deq.sink(0))
} }
@ -92,6 +107,7 @@ class RationalCrossingSink[T <: Data](gen: T, direction: RationalDirection = Sym
val deq = Wire(io.deq) val deq = Wire(io.deq)
direction match { direction match {
case Symmetric => io.deq <> Queue(deq, 1, pipe=true) case Symmetric => io.deq <> Queue(deq, 1, pipe=true)
case Flexible => io.deq <> Queue(deq, 2)
case FastToSlow => io.deq <> Queue(deq, 2) case FastToSlow => io.deq <> Queue(deq, 2)
case SlowToFast => io.deq <> deq case SlowToFast => io.deq <> deq
} }
@ -109,6 +125,7 @@ class RationalCrossingSink[T <: Data](gen: T, direction: RationalDirection = Sym
// Ensure the clocking is setup correctly // Ensure the clocking is setup correctly
direction match { direction match {
case Symmetric => () // always safe case Symmetric => () // always safe
case Flexible => ()
case FastToSlow => assert (equal || count(1) =/= enq.source(0)) case FastToSlow => assert (equal || count(1) =/= enq.source(0))
case SlowToFast => assert (equal || count(1) === enq.source(0)) case SlowToFast => assert (equal || count(1) === enq.source(0))
} }