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:
parent
924afebbd9
commit
91d1880dbf
@ -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
|
Loading…
Reference in New Issue
Block a user