From 9d51ac379405c2f825dea312cfa97d8954a21601 Mon Sep 17 00:00:00 2001 From: Max Korbel Date: Tue, 1 Nov 2022 10:16:31 -0700 Subject: [PATCH] Fix bug related to clock divider simulation, fix #191 --- lib/src/modules/conditional.dart | 22 ++++++---- test/clock_divider_test.dart | 69 ++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 test/clock_divider_test.dart diff --git a/lib/src/modules/conditional.dart b/lib/src/modules/conditional.dart index 589a3d52a..25e98144b 100644 --- a/lib/src/modules/conditional.dart +++ b/lib/src/modules/conditional.dart @@ -336,14 +336,22 @@ class Sequential extends _Always { clk.glitch.listen((event) async { // we want the first previousValue from the first glitch of this tick _preTickClkValues[i] ??= event.previousValue; - if (!_pendingExecute) { - unawaited(Simulator.clkStable.first.then((value) { - // once the clocks are stable, execute the contents of the FF - _execute(); - _pendingExecute = false; - })); + + if (Simulator.phase == SimulatorPhase.clkStable) { + // this could be an output of a flop driving the clock of this + // flop, so execute immediately (e.g. clock divider) + _execute(); + _pendingExecute = false; + } else { + if (!_pendingExecute) { + unawaited(Simulator.clkStable.first.then((value) { + // once the clocks are stable, execute the contents of the FF + _execute(); + _pendingExecute = false; + })); + } + _pendingExecute = true; } - _pendingExecute = true; }); } } diff --git a/test/clock_divider_test.dart b/test/clock_divider_test.dart new file mode 100644 index 000000000..051113bd9 --- /dev/null +++ b/test/clock_divider_test.dart @@ -0,0 +1,69 @@ +import 'package:rohd/rohd.dart'; +import 'package:rohd/src/utilities/simcompare.dart'; +import 'package:test/test.dart'; + +import '../example/example.dart'; + +class ClockDivider extends Module { + Logic get clkOut => output('clkOut'); + ClockDivider(Logic clkIn, Logic reset) : super(name: 'clockDivider') { + clkIn = addInput('clkIn', clkIn); + reset = addInput('reset', reset); + final clkOut = addOutput('clkOut'); + + Sequential(clkIn, [ + If( + reset, + then: [clkOut < 0], + orElse: [clkOut < ~clkOut], + ), + ]); + } +} + +class TwoCounters extends Module { + TwoCounters(Logic resetClks, Logic resetCounters) { + resetClks = addInput('resetClks', resetClks); + resetCounters = addInput('resetCounters', resetCounters); + + final clk = SimpleClockGenerator(10).clk; + final clkDiv = ClockDivider(clk, resetClks).clkOut; + + addOutput('cntFast', width: 8) <= + Counter(Const(1), resetCounters, clk, name: 'fastCounter').val; + addOutput('cntSlow', width: 8) <= + Counter(Const(1), resetCounters, clkDiv, name: 'slowCounter').val; + } +} + +void main() { + test('clock divider', () async { + final mod = TwoCounters(Logic(), Logic()); + await mod.build(); + final vectors = [ + Vector({'resetClks': 1, 'resetCounters': 1}, {}), + Vector({'resetClks': 0, 'resetCounters': 1}, {}), + Vector({'resetClks': 0, 'resetCounters': 1}, {}), + Vector( + {'resetClks': 0, 'resetCounters': 0}, {'cntSlow': 0, 'cntFast': 0}), + Vector( + {'resetClks': 0, 'resetCounters': 0}, {'cntSlow': 1, 'cntFast': 1}), + Vector( + {'resetClks': 0, 'resetCounters': 0}, {'cntSlow': 1, 'cntFast': 2}), + Vector( + {'resetClks': 0, 'resetCounters': 0}, {'cntSlow': 2, 'cntFast': 3}), + Vector( + {'resetClks': 0, 'resetCounters': 0}, {'cntSlow': 2, 'cntFast': 4}), + Vector( + {'resetClks': 0, 'resetCounters': 0}, {'cntSlow': 3, 'cntFast': 5}), + Vector( + {'resetClks': 0, 'resetCounters': 0}, {'cntSlow': 3, 'cntFast': 6}), + ]; + + await SimCompare.checkFunctionalVector(mod, vectors); + final simResult = SimCompare.iverilogVector( + mod.generateSynth(), mod.runtimeType.toString(), vectors, + signalToWidthMap: {'cntSlow': 8, 'cntFast': 8}); + expect(simResult, equals(true)); + }); +}