From 91d1880dbf63696baa29d80e1f1576d8ba19b98b Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Fri, 17 Feb 2017 11:49:35 +0100 Subject: [PATCH] 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. --- src/main/scala/util/ClockDivider.scala | 15 ++++++--------- vsim/Makefrag | 1 + vsrc/ClockDivider2.v | 21 +++++++++++++++++++++ 3 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 vsrc/ClockDivider2.v diff --git a/src/main/scala/util/ClockDivider.scala b/src/main/scala/util/ClockDivider.scala index 500650a8..094f045f 100644 --- a/src/main/scala/util/ClockDivider.scala +++ b/src/main/scala/util/ClockDivider.scala @@ -5,15 +5,11 @@ package util import Chisel._ /** Divide the clock by 2 */ -class ClockDivider2 extends Module { +class ClockDivider2 extends BlackBox { 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. @@ -30,9 +26,10 @@ class Pow2ClockDivider(pow2: Int) extends Module { val dividers = Seq.fill(pow2) { Module(new ClockDivider2) } 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 } } diff --git a/vsim/Makefrag b/vsim/Makefrag index 66f681c8..93c38d8f 100644 --- a/vsim/Makefrag +++ b/vsim/Makefrag @@ -6,6 +6,7 @@ bb_vsrcs = $(base_dir)/vsrc/DebugTransportModuleJtag.v \ $(base_dir)/vsrc/jtag_vpi.v \ + $(base_dir)/vsrc/ClockDivider2.v \ $(base_dir)/vsrc/AsyncResetReg.v \ sim_vsrcs = \ diff --git a/vsrc/ClockDivider2.v b/vsrc/ClockDivider2.v new file mode 100644 index 00000000..9da5e93c --- /dev/null +++ b/vsrc/ClockDivider2.v @@ -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