Merge pull request #742 from ucb-bar/true-rational
RationalCrossing: now supporting true rational N:M crossings
This commit is contained in:
		@@ -212,10 +212,13 @@ class TLRAMRationalCrossing(implicit p: Parameters) extends LazyModule {
 | 
			
		||||
 | 
			
		||||
    // Generate slower clock
 | 
			
		||||
    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_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
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,12 @@ class ClockDivider2 extends BlackBox {
 | 
			
		||||
    val clk_in  = Clock(INPUT)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
class ClockDivider3 extends BlackBox {
 | 
			
		||||
  val io = new Bundle {
 | 
			
		||||
    val clk_out = Clock(OUTPUT)
 | 
			
		||||
    val clk_in  = Clock(INPUT)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Divide the clock by power of 2 times.
 | 
			
		||||
 *  @param pow2 divides the clock 2 ^ pow2 times
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
// See LICENSE.SiFive for license details.
 | 
			
		||||
 | 
			
		||||
// If you know two clocks are related with a N:1 or 1:N relationship, you
 | 
			
		||||
// can cross the clock domains with lower latency than an AsyncQueue. This
 | 
			
		||||
// crossing adds 1 cycle in the target clock domain.
 | 
			
		||||
// 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 crossing adds 1 cycle in the target clock domain.
 | 
			
		||||
 | 
			
		||||
package util
 | 
			
		||||
import Chisel._
 | 
			
		||||
@@ -18,17 +18,30 @@ sealed trait RationalDirection {
 | 
			
		||||
// place registers on both sides of the crossing, by splitting
 | 
			
		||||
// a Queue into flow and pipe parts on either side. This is safe
 | 
			
		||||
// 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 {
 | 
			
		||||
  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 {
 | 
			
		||||
  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 {
 | 
			
		||||
  def flip = FastToSlow
 | 
			
		||||
}
 | 
			
		||||
@@ -59,6 +72,7 @@ class RationalCrossingSource[T <: Data](gen: T, direction: RationalDirection = S
 | 
			
		||||
  val deq = io.deq
 | 
			
		||||
  val enq = direction match {
 | 
			
		||||
    case Symmetric  => Queue(io.enq, 1, flow=true)
 | 
			
		||||
    case Flexible => Queue(io.enq, 2)
 | 
			
		||||
    case FastToSlow => io.enq
 | 
			
		||||
    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
 | 
			
		||||
  direction match {
 | 
			
		||||
    case Symmetric  => () // always safe
 | 
			
		||||
    case Flexible   => ()
 | 
			
		||||
    case FastToSlow => 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)
 | 
			
		||||
  direction match {
 | 
			
		||||
    case Symmetric  => io.deq <> Queue(deq, 1, pipe=true)
 | 
			
		||||
    case Flexible   => io.deq <> Queue(deq, 2)
 | 
			
		||||
    case FastToSlow => io.deq <> Queue(deq, 2)
 | 
			
		||||
    case SlowToFast => io.deq <> deq
 | 
			
		||||
  }
 | 
			
		||||
@@ -109,6 +125,7 @@ class RationalCrossingSink[T <: Data](gen: T, direction: RationalDirection = Sym
 | 
			
		||||
  // Ensure the clocking is setup correctly
 | 
			
		||||
  direction match {
 | 
			
		||||
    case Symmetric  => () // always safe
 | 
			
		||||
    case Flexible   => ()
 | 
			
		||||
    case FastToSlow => assert (equal || count(1) =/= enq.source(0))
 | 
			
		||||
    case SlowToFast => assert (equal || count(1) === enq.source(0))
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@
 | 
			
		||||
bb_vsrcs = \
 | 
			
		||||
	$(base_dir)/vsrc/jtag_vpi.v \
 | 
			
		||||
	$(base_dir)/vsrc/ClockDivider2.v \
 | 
			
		||||
	$(base_dir)/vsrc/ClockDivider3.v \
 | 
			
		||||
	$(base_dir)/vsrc/AsyncResetReg.v \
 | 
			
		||||
 | 
			
		||||
sim_vsrcs = \
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										37
									
								
								vsrc/ClockDivider3.v
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								vsrc/ClockDivider3.v
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
// See LICENSE.SiFive for license details.
 | 
			
		||||
 | 
			
		||||
/** This black-boxes a Clock Divider by 3.
 | 
			
		||||
  * The output clock is phase-aligned to the input clock.
 | 
			
		||||
  * Do NOT use this in synthesis; the duty cycle is 2:1.
 | 
			
		||||
  *
 | 
			
		||||
  * Because Chisel does not support
 | 
			
		||||
  * blocking assignments, it is impossible
 | 
			
		||||
  * to create a deterministic divided clock.
 | 
			
		||||
  *
 | 
			
		||||
  *  @param clk_out Divided Clock
 | 
			
		||||
  *  @param clk_in  Clock Input
 | 
			
		||||
  *
 | 
			
		||||
  */
 | 
			
		||||
 | 
			
		||||
module ClockDivider3 (output reg clk_out, input clk_in);
 | 
			
		||||
 | 
			
		||||
   reg delay;
 | 
			
		||||
 | 
			
		||||
   initial begin
 | 
			
		||||
     clk_out = 1'b0;
 | 
			
		||||
     delay = 1'b0;
 | 
			
		||||
   end
 | 
			
		||||
 | 
			
		||||
   always @(posedge clk_in) begin
 | 
			
		||||
      if (clk_out == 1'b0) begin
 | 
			
		||||
        clk_out = 1'b1;
 | 
			
		||||
        delay <= 1'b0;
 | 
			
		||||
      end else if (delay == 1'b1) begin
 | 
			
		||||
        clk_out = 1'b0;
 | 
			
		||||
        delay <= 1'b0;
 | 
			
		||||
      end else begin
 | 
			
		||||
        delay <= 1'b1;
 | 
			
		||||
      end
 | 
			
		||||
   end
 | 
			
		||||
 | 
			
		||||
endmodule // ClockDivider3
 | 
			
		||||
		Reference in New Issue
	
	Block a user