From 9d51ac379405c2f825dea312cfa97d8954a21601 Mon Sep 17 00:00:00 2001 From: Max Korbel Date: Tue, 1 Nov 2022 10:16:31 -0700 Subject: [PATCH 1/5] 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)); + }); +} From a12d2f66bf8955d2913f963a9f8171c6ca8161bc Mon Sep 17 00:00:00 2001 From: Max Korbel Date: Tue, 1 Nov 2022 10:20:14 -0700 Subject: [PATCH 2/5] Add header to clock divider test --- test/clock_divider_test.dart | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/clock_divider_test.dart b/test/clock_divider_test.dart index 051113bd9..fdc3e8335 100644 --- a/test/clock_divider_test.dart +++ b/test/clock_divider_test.dart @@ -1,3 +1,13 @@ +/// Copyright (C) 2022 Intel Corporation +/// SPDX-License-Identifier: BSD-3-Clause +/// +/// clock_divider_test.dart +/// Unit tests for a clock divider. +/// +/// 2022 November 1 +/// Author: Max Korbel +/// + import 'package:rohd/rohd.dart'; import 'package:rohd/src/utilities/simcompare.dart'; import 'package:test/test.dart'; From 1685ae7a6fc99d44c5c6aef4775875d655aff1a5 Mon Sep 17 00:00:00 2001 From: Max Korbel Date: Tue, 1 Nov 2022 12:01:28 -0700 Subject: [PATCH 3/5] added async reset version of the test --- test/clock_divider_test.dart | 52 +++++++++++++++++++++++++++--------- test/counter_test.dart | 8 ++++-- 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/test/clock_divider_test.dart b/test/clock_divider_test.dart index fdc3e8335..702f92c93 100644 --- a/test/clock_divider_test.dart +++ b/test/clock_divider_test.dart @@ -12,7 +12,8 @@ import 'package:rohd/rohd.dart'; import 'package:rohd/src/utilities/simcompare.dart'; import 'package:test/test.dart'; -import '../example/example.dart'; +import '../example/example.dart' as sync_reset; +import 'counter_test.dart' as async_reset; class ClockDivider extends Module { Logic get clkOut => output('clkOut'); @@ -32,7 +33,7 @@ class ClockDivider extends Module { } class TwoCounters extends Module { - TwoCounters(Logic resetClks, Logic resetCounters) { + TwoCounters(Logic resetClks, Logic resetCounters, {required bool syncReset}) { resetClks = addInput('resetClks', resetClks); resetCounters = addInput('resetCounters', resetCounters); @@ -40,16 +41,26 @@ class TwoCounters extends Module { final clkDiv = ClockDivider(clk, resetClks).clkOut; addOutput('cntFast', width: 8) <= - Counter(Const(1), resetCounters, clk, name: 'fastCounter').val; + (syncReset + ? sync_reset.Counter(Const(1), resetCounters, clk, + name: 'fastCounter') + .val + : async_reset.Counter(Const(1), resetCounters, + clkOverride: clk, name: 'fastCounter') + .val); addOutput('cntSlow', width: 8) <= - Counter(Const(1), resetCounters, clkDiv, name: 'slowCounter').val; + (syncReset + ? sync_reset.Counter(Const(1), resetCounters, clkDiv, + name: 'slowCounter') + .val + : async_reset.Counter(Const(1), resetCounters, + clkOverride: clkDiv, name: 'slowCounter') + .val); } } void main() { - test('clock divider', () async { - final mod = TwoCounters(Logic(), Logic()); - await mod.build(); + group('clock divider', () { final vectors = [ Vector({'resetClks': 1, 'resetCounters': 1}, {}), Vector({'resetClks': 0, 'resetCounters': 1}, {}), @@ -69,11 +80,28 @@ void main() { Vector( {'resetClks': 0, 'resetCounters': 0}, {'cntSlow': 3, 'cntFast': 6}), ]; + final signalToWidthMap = {'cntSlow': 8, 'cntFast': 8}; - await SimCompare.checkFunctionalVector(mod, vectors); - final simResult = SimCompare.iverilogVector( - mod.generateSynth(), mod.runtimeType.toString(), vectors, - signalToWidthMap: {'cntSlow': 8, 'cntFast': 8}); - expect(simResult, equals(true)); + test('sync reset', () async { + final mod = TwoCounters(Logic(), Logic(), syncReset: true); + await mod.build(); + + await SimCompare.checkFunctionalVector(mod, vectors); + final simResult = SimCompare.iverilogVector( + mod.generateSynth(), mod.runtimeType.toString(), vectors, + signalToWidthMap: signalToWidthMap); + expect(simResult, equals(true)); + }); + + test('async reset', () async { + final mod = TwoCounters(Logic(), Logic(), syncReset: false); + await mod.build(); + + await SimCompare.checkFunctionalVector(mod, vectors); + final simResult = SimCompare.iverilogVector( + mod.generateSynth(), mod.runtimeType.toString(), vectors, + signalToWidthMap: signalToWidthMap); + expect(simResult, equals(true)); + }); }); } diff --git a/test/counter_test.dart b/test/counter_test.dart index e9bb9f5d3..e696d7c92 100644 --- a/test/counter_test.dart +++ b/test/counter_test.dart @@ -18,7 +18,8 @@ import 'package:test/test.dart'; class Counter extends Module { final int width; Logic get val => output('val'); - Counter(Logic en, Logic reset, {this.width = 8}) : super(name: 'counter') { + Counter(Logic en, Logic reset, + {this.width = 8, Logic? clkOverride, super.name = 'counter'}) { en = addInput('en', en); reset = addInput('reset', reset); @@ -29,7 +30,10 @@ class Counter extends Module { nextVal <= val + 1; Sequential.multi([ - SimpleClockGenerator(10).clk, + if (clkOverride != null) + addInput('clk', clkOverride) + else + SimpleClockGenerator(10).clk, reset ], [ If(reset, then: [ From 7219621e8108fa3ab34374e241cc50f0439e1c47 Mon Sep 17 00:00:00 2001 From: Max Korbel Date: Tue, 1 Nov 2022 12:05:18 -0700 Subject: [PATCH 4/5] Fix teardown in clock divider test --- test/clock_divider_test.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/test/clock_divider_test.dart b/test/clock_divider_test.dart index 702f92c93..799aa9afc 100644 --- a/test/clock_divider_test.dart +++ b/test/clock_divider_test.dart @@ -60,6 +60,7 @@ class TwoCounters extends Module { } void main() { + tearDown(Simulator.reset); group('clock divider', () { final vectors = [ Vector({'resetClks': 1, 'resetCounters': 1}, {}), From 33037289394923601b322613f68ae688891410b3 Mon Sep 17 00:00:00 2001 From: Max Korbel Date: Fri, 4 Nov 2022 12:52:55 -0700 Subject: [PATCH 5/5] Made the reset for divider async also in async reset test --- test/clock_divider_test.dart | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/clock_divider_test.dart b/test/clock_divider_test.dart index 799aa9afc..8dac98041 100644 --- a/test/clock_divider_test.dart +++ b/test/clock_divider_test.dart @@ -17,12 +17,16 @@ import 'counter_test.dart' as async_reset; class ClockDivider extends Module { Logic get clkOut => output('clkOut'); - ClockDivider(Logic clkIn, Logic reset) : super(name: 'clockDivider') { + ClockDivider(Logic clkIn, Logic reset, {bool syncReset = true}) + : super(name: 'clockDivider') { clkIn = addInput('clkIn', clkIn); reset = addInput('reset', reset); final clkOut = addOutput('clkOut'); - Sequential(clkIn, [ + Sequential.multi([ + clkIn, + if (!syncReset) reset + ], [ If( reset, then: [clkOut < 0], @@ -38,7 +42,7 @@ class TwoCounters extends Module { resetCounters = addInput('resetCounters', resetCounters); final clk = SimpleClockGenerator(10).clk; - final clkDiv = ClockDivider(clk, resetClks).clkOut; + final clkDiv = ClockDivider(clk, resetClks, syncReset: syncReset).clkOut; addOutput('cntFast', width: 8) <= (syncReset