From f6fc3c41e2b8e13b78a291eb03ecd8facbe26e9c Mon Sep 17 00:00:00 2001 From: Max Korbel Date: Mon, 29 Jan 2024 16:37:17 -0800 Subject: [PATCH 1/6] Add EdgeDetector --- doc/README.md | 2 +- doc/components/edge_detector.md | 3 + lib/rohd_hcl.dart | 1 + lib/src/count.dart | 3 +- lib/src/edge_detector.dart | 76 +++++++++++++++++++++ test/edge_detector_test.dart | 117 ++++++++++++++++++++++++++++++++ 6 files changed, 199 insertions(+), 3 deletions(-) create mode 100644 doc/components/edge_detector.md create mode 100644 lib/src/edge_detector.dart create mode 100644 test/edge_detector_test.dart diff --git a/doc/README.md b/doc/README.md index cc31d3a8b..89473dd84 100644 --- a/doc/README.md +++ b/doc/README.md @@ -28,7 +28,7 @@ Some in-development items will have opened issues, as well. Feel free to create - [Count bit occurence](./components/count.md) - Count pattern occurence - Detection - - Edge detection + - [Edge detection](./components/edge_detector.md) - Sort - [Bitonic sort](./components/sort.md#bitonic-sort) - Arithmetic diff --git a/doc/components/edge_detector.md b/doc/components/edge_detector.md new file mode 100644 index 000000000..7984bd989 --- /dev/null +++ b/doc/components/edge_detector.md @@ -0,0 +1,3 @@ +# Edge Detection + +The `EdgeDetector` is a simple utility to determine whether the current value of a 1-bit signal is different from the value in the previous cycle. It is a fully synchronous design, so it does not asynchronously detect edges. It optionally supports a reset, with an optional reset value. It can be configured to detect positive, negative, or "any" edges. diff --git a/lib/rohd_hcl.dart b/lib/rohd_hcl.dart index 2afd3387b..a41967538 100644 --- a/lib/rohd_hcl.dart +++ b/lib/rohd_hcl.dart @@ -6,6 +6,7 @@ export 'src/arbiters/arbiters.dart'; export 'src/carry_save_mutiplier.dart'; export 'src/component_config/component_config.dart'; export 'src/count.dart'; +export 'src/edge_detector.dart'; export 'src/encodings/encodings.dart'; export 'src/error_checking/error_checking.dart'; export 'src/exceptions.dart'; diff --git a/lib/src/count.dart b/lib/src/count.dart index 351799520..44f0c4833 100644 --- a/lib/src/count.dart +++ b/lib/src/count.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2023 Intel Corporation +// Copyright (C) 2023-2024 Intel Corporation // SPDX-License-Identifier: BSD-3-Clause // // count.dart @@ -6,7 +6,6 @@ // // 2023 July 11 // Author: Rahul Gautham Putcha -// import 'dart:math'; diff --git a/lib/src/edge_detector.dart b/lib/src/edge_detector.dart new file mode 100644 index 000000000..9f14d404e --- /dev/null +++ b/lib/src/edge_detector.dart @@ -0,0 +1,76 @@ +// Copyright (C) 2024 Intel Corporation +// SPDX-License-Identifier: BSD-3-Clause +// +// edge_detector.dart +// Implementation of edge detectors. +// +// 2024 January 29 +// Author: Max Korbel + +import 'package:rohd/rohd.dart'; +import 'package:rohd_hcl/src/exceptions.dart'; +import 'package:rohd_vf/rohd_vf.dart'; + +/// +class EdgeDetector extends Module { + /// The type of edge(s) to detect. + final Edge edgeType; + + /// The name of the [edge] output. + String get _edgeName => '${edgeType.name}_edge'; + + /// High for one cycle when the input signal has an [edgeType] transition. + Logic get edge => output(_edgeName); + + /// Creates an edge detector which flags an [edge] when [signal] changes + /// relative to its value in the previous cycle. + /// + /// [signal] must be 1-bit. + /// + /// If a [reset] is provided, then the first cycle after [reset] is + /// deasserted, [signal] will be compared to [resetValue] (or 0, if not + /// provided). + EdgeDetector( + Logic signal, { + required Logic clk, + Logic? reset, + dynamic resetValue, + this.edgeType = Edge.pos, + String? name, + }) : super(name: name ?? '${edgeType.name}_edge_detector') { + if (signal.width != 1 || + (resetValue is Logic && resetValue.width != 1) || + (resetValue is LogicValue && resetValue.width != 1)) { + throw RohdHclException('Can only detect edges on 1-bit signals.'); + } + + if (reset == null && resetValue != null) { + throw RohdHclException( + 'If no reset is provided, then a resetValue cannot be provided.'); + } + + clk = addInput('clk', clk); + signal = addInput('signal', signal); + + if (reset != null) { + reset = addInput('reset', reset); + } + + if (resetValue != null && resetValue is Logic) { + resetValue = addInput('resetValue', resetValue); + } + + addOutput(_edgeName); + + final previousValue = Logic(name: 'previousValue') + ..gets( + flop(clk, reset: reset, resetValue: resetValue, signal), + ); + + edge <= + [ + if (edgeType case Edge.pos || Edge.any) ~previousValue & signal, + if (edgeType case Edge.neg || Edge.any) previousValue & ~signal, + ].swizzle().or(); + } +} diff --git a/test/edge_detector_test.dart b/test/edge_detector_test.dart new file mode 100644 index 000000000..21e4024fb --- /dev/null +++ b/test/edge_detector_test.dart @@ -0,0 +1,117 @@ +// Copyright (C) 2024 Intel Corporation +// SPDX-License-Identifier: BSD-3-Clause +// +// edge_detector_test.dart +// Tests for edge detector. +// +// 2024 January 29 +// Author: Max Korbel + +import 'dart:async'; + +import 'package:rohd/rohd.dart'; +import 'package:rohd_hcl/rohd_hcl.dart'; +import 'package:rohd_vf/rohd_vf.dart'; +import 'package:test/test.dart'; + +void main() { + tearDown(() async { + await Simulator.reset(); + }); + + Future testEdgeDetector(Edge edgeType) async { + final clk = SimpleClockGenerator(10).clk; + final a = Logic(); + final mod = EdgeDetector(a, clk: clk, edgeType: edgeType); + await mod.build(); + final edge = mod.edge; + + Simulator.setMaxSimTime(200); + unawaited(Simulator.run()); + + a.inject(0); + await clk.waitCycles(3); + expect(edge.value.toBool(), isFalse); + + a.inject(1); + + await clk.nextNegedge; + + expect(edge.value.toBool(), edgeType == Edge.pos || edgeType == Edge.any); + + await clk.nextPosedge; + + await clk.nextNegedge; + + expect(edge.value.toBool(), isFalse); + + await clk.nextPosedge; + + a.inject(0); + + await clk.nextNegedge; + + expect(edge.value.toBool(), edgeType == Edge.neg || edgeType == Edge.any); + + await clk.nextPosedge; + + await clk.nextNegedge; + + expect(edge.value.toBool(), isFalse); + + await Simulator.endSimulation(); + } + + for (final edgeType in Edge.values) { + test('${edgeType.name} edge detector', () async { + await testEdgeDetector(edgeType); + }); + } + + test('custom reset value', () async { + final clk = SimpleClockGenerator(10).clk; + final a = Logic(); + final reset = Logic(); + const resetValue = 1; + final mod = EdgeDetector( + a, + clk: clk, + reset: reset, + resetValue: resetValue, + edgeType: Edge.neg, + ); + await mod.build(); + WaveDumper(mod); + final edge = mod.edge; + + Simulator.setMaxSimTime(200); + unawaited(Simulator.run()); + + // leave `a` floating intentionally + reset.inject(0); + + await clk.waitCycles(3); + + reset.inject(1); + + await clk.nextPosedge; + reset.inject(0); + a.inject(0); + + await clk.nextNegedge; + + expect(edge.value.toBool(), isTrue); + + await Simulator.endSimulation(); + }); + + test('exception: bad width signal', () { + expect(() => EdgeDetector(Logic(width: 2), clk: Logic()), + throwsA(isA())); + }); + + test('exception: reset value without reset', () { + expect(() => EdgeDetector(Logic(), clk: Logic(), resetValue: 5), + throwsA(isA())); + }); +} From 6bb8e40245eaa2cc3c779b9eaeded63844985a40 Mon Sep 17 00:00:00 2001 From: Max Korbel Date: Mon, 29 Jan 2024 16:38:55 -0800 Subject: [PATCH 2/6] Remove test wave dumpers that are not necessary --- test/arbiter_test.dart | 2 -- test/edge_detector_test.dart | 1 - test/fifo_test.dart | 3 --- test/memory_test.dart | 2 -- 4 files changed, 8 deletions(-) diff --git a/test/arbiter_test.dart b/test/arbiter_test.dart index 02d1a6fcf..23d3b80b0 100644 --- a/test/arbiter_test.dart +++ b/test/arbiter_test.dart @@ -202,8 +202,6 @@ void main() { rrArbType.constructor(requests, clk: clk, reset: reset); await arbiter.build(); - WaveDumper(arbiter); - final grantCounts = List.generate(arbiter.count, (_) => 0); for (var i = 0; i < arbiter.count; i++) { diff --git a/test/edge_detector_test.dart b/test/edge_detector_test.dart index 21e4024fb..4a48b80a5 100644 --- a/test/edge_detector_test.dart +++ b/test/edge_detector_test.dart @@ -81,7 +81,6 @@ void main() { edgeType: Edge.neg, ); await mod.build(); - WaveDumper(mod); final edge = mod.edge; Simulator.setMaxSimTime(200); diff --git a/test/fifo_test.dart b/test/fifo_test.dart index 0e09548c9..57fc80e19 100644 --- a/test/fifo_test.dart +++ b/test/fifo_test.dart @@ -642,9 +642,6 @@ void main() { Directory('tmp_test').createSync(); - // await fifoTest.fifo.build(); - // WaveDumper(fifoTest.fifo); - final tracker = FifoTracker(fifoTest.fifo, outputFolder: 'tmp_test', dumpTable: false); diff --git a/test/memory_test.dart b/test/memory_test.dart index 7d4822666..5e3318312 100644 --- a/test/memory_test.dart +++ b/test/memory_test.dart @@ -185,8 +185,6 @@ void main() { await mem.build(); - WaveDumper(mem); - wrPorts = wrPorts.map((oldWrPort) { final newWrPort = MaskedDataPortInterface(dataWidth, addrWidth) ..en.put(0); From e6ed35eca3c7162430699e4f68c86a29e00585c3 Mon Sep 17 00:00:00 2001 From: Max Korbel Date: Mon, 29 Jan 2024 16:48:02 -0800 Subject: [PATCH 3/6] Add configurator for edge detector --- .../components/component_registry.dart | 1 + .../components/components.dart | 1 + .../components/config_edge_detector.dart | 51 +++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 lib/src/component_config/components/config_edge_detector.dart diff --git a/lib/src/component_config/components/component_registry.dart b/lib/src/component_config/components/component_registry.dart index 5068b4718..64beb5c92 100644 --- a/lib/src/component_config/components/component_registry.dart +++ b/lib/src/component_config/components/component_registry.dart @@ -21,4 +21,5 @@ List get componentRegistry => [ BitonicSortConfigurator(), OneHotConfigurator(), RegisterFileConfigurator(), + EdgeDetectorConfigurator(), ]; diff --git a/lib/src/component_config/components/components.dart b/lib/src/component_config/components/components.dart index 6788b841f..501780ad4 100644 --- a/lib/src/component_config/components/components.dart +++ b/lib/src/component_config/components/components.dart @@ -3,6 +3,7 @@ export 'config_carry_save_multiplier.dart'; export 'config_ecc.dart'; +export 'config_edge_detector.dart'; export 'config_fifo.dart'; export 'config_one_hot.dart'; export 'config_priority_arbiter.dart'; diff --git a/lib/src/component_config/components/config_edge_detector.dart b/lib/src/component_config/components/config_edge_detector.dart new file mode 100644 index 000000000..3e6301755 --- /dev/null +++ b/lib/src/component_config/components/config_edge_detector.dart @@ -0,0 +1,51 @@ +// Copyright (C) 2024 Intel Corporation +// SPDX-License-Identifier: BSD-3-Clause +// +// config_edge_detector.dart +// Configurator for a EdgeDetector. +// +// 2024 January 29 +// Author: Max Korbel + +import 'dart:collection'; + +import 'package:rohd/rohd.dart'; +import 'package:rohd_hcl/rohd_hcl.dart'; +import 'package:rohd_vf/rohd_vf.dart'; + +/// A [Configurator] for [EdgeDetector]. +class EdgeDetectorConfigurator extends Configurator { + /// A knob controlling the type of edge detector. + final ChoiceConfigKnob edgeTypeKnob = + ChoiceConfigKnob(Edge.values, value: Edge.pos); + + /// A knob controlling whether there is a reset. + final ToggleConfigKnob hasResetKnob = ToggleConfigKnob(value: true); + + /// A knob controlling the reset value. + final ChoiceConfigKnob resetValueKnob = + ChoiceConfigKnob([0, 1, 'Input'], value: 0); + + @override + Module createModule() => EdgeDetector( + Logic(), + clk: Logic(), + reset: hasResetKnob.value ? Logic() : null, + resetValue: hasResetKnob.value + ? resetValueKnob.value == 'Input' + ? Logic() + : resetValueKnob.value + : null, + ); + + @override + // TODO: implement knobs + late final Map> knobs = UnmodifiableMapView({ + 'Edge Type': edgeTypeKnob, + 'Has Reset': hasResetKnob, + if (hasResetKnob.value) 'Reset Value': resetValueKnob, + }); + + @override + final String name = 'Edge Detector'; +} From 23f7a1d1cebfe2e0c10b6052e82bf7ce27f2ca74 Mon Sep 17 00:00:00 2001 From: Max Korbel Date: Mon, 29 Jan 2024 16:49:03 -0800 Subject: [PATCH 4/6] fix lint --- lib/src/component_config/components/config_edge_detector.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/src/component_config/components/config_edge_detector.dart b/lib/src/component_config/components/config_edge_detector.dart index 3e6301755..5e5dd2d01 100644 --- a/lib/src/component_config/components/config_edge_detector.dart +++ b/lib/src/component_config/components/config_edge_detector.dart @@ -39,7 +39,6 @@ class EdgeDetectorConfigurator extends Configurator { ); @override - // TODO: implement knobs late final Map> knobs = UnmodifiableMapView({ 'Edge Type': edgeTypeKnob, 'Has Reset': hasResetKnob, From 49e5e46583acc993295ee0e6d900b53ed7edd188 Mon Sep 17 00:00:00 2001 From: Max Korbel Date: Mon, 29 Jan 2024 16:51:16 -0800 Subject: [PATCH 5/6] fix copyright dates --- lib/rohd_hcl.dart | 2 +- lib/src/component_config/components/component_registry.dart | 2 +- lib/src/component_config/components/components.dart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/rohd_hcl.dart b/lib/rohd_hcl.dart index a41967538..e16a51e56 100644 --- a/lib/rohd_hcl.dart +++ b/lib/rohd_hcl.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2023 Intel Corporation +// Copyright (C) 2023-2024 Intel Corporation // SPDX-License-Identifier: BSD-3-Clause export 'src/adder.dart'; diff --git a/lib/src/component_config/components/component_registry.dart b/lib/src/component_config/components/component_registry.dart index 64beb5c92..4b270fb74 100644 --- a/lib/src/component_config/components/component_registry.dart +++ b/lib/src/component_config/components/component_registry.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2023 Intel Corporation +// Copyright (C) 2023-2024 Intel Corporation // SPDX-License-Identifier: BSD-3-Clause // // component_registry.dart diff --git a/lib/src/component_config/components/components.dart b/lib/src/component_config/components/components.dart index 501780ad4..1f51c899a 100644 --- a/lib/src/component_config/components/components.dart +++ b/lib/src/component_config/components/components.dart @@ -1,4 +1,4 @@ -// Copyright (C) 2023 Intel Corporation +// Copyright (C) 2023-2024 Intel Corporation // SPDX-License-Identifier: BSD-3-Clause export 'config_carry_save_multiplier.dart'; From dfec3465bbdb2cedbc99ff61b8782cfa1cb8e408 Mon Sep 17 00:00:00 2001 From: Max Korbel Date: Mon, 29 Jan 2024 23:53:02 -0800 Subject: [PATCH 6/6] fix comment and getter in configurator --- .../components/config_edge_detector.dart | 10 +++++----- lib/src/edge_detector.dart | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/src/component_config/components/config_edge_detector.dart b/lib/src/component_config/components/config_edge_detector.dart index 5e5dd2d01..ec061ea31 100644 --- a/lib/src/component_config/components/config_edge_detector.dart +++ b/lib/src/component_config/components/config_edge_detector.dart @@ -39,11 +39,11 @@ class EdgeDetectorConfigurator extends Configurator { ); @override - late final Map> knobs = UnmodifiableMapView({ - 'Edge Type': edgeTypeKnob, - 'Has Reset': hasResetKnob, - if (hasResetKnob.value) 'Reset Value': resetValueKnob, - }); + Map> get knobs => UnmodifiableMapView({ + 'Edge Type': edgeTypeKnob, + 'Has Reset': hasResetKnob, + if (hasResetKnob.value) 'Reset Value': resetValueKnob, + }); @override final String name = 'Edge Detector'; diff --git a/lib/src/edge_detector.dart b/lib/src/edge_detector.dart index 9f14d404e..7c8fc7878 100644 --- a/lib/src/edge_detector.dart +++ b/lib/src/edge_detector.dart @@ -11,7 +11,8 @@ import 'package:rohd/rohd.dart'; import 'package:rohd_hcl/src/exceptions.dart'; import 'package:rohd_vf/rohd_vf.dart'; -/// +/// An edge detector for positive, negative, or any edge on a signal relative to +/// the previous clock cycle. class EdgeDetector extends Module { /// The type of edge(s) to detect. final Edge edgeType;