Skip to content

Commit

Permalink
Gated counter and toggle gate (#111)
Browse files Browse the repository at this point in the history
  • Loading branch information
mkorbel1 authored Nov 20, 2024
1 parent 3530022 commit d8d72f8
Show file tree
Hide file tree
Showing 22 changed files with 1,595 additions and 200 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/general.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ jobs:

- name: Generate HTML for examples
run: tool/gh_actions/create_htmls.sh

- name: Check temporary test files
run: tool/gh_actions/check_tmp_test.sh

# https://github.com/devcontainers/ci/blob/main/docs/github-action.md
- name: Build dev container and run tests in it
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ tmp*
confapp/.vscode/*
*tracker.json
*tracker.log
devtools_options.yaml
*.sv

# Exceptions
Expand Down
4 changes: 3 additions & 1 deletion doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ Some in-development items will have opened issues, as well. Feel free to create
- Counters
- [Summation](./components/summation.md#sum)
- [Binary counter](./components/summation.md#counter)
- [Gated counter](./components/summation.md#gated-counter)
- Gray counter
- Pseudorandom
- LFSR
Expand All @@ -73,8 +74,9 @@ Some in-development items will have opened issues, as well. Feel free to create
- CRC
- [Parity](./components/parity.md)
- Interleaving
- Clocking
- Gating
- [Clock gating](./components/clock_gating.md)
- [Toggle gating](./components/toggle_gate.md)
- Data flow
- Ready/Valid
- Connect/Disconnect
Expand Down
8 changes: 8 additions & 0 deletions doc/components/summation.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,11 @@ The `Counter` also has a `Counter.simple` constructor which is intended for very
// A counter which increments by 1 each cycle up to 5, then rolls over.
Counter.simple(clk: clk, reset: reset, maxValue: 5);
```

## Gated Counter

The `GatedCounter` is a version of a `Counter` which contains a number of power-saving features including clock gating to save on flop power and enable gating to avoid unnecessary combinational toggles.

The `GatedCounter` has a `clkGatePartitionIndex` which determines a dividing line for the counter to be clock gated such that flops at or above that index will be independently clock gated from the flops below that index. This is an effective method of saving extra power on many counters because the upper bits of the counter may change much less frequently than the lower bits (or vice versa). If the index is negative or greater than or equal to the width of the counter, then the whole counter will be clock gated in unison.

The `gateToggles` flag will enable `ToggleGate` insertion on a per-interface basis to help reduce combinational toggles within the design when interfaces are not enabled.
16 changes: 16 additions & 0 deletions doc/components/toggle_gate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Toggle Gate

The `ToggleGate` component is intended to help save power by avoiding unnecessary toggles through combinational logic. It accomplishes this by flopping the previous value of data and muxing the previous value to the `gatedData` output if the `enable` is low. By default, the flops within the `ToggleGate` are also clock gated for extra power savings, but it can be controlled via a `ClockGateControlInterface`.

As an example use case, if you have a large arithmetic unit but only care about the result when a `valid` bit is high, you could use a `ToggleGate` so that the inputs to that combinational logic do not change unless `valid` is high.

```dart
final toggleGate = ToggleGate(
clk: clk,
reset: reset,
enable: arithmeticDataValid,
data: arithmeticData,
);
BigArithmeticUnit(dataIn: toggleGate.gatedData);
```
1 change: 1 addition & 0 deletions lib/rohd_hcl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ export 'src/serialization/serialization.dart';
export 'src/shift_register.dart';
export 'src/sort.dart';
export 'src/summation/summation.dart';
export 'src/toggle_gate.dart';
export 'src/utils.dart';
56 changes: 45 additions & 11 deletions lib/src/component_config/components/config_summation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -112,24 +112,56 @@ class CounterConfigurator extends SummationConfigurator {
/// The reset value.
final IntConfigKnob resetValueKnob = IntConfigKnob(value: 0);

/// Whether to instantiate a [GatedCounter].
final ToggleConfigKnob clockGatingKnob = ToggleConfigKnob(value: false);

/// The clock gating partition index.
final IntOptionalConfigKnob clockGatingPartitionIndexKnob =
IntOptionalConfigKnob(value: null);

/// The gate toggles knob.
final ToggleConfigKnob gateTogglesKnob = ToggleConfigKnob(value: false);

@override
Map<String, ConfigKnob<dynamic>> get knobs => {
...super.knobs,
'Reset Value': resetValueKnob,
'Clock Gating': clockGatingKnob,
if (clockGatingKnob.value) ...{
'Clock Gating Partition Index': clockGatingPartitionIndexKnob,
'Gate Toggles': gateTogglesKnob,
},
};

@override
Module createModule() => Counter(
sumInterfaceKnobs.knobs
.map((e) => e as SumInterfaceKnob)
.map((e) => SumInterface(
hasEnable: e.hasEnableKnob.value,
fixedAmount:
e.isFixedValueKnob.value ? e.fixedValueKnob.value : null,
width: e.widthKnob.value,
increments: e.incrementsKnob.value,
))
.toList(),
Module createModule() {
final sumIntfs = sumInterfaceKnobs.knobs
.map((e) => e as SumInterfaceKnob)
.map((e) => SumInterface(
hasEnable: e.hasEnableKnob.value,
fixedAmount:
e.isFixedValueKnob.value ? e.fixedValueKnob.value : null,
width: e.widthKnob.value,
increments: e.incrementsKnob.value,
))
.toList();

if (clockGatingKnob.value) {
return GatedCounter(
sumIntfs,
resetValue: resetValueKnob.value,
width: widthKnob.value,
minValue: minValueKnob.value,
maxValue: maxValueKnob.value,
saturates: saturatesKnob.value,
clk: Logic(),
reset: Logic(),
clkGatePartitionIndex: clockGatingPartitionIndexKnob.value,
gateToggles: gateTogglesKnob.value,
);
} else {
return Counter(
sumIntfs,
resetValue: resetValueKnob.value,
width: widthKnob.value,
minValue: minValueKnob.value,
Expand All @@ -138,6 +170,8 @@ class CounterConfigurator extends SummationConfigurator {
clk: Logic(),
reset: Logic(),
);
}
}

@override
String get name => 'Counter';
Expand Down
69 changes: 49 additions & 20 deletions lib/src/summation/counter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
// 2024 August 26
// Author: Max Korbel <[email protected]>

import 'package:meta/meta.dart';
import 'package:rohd/rohd.dart';
import 'package:rohd_hcl/rohd_hcl.dart';
import 'package:rohd_hcl/src/summation/summation_base.dart';
Expand All @@ -17,6 +18,19 @@ class Counter extends SummationBase {
/// The output value of the counter.
Logic get count => output('count');

/// The main clock signal.
@visibleForTesting
@protected
late final Logic clk;

/// The reset signal.
@protected
late final Logic reset;

/// The restart signal.
@protected
late final Logic? restart;

/// Creates a counter that increments according to the provided [interfaces].
///
/// The [width] can be either explicitly provided or inferred from other
Expand Down Expand Up @@ -50,39 +64,54 @@ class Counter extends SummationBase {
super.saturates,
super.name = 'counter',
}) : super(initialValue: resetValue) {
clk = addInput('clk', clk);
reset = addInput('reset', reset);
this.clk = addInput('clk', clk);
this.reset = addInput('reset', reset);

if (restart != null) {
restart = addInput('restart', restart);
this.restart = addInput('restart', restart);
} else {
this.restart = null;
}

addOutput('count', width: width);

final sum = Sum(
interfaces,
initialValue:
restart != null ? mux(restart, initialValueLogic, count) : count,
maxValue: maxValueLogic,
minValue: minValueLogic,
width: width,
saturates: saturates,
);
_buildLogic();
}

/// The internal [Sum] that is used to keep track of the count.
@protected
late final Sum summer = Sum(
interfaces,
initialValue:
restart != null ? mux(restart!, initialValueLogic, count) : count,
maxValue: maxValueLogic,
minValue: minValueLogic,
width: width,
saturates: saturates,
);

/// Builds the internal logic for the counter.
void _buildLogic() {
buildFlops();

// need to flop these since value is flopped
overflowed <= flop(clk, summer.overflowed, reset: reset);
underflowed <= flop(clk, summer.underflowed, reset: reset);

equalsMax <= count.eq(maxValueLogic);
equalsMin <= count.eq(minValueLogic);
}

/// Builds the flops that store the [count].
@protected
void buildFlops() {
count <=
flop(
clk,
sum.sum,
summer.sum,
reset: reset,
resetValue: initialValueLogic,
);

// need to flop these since value is flopped
overflowed <= flop(clk, sum.overflowed, reset: reset);
underflowed <= flop(clk, sum.underflowed, reset: reset);

equalsMax <= count.eq(maxValueLogic);
equalsMin <= count.eq(minValueLogic);
}

/// A simplified constructor for [Counter] that accepts a single fixed amount
Expand Down
Loading

0 comments on commit d8d72f8

Please sign in to comment.