-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adds linear feedback shift register component #108
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
// Copyright (C) 2023 Intel Corporation | ||
|
||
// SPDX-License-Identifier: BSD-3-Clause | ||
|
||
// | ||
|
||
// linear_feedback_shift_register.dart | ||
|
||
// Implementation of Galois Linear Feedback Shift Register. | ||
|
||
// | ||
|
||
// 2024 October 1 | ||
|
||
// Author: Omonefe Itietie <[email protected]> | ||
|
||
// | ||
|
||
import 'dart:collection'; | ||
import 'package:rohd/rohd.dart'; | ||
|
||
/// Galois Linear Feedback Shift Register | ||
class LinearFeedbackShiftRegister extends Module { | ||
/// Contains polynomial size for LFSR | ||
final int width; | ||
|
||
/// Contains seed of LFSR (starting value) | ||
Logic state; | ||
|
||
/// Data names for signals | ||
final String dataName; | ||
|
||
/// Contains bit string that will be used to calculate the output | ||
final Logic taps; | ||
|
||
/// Output for shift register | ||
Logic get dataOut => output('${dataName}_out'); | ||
|
||
/// The number of stages in this shift register. | ||
final int shifts; | ||
|
||
/// A [List] of [output]s where the `n`'th entry corresponds to a version of | ||
/// the input data after passing through `n + 1` flops. | ||
late final List<Logic> stages = UnmodifiableListView( | ||
[for (var i = 0; i < shifts; i++) output(_stageName(i))]); | ||
|
||
/// The name of the signal (and output pin) for the [i]th stage. | ||
String _stageName(int i) => '${dataName}_stage_$i'; | ||
|
||
LinearFeedbackShiftRegister(Logic dataIn, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add a doc comment to the constructor |
||
{required Logic clk, | ||
required this.state, | ||
required this.shifts, | ||
required this.taps, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Careful using |
||
Logic? enable, | ||
Logic? reset, | ||
dynamic resetValue, | ||
this.dataName = 'data'}) | ||
: width = dataIn.width, | ||
super(name: '${dataName}_lfsr') { | ||
dataIn = addInput('${dataName}_in', dataIn, width: width); | ||
clk = addInput('clk', clk); | ||
addOutput('${dataName}_out', width: width); | ||
|
||
Map<Logic, dynamic>? resetValues; | ||
|
||
if (reset != null) { | ||
reset = addInput('reset', reset); | ||
if (resetValue != null) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the original shift register was recently upgraded to allow for a |
||
if (resetValue is Logic) { | ||
resetValue = | ||
addInput('resetValue', resetValue, width: resetValue.width); | ||
} | ||
resetValues = {}; | ||
} | ||
} | ||
|
||
var dataStage = dataIn; | ||
var conds = <Conditional>[]; | ||
|
||
// Create the LFSR logic for each shift stage | ||
for (var i = 0; i < shifts; i++) { | ||
final stageI = addOutput(_stageName(i), width: width); | ||
|
||
conds.add(stageI < dataStage); | ||
resetValues?[stageI] = resetValue; | ||
|
||
Logic lsb = state.getRange(0, 1); // Get LSB (least significant bit) | ||
state = [Const(0, width: 1), state.getRange(1, width)].swizzle(); | ||
|
||
If(lsb.eq(Const(1)), then: [ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This |
||
state < state ^ taps // Perform XOR and assign back to state | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If |
||
]); | ||
|
||
dataStage = stageI; | ||
} | ||
|
||
// Enable logic if needed | ||
if (enable != null) { | ||
enable = addInput('enable', enable); | ||
conds = [If(enable, then: conds)]; | ||
} | ||
|
||
// Sequential logic block | ||
Sequential( | ||
clk, | ||
reset: reset, | ||
resetValues: resetValues, | ||
conds, | ||
); | ||
// Connect the final stage to the output | ||
dataOut <= dataStage; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
// | ||
// linear_feedback_shift_register_test.dart | ||
// Tests for linear feedback shift register | ||
// | ||
// 2024 October 1 | ||
// Author: Omonefe Itietie <[email protected]> | ||
|
||
import 'dart:async'; | ||
|
||
import 'package:rohd/rohd.dart'; | ||
import 'package:rohd_hcl/src/linear_feedback_shift_register.dart'; | ||
import 'package:rohd_vf/rohd_vf.dart'; | ||
import 'package:test/test.dart'; | ||
|
||
void main() { | ||
tearDown(() async { | ||
await Simulator.reset(); | ||
}); | ||
test('Test LFSR creation', () async { | ||
final dataIn = Logic(width: 4)..put(bin('1000')); // initial state | ||
final clk = SimpleClockGenerator(6).clk; | ||
final state = Logic(width: 4)..put(bin('1000')); | ||
const shifts = 6; | ||
final taps = Logic(width: 4)..put(bin('1010')); // tap positions | ||
final lfsr = LinearFeedbackShiftRegister(dataIn, | ||
clk: clk, state: state, shifts: shifts, taps: taps); | ||
|
||
final dataOut = lfsr.dataOut; | ||
|
||
await lfsr.build(); | ||
|
||
final expectedData = [8, 12, 6, 3, 9, 4, 2, 1]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how did you determine the expected values? |
||
|
||
unawaited(Simulator.run()); | ||
await clk.waitCycles(5); | ||
|
||
for (var i = 0; i < expectedData.length; i++) { | ||
unawaited(clk | ||
.waitCycles(1) | ||
.then((value) => expect(dataOut.value.toInt(), expectedData[i]))); | ||
} | ||
|
||
await Simulator.endSimulation(); | ||
}); | ||
|
||
test('Test LFSR naming', () async { | ||
final lfsr = LinearFeedbackShiftRegister(Logic(), | ||
clk: Logic(), | ||
state: Logic(), | ||
shifts: 2, | ||
taps: Logic(), | ||
dataName: 'test'); | ||
|
||
expect(lfsr.name, contains('test')); | ||
expect(lfsr.dataOut.name, contains('test')); | ||
expect( | ||
// ignore: invalid_use_of_protected_member | ||
lfsr.inputs.keys.where((element) => element.contains('test')).length, | ||
1); | ||
}); | ||
|
||
test('Test LFSR with 0 initial state and 0 taps returns as 0', () async { | ||
final dataIn = Logic(width: 4)..put(bin('0000')); // initial state | ||
final clk = SimpleClockGenerator(6).clk; | ||
final state = Logic(width: 4)..put(bin('0000')); | ||
const shifts = 6; | ||
final taps = Logic(width: 4)..put(bin('0000')); // tap positions | ||
final lfsr = LinearFeedbackShiftRegister(dataIn, | ||
clk: clk, state: state, shifts: shifts, taps: taps); | ||
|
||
final dataOut = lfsr.dataOut; | ||
|
||
await lfsr.build(); | ||
|
||
final expectedData = [0, 0, 0, 0]; | ||
|
||
unawaited(Simulator.run()); | ||
await clk.waitCycles(5); | ||
|
||
for (var i = 0; i < expectedData.length; i++) { | ||
unawaited(clk | ||
.waitCycles(1) | ||
.then((value) => expect(dataOut.value.toInt(), expectedData[i]))); | ||
} | ||
|
||
await Simulator.endSimulation(); | ||
}); | ||
|
||
test('Test LFSR with enable signal and reset', () async { | ||
final dataIn = Logic(width: 4)..put(bin('1110')); | ||
final clk = SimpleClockGenerator(6).clk; | ||
final state = Logic(width: 4)..put(bin('1110')); | ||
final enable = Logic(); // Create the enable signal | ||
final reset = Logic(); // Create a reset signal | ||
const shifts = 6; | ||
final taps = Logic(width: 4)..put(bin('1010')); | ||
|
||
final lfsr = LinearFeedbackShiftRegister(dataIn, | ||
clk: clk, | ||
state: state, | ||
shifts: shifts, | ||
taps: taps, | ||
enable: enable, | ||
reset: reset); | ||
|
||
final dataOut = lfsr.dataOut; | ||
|
||
await lfsr.build(); | ||
|
||
final expectedData = [0, 0, 0, 0, 0, 14]; | ||
|
||
unawaited(Simulator.run()); | ||
|
||
// Apply reset | ||
reset.put(1); | ||
await clk.nextPosedge; // Wait for reset to propagate | ||
reset.put(0); // Remove reset | ||
|
||
// Apply enable | ||
enable.put(1); | ||
|
||
for (var i = 0; i < expectedData.length; i++) { | ||
await clk.nextPosedge; | ||
expect( | ||
dataOut.value.toInt(), expectedData[i]); // Check output when enabled | ||
} | ||
|
||
await Simulator.endSimulation(); | ||
}); | ||
|
||
test('Test LFSR with reset value', () async { | ||
final dataIn = Logic(width: 4)..put(bin('1010')); | ||
final clk = SimpleClockGenerator(6).clk; | ||
final state = Logic(width: 4)..put(bin('1010')); | ||
final reset = Logic(); // Create a reset signal | ||
const shifts = 6; | ||
final taps = Logic(width: 4)..put(bin('1000')); | ||
|
||
final lfsr = LinearFeedbackShiftRegister(dataIn, | ||
clk: clk, state: state, shifts: shifts, taps: taps, reset: reset); | ||
|
||
final dataOut = lfsr.dataOut; | ||
|
||
await lfsr.build(); | ||
|
||
final expectedData = [0, 0, 0, 0, 0, 0, 0]; | ||
|
||
unawaited(Simulator.run()); | ||
|
||
// Apply reset | ||
reset.put(1); | ||
await clk.nextPosedge; // Wait for reset to propagate | ||
|
||
for (var i = 0; i < expectedData.length; i++) { | ||
await clk.nextPosedge; | ||
expect( | ||
dataOut.value.toInt(), expectedData[i]); // Check output when enabled | ||
} | ||
|
||
await Simulator.endSimulation(); | ||
}); | ||
|
||
test('Test Enabled LFSR', () async { | ||
final dataIn = Logic(width: 4)..put(bin('1110')); | ||
final clk = SimpleClockGenerator(6).clk; | ||
final state = Logic(width: 4)..put(bin('1110')); | ||
final enable = Logic(); // Create the enable signal | ||
const shifts = 6; | ||
final taps = Logic(width: 4)..put(bin('1110')); | ||
|
||
final lfsr = LinearFeedbackShiftRegister(dataIn, | ||
clk: clk, state: state, shifts: shifts, taps: taps, enable: enable); | ||
|
||
final dataOut = lfsr.dataOut; | ||
|
||
await lfsr.build(); | ||
|
||
final expectedData = [14, 7, 12, 6, 3]; | ||
|
||
unawaited(Simulator.run()); | ||
|
||
// Apply enable | ||
enable.put(1); | ||
await clk.waitCycles(5); | ||
|
||
for (var i = 0; i < expectedData.length; i++) { | ||
unawaited(clk | ||
.waitCycles(1) | ||
.then((value) => expect(dataOut.value.toInt(), expectedData[i]))); | ||
} | ||
|
||
await Simulator.endSimulation(); | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove blank (uncommented) lines in the header?