1
0

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:
Wesley W. Terpstra 2017-02-17 11:49:35 +01:00
parent 924afebbd9
commit 91d1880dbf
3 changed files with 28 additions and 9 deletions

View File

@ -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
} }
} }

View File

@ -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
View 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