Skip to content

Commit

Permalink
Edge Detector (#75)
Browse files Browse the repository at this point in the history
  • Loading branch information
mkorbel1 authored Jan 30, 2024
1 parent 084e01e commit f0b53a1
Show file tree
Hide file tree
Showing 12 changed files with 254 additions and 13 deletions.
2 changes: 1 addition & 1 deletion doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions doc/components/edge_detector.md
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.
3 changes: 2 additions & 1 deletion lib/rohd_hcl.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// Copyright (C) 2023 Intel Corporation
// Copyright (C) 2023-2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause

export 'src/adder.dart';
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';
Expand Down
3 changes: 2 additions & 1 deletion lib/src/component_config/components/component_registry.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2023 Intel Corporation
// Copyright (C) 2023-2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// component_registry.dart
Expand All @@ -21,4 +21,5 @@ List<Configurator> get componentRegistry => [
BitonicSortConfigurator(),
OneHotConfigurator(),
RegisterFileConfigurator(),
EdgeDetectorConfigurator(),
];
3 changes: 2 additions & 1 deletion lib/src/component_config/components/components.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// Copyright (C) 2023 Intel Corporation
// Copyright (C) 2023-2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause

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';
Expand Down
50 changes: 50 additions & 0 deletions lib/src/component_config/components/config_edge_detector.dart
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';
}
3 changes: 1 addition & 2 deletions lib/src/count.dart
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';

Expand Down
77 changes: 77 additions & 0 deletions lib/src/edge_detector.dart
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();
}
}
2 changes: 0 additions & 2 deletions test/arbiter_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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++) {
Expand Down
116 changes: 116 additions & 0 deletions test/edge_detector_test.dart
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>()));
});
}
3 changes: 0 additions & 3 deletions test/fifo_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
2 changes: 0 additions & 2 deletions test/memory_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,6 @@ void main() {

await mem.build();

WaveDumper(mem);

wrPorts = wrPorts.map((oldWrPort) {
final newWrPort = MaskedDataPortInterface(dataWidth, addrWidth)
..en.put(0);
Expand Down

0 comments on commit f0b53a1

Please sign in to comment.