-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
254 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
lib/src/component_config/components/config_edge_detector.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// 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 <[email protected]> | ||
|
||
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<Edge> 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<dynamic> 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 | ||
Map<String, ConfigKnob<dynamic>> get knobs => UnmodifiableMapView({ | ||
'Edge Type': edgeTypeKnob, | ||
'Has Reset': hasResetKnob, | ||
if (hasResetKnob.value) 'Reset Value': resetValueKnob, | ||
}); | ||
|
||
@override | ||
final String name = 'Edge Detector'; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,11 @@ | ||
// Copyright (C) 2023 Intel Corporation | ||
// Copyright (C) 2023-2024 Intel Corporation | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
// | ||
// count.dart | ||
// Implementation of Count Functionality. | ||
// | ||
// 2023 July 11 | ||
// Author: Rahul Gautham Putcha <[email protected]> | ||
// | ||
|
||
import 'dart:math'; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
// Copyright (C) 2024 Intel Corporation | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
// | ||
// edge_detector.dart | ||
// Implementation of edge detectors. | ||
// | ||
// 2024 January 29 | ||
// Author: Max Korbel <[email protected]> | ||
|
||
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; | ||
|
||
/// 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(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
// 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 <[email protected]> | ||
|
||
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<void> 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(); | ||
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<RohdHclException>())); | ||
}); | ||
|
||
test('exception: reset value without reset', () { | ||
expect(() => EdgeDetector(Logic(), clk: Logic(), resetValue: 5), | ||
throwsA(isA<RohdHclException>())); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters