ClockDivider2: fix launch alignment of clocks (vcs)
Doing this in Chisel leads to non-determinism due to shitty Verilog ordering semantis. Using an '=' ensures that all of the clock posedges fire before concurrent register updates. See "Gotcha 29: Sequential logic that requires blocking assignments" in "Verilog and SystemVerilog Gotchas" by Stuart Sutherland, Don Mills.
This commit is contained in:
		@@ -5,15 +5,11 @@ package util
 | 
				
			|||||||
import Chisel._
 | 
					import Chisel._
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Divide the clock by 2 */
 | 
					/** Divide the clock by 2 */
 | 
				
			||||||
class ClockDivider2 extends Module {
 | 
					class ClockDivider2 extends BlackBox {
 | 
				
			||||||
  val io = new Bundle {
 | 
					  val io = new Bundle {
 | 
				
			||||||
    val clock_out = Clock(OUTPUT)
 | 
					    val clk_out = Clock(OUTPUT)
 | 
				
			||||||
 | 
					    val clk_in  = Clock(INPUT)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
  val clock_reg = Reg(Bool())
 | 
					 | 
				
			||||||
  clock_reg := !clock_reg
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  io.clock_out := clock_reg.asClock
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Divide the clock by power of 2 times.
 | 
					/** Divide the clock by power of 2 times.
 | 
				
			||||||
@@ -30,9 +26,10 @@ class Pow2ClockDivider(pow2: Int) extends Module {
 | 
				
			|||||||
    val dividers = Seq.fill(pow2) { Module(new ClockDivider2) }
 | 
					    val dividers = Seq.fill(pow2) { Module(new ClockDivider2) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dividers.init.zip(dividers.tail).map { case (last, next) =>
 | 
					    dividers.init.zip(dividers.tail).map { case (last, next) =>
 | 
				
			||||||
      next.clock := last.io.clock_out
 | 
					      next.io.clk_in := last.io.clk_out
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    io.clock_out := dividers.last.io.clock_out
 | 
					    dividers.head.io.clk_in := clock
 | 
				
			||||||
 | 
					    io.clock_out := dividers.last.io.clk_out
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
bb_vsrcs = $(base_dir)/vsrc/DebugTransportModuleJtag.v \
 | 
					bb_vsrcs = $(base_dir)/vsrc/DebugTransportModuleJtag.v \
 | 
				
			||||||
	$(base_dir)/vsrc/jtag_vpi.v \
 | 
						$(base_dir)/vsrc/jtag_vpi.v \
 | 
				
			||||||
 | 
						$(base_dir)/vsrc/ClockDivider2.v \
 | 
				
			||||||
	$(base_dir)/vsrc/AsyncResetReg.v \
 | 
						$(base_dir)/vsrc/AsyncResetReg.v \
 | 
				
			||||||
 | 
					
 | 
				
			||||||
sim_vsrcs = \
 | 
					sim_vsrcs = \
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										21
									
								
								vsrc/ClockDivider2.v
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vsrc/ClockDivider2.v
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					// See LICENSE.SiFive for license details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** This black-boxes a Clock Divider.
 | 
				
			||||||
 | 
					  *
 | 
				
			||||||
 | 
					  * 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 ClockDivider2 (output reg clk_out, input clk_in);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   initial clk_out = 1'b0;
 | 
				
			||||||
 | 
					   always @(posedge clk_in) begin
 | 
				
			||||||
 | 
					      clk_out = ~clk_out; // Must use =, NOT <=
 | 
				
			||||||
 | 
					   end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					endmodule // ClockDivider2
 | 
				
			||||||
		Reference in New Issue
	
	Block a user