Skip to content

Commit

Permalink
Shift Register Updates (#105)
Browse files Browse the repository at this point in the history
  • Loading branch information
robtorx authored Oct 11, 2024
1 parent 68eb1ad commit a244a54
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 7 deletions.
4 changes: 2 additions & 2 deletions doc/components/shift_register.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ The `ShiftRegister` in ROHD-HCL is a configurable shift register including:
- support for any width data
- a configurable `depth` (which corresponds to the latency)
- an optional `enable`
- an optional `reset`
- if `reset` is provided, an optional `resetValue`
- an optional `reset` (synchronous or asynchronous)
- if `reset` is provided, an optional `resetValue` for all stages or each stage indvidually
- access to each of the `stages` output from each flop
34 changes: 29 additions & 5 deletions lib/src/shift_register.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import 'dart:collection';

import 'package:rohd/rohd.dart';
import 'package:rohd_hcl/rohd_hcl.dart';

/// A shift register with configurable width and depth and optional enable and
/// reset.
Expand Down Expand Up @@ -37,14 +38,18 @@ class ShiftRegister extends Module {
final String dataName;

/// Creates a new shift register with specified [depth] which is only active
/// when [enable]d. If [reset] is provided, it will reset to a default of `0`
/// at all stages synchronously with [clk] or to the provided [resetValue].
/// when [enable]d. If [reset] is provided, it will reset synchronously with
/// [clk] or aynchronously if [asyncReset] is true. The [reset] will reset all
/// stages to a default of `0` or to the provided [resetValue].
/// If [resetValue] is a [List] the stages will reset to the corresponding
/// value in the list.
ShiftRegister(
Logic dataIn, {
required Logic clk,
required this.depth,
Logic? enable,
Logic? reset,
bool asyncReset = false,
dynamic resetValue,
this.dataName = 'data',
}) : width = dataIn.width,
Expand All @@ -55,6 +60,7 @@ class ShiftRegister extends Module {
addOutput('${dataName}_out', width: width);

Map<Logic, dynamic>? resetValues;

if (reset != null) {
reset = addInput('reset', reset);

Expand All @@ -63,6 +69,23 @@ class ShiftRegister extends Module {
resetValue =
addInput('resetValue', resetValue, width: resetValue.width);
}

if (resetValue is List) {
// Check if list length is equal to depth
if (resetValue.length != depth) {
throw RohdHclException(
'ResetValue list length must equal shift register depth.');
}

for (var i = 0; i < resetValue.length; i++) {
final element = resetValue[i];
if (element is Logic) {
resetValue[i] =
addInput('resetValue$i', element, width: element.width);
}
}
}

resetValues = {};
}
}
Expand All @@ -73,7 +96,8 @@ class ShiftRegister extends Module {
for (var i = 0; i < depth; i++) {
final stageI = addOutput(_stageName(i), width: width);
conds.add(stageI < dataStage);
resetValues?[stageI] = resetValue;

resetValues?[stageI] = resetValue is List ? resetValue[i] : resetValue;
dataStage = stageI;
}

Expand All @@ -83,8 +107,8 @@ class ShiftRegister extends Module {
conds = [If(enable, then: conds)];
}

Sequential(
clk,
Sequential.multi(
[clk, if (asyncReset && reset != null) reset],
reset: reset,
resetValues: resetValues,
conds,
Expand Down
109 changes: 109 additions & 0 deletions test/shift_register_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,113 @@ void main() {

await Simulator.endSimulation();
});

group('list reset value shift register', () {
Future<void> listResetTest(
dynamic resetVal, void Function(Logic dataOut) check) async {
final dataIn = Logic(width: 8);
final clk = SimpleClockGenerator(10).clk;
const depth = 5;
final reset = Logic();
final dataOut = ShiftRegister(dataIn,
clk: clk, depth: depth, reset: reset, resetValue: resetVal)
.dataOut;

unawaited(Simulator.run());

dataIn.put(0x45);
reset.put(true);

await clk.nextPosedge;

reset.put(false);

await clk.waitCycles(3);

check(dataOut);

await Simulator.endSimulation();
}

test('list of logics reset value', () async {
await listResetTest([
Logic(width: 8)..put(0x2),
Logic(width: 8)..put(0x10),
Logic(width: 8)..put(0x22),
Logic(width: 8)..put(0x33),
Logic(width: 8)..put(0x42),
], (dataOut) {
expect(dataOut.value.toInt(), 0x10);
});
});

test('list of mixed reset value', () async {
await listResetTest([
Logic(width: 8)..put(0x2),
26,
Logic(width: 8)..put(0x22),
true,
Logic(width: 8)..put(0x42),
], (dataOut) {
expect(dataOut.value.toInt(), 0x1A);
});
});
});

group('async reset shift register', () {
Future<void> asyncResetTest(
dynamic resetVal, void Function(Logic dataOut) check) async {
final dataIn = Logic(width: 8);
final clk = SimpleClockGenerator(10).clk;
const depth = 5;
final reset = Logic();
final dataOut = ShiftRegister(dataIn,
clk: Const(0),
depth: depth,
reset: reset,
resetValue: resetVal,
asyncReset: true)
.dataOut;

unawaited(Simulator.run());

dataIn.put(0x42);

reset.inject(false);

await clk.waitCycles(1);

reset.inject(true);

await clk.waitCycles(1);

check(dataOut);

await Simulator.endSimulation();
}

test('async reset value', () async {
await asyncResetTest(Const(0x78, width: 8), (dataOut) {
expect(dataOut.value.toInt(), 0x78);
});
});

test('async null reset value', () async {
await asyncResetTest(null, (dataOut) {
expect(dataOut.value.toInt(), 0);
});
});

test('async reset with list mixed type', () async {
await asyncResetTest([
Logic(width: 8)..put(0x2),
59,
Const(0x78, width: 8),
Logic(width: 8)..put(0x33),
true,
], (dataOut) {
expect(dataOut.value.toInt(), 0x1);
});
});
});
}

0 comments on commit a244a54

Please sign in to comment.