-
Notifications
You must be signed in to change notification settings - Fork 68
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reset for flops and try ports (#410)
- Loading branch information
Showing
8 changed files
with
342 additions
and
69 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
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 |
---|---|---|
|
@@ -2,7 +2,8 @@ | |
// SPDX-License-Identifier: BSD-3-Clause | ||
// | ||
// conditional.dart | ||
// Definitions of conditionallly executed hardware constructs (if/else statements, always_comb, always_ff, etc.) | ||
// Definitions of conditionallly executed hardware constructs | ||
// (if/else statements, always_comb, always_ff, etc.) | ||
// | ||
// 2021 May 7 | ||
// Author: Max Korbel <[email protected]> | ||
|
@@ -1552,25 +1553,49 @@ ${padding}end '''); | |
|
||
/// Constructs a positive edge triggered flip flop on [clk]. | ||
/// | ||
/// It returns [FlipFlop.q]. When optional [en] is provided, an additional | ||
/// input will be created for flop. If optional [en] is high or not provided, | ||
/// output will vary as per input[d]. For low [en], output remains frozen | ||
/// irrespective of input [d] | ||
Logic flop(Logic clk, Logic d, {Logic? en}) => FlipFlop(clk, d, en: en).q; | ||
/// It returns [FlipFlop.q]. | ||
/// | ||
/// When the optional [en] is provided, an additional input will be created for | ||
/// flop. If optional [en] is high or not provided, output will vary as per | ||
/// input[d]. For low [en], output remains frozen irrespective of input [d]. | ||
/// | ||
/// When the optional [reset] is provided, the flop will be reset (active-high). | ||
/// If no [resetValue] is provided, the reset value is always `0`. Otherwise, | ||
/// it will reset to the provided [resetValue]. | ||
Logic flop( | ||
Logic clk, | ||
Logic d, { | ||
Logic? en, | ||
Logic? reset, | ||
dynamic resetValue, | ||
}) => | ||
FlipFlop( | ||
clk, | ||
d, | ||
en: en, | ||
reset: reset, | ||
resetValue: resetValue, | ||
).q; | ||
|
||
/// Represents a single flip-flop with no reset. | ||
class FlipFlop extends Module with CustomSystemVerilog { | ||
/// Name for the enable input of this flop | ||
late final String _enName; | ||
final String _enName = Module.unpreferredName('en'); | ||
|
||
/// Name for the clk of this flop. | ||
late final String _clkName; | ||
final String _clkName = Module.unpreferredName('clk'); | ||
|
||
/// Name for the input of this flop. | ||
late final String _dName; | ||
final String _dName = Module.unpreferredName('d'); | ||
|
||
/// Name for the output of this flop. | ||
late final String _qName; | ||
final String _qName = Module.unpreferredName('q'); | ||
|
||
/// Name for the reset of this flop. | ||
final String _resetName = Module.unpreferredName('reset'); | ||
|
||
/// Name for the reset value of this flop. | ||
final String _resetValueName = Module.unpreferredName('resetValue'); | ||
|
||
/// The clock, posedge triggered. | ||
late final Logic _clk = input(_clkName); | ||
|
@@ -1580,85 +1605,125 @@ class FlipFlop extends Module with CustomSystemVerilog { | |
/// If enable is high or enable is not provided then flop output will vary | ||
/// on the basis of clock [_clk] and input [_d]. If enable is low, then | ||
/// output of the flop remains frozen irrespective of the input [_d]. | ||
late final Logic _en = input(_enName); | ||
late final Logic? _en = tryInput(_enName); | ||
|
||
/// Optional reset input to the flop. | ||
late final Logic? _reset = tryInput(_resetName); | ||
|
||
/// The input to the flop. | ||
late final Logic _d = input(_dName); | ||
|
||
/// The output of the flop. | ||
late final Logic q = output(_qName); | ||
|
||
/// To track if optional enable is provided or not. | ||
late final bool _isEnableProvided; | ||
/// The reset value for this flop, if it was a port. | ||
Logic? _resetValuePort; | ||
|
||
/// The reset value for this flop, if it was a constant. | ||
/// | ||
/// Only initialized if a constant value is provided. | ||
late LogicValue _resetValueConst; | ||
|
||
/// Constructs a flip flop which is positive edge triggered on [clk]. | ||
/// | ||
/// When optional [en] is provided, an additional input will be created for | ||
/// flop. If optional [en] is high or not provided, output will vary as per | ||
/// input[d]. For low [en], output remains frozen irrespective of input [d] | ||
FlipFlop(Logic clk, Logic d, {Logic? en, super.name = 'flipflop'}) { | ||
/// | ||
/// When the optional [reset] is provided, the flop will be reset active-high. | ||
/// If no [resetValue] is provided, the reset value is always `0`. Otherwise, | ||
/// it will reset to the provided [resetValue]. The type of [resetValue] must | ||
/// be a valid driver of a [ConditionalAssign] (e.g. [Logic], [LogicValue], | ||
/// [int], etc.). | ||
FlipFlop( | ||
Logic clk, | ||
Logic d, { | ||
Logic? en, | ||
Logic? reset, | ||
dynamic resetValue, | ||
super.name = 'flipflop', | ||
}) { | ||
if (clk.width != 1) { | ||
throw Exception('clk must be 1 bit'); | ||
} | ||
|
||
_clkName = Module.unpreferredName('clk'); | ||
_dName = Module.unpreferredName('d'); | ||
_qName = Module.unpreferredName('q'); | ||
|
||
addInput(_clkName, clk); | ||
addInput(_dName, d, width: d.width); | ||
addOutput(_qName, width: d.width); | ||
|
||
if (en != null) { | ||
if (en.width != 1) { | ||
throw PortWidthMismatchException(en, 1); | ||
} | ||
_enName = Module.unpreferredName('en'); | ||
addInput(_enName, en); | ||
_isEnableProvided = true; | ||
} | ||
|
||
_setupWithEnable(); | ||
} else { | ||
_isEnableProvided = false; | ||
if (reset != null) { | ||
addInput(_resetName, reset); | ||
|
||
_setup(); | ||
if (resetValue != null && resetValue is Logic) { | ||
_resetValuePort = addInput(_resetValueName, resetValue, width: d.width); | ||
} else { | ||
_resetValueConst = LogicValue.of(resetValue ?? 0, width: d.width); | ||
} | ||
} | ||
|
||
_setup(); | ||
} | ||
|
||
/// Performs setup for custom functional behavior. | ||
void _setup() { | ||
Sequential(_clk, [q < _d]); | ||
} | ||
var contents = [q < _d]; | ||
|
||
if (_en != null) { | ||
contents = [If(_en!, then: contents)]; | ||
} | ||
|
||
/// Performs setup for custom functional behavior with enable | ||
void _setupWithEnable() { | ||
Sequential(_clk, [ | ||
If(_en, then: [q < _d]) | ||
]); | ||
Sequential( | ||
_clk, | ||
contents, | ||
reset: _reset, | ||
resetValues: | ||
_reset != null ? {q: _resetValuePort ?? _resetValueConst} : null, | ||
); | ||
} | ||
|
||
@override | ||
String instantiationVerilog(String instanceType, String instanceName, | ||
Map<String, String> inputs, Map<String, String> outputs) { | ||
if (_isEnableProvided) { | ||
if (inputs.length != 3 || outputs.length != 1) { | ||
throw Exception('FlipFlop has exactly three inputs and one output.'); | ||
} | ||
} else { | ||
if (inputs.length != 2 || outputs.length != 1) { | ||
throw Exception('FlipFlop has exactly two inputs and one output.'); | ||
} | ||
var expectedInputs = 2; | ||
if (_en != null) { | ||
expectedInputs++; | ||
} | ||
if (_reset != null) { | ||
expectedInputs++; | ||
} | ||
if (_resetValuePort != null) { | ||
expectedInputs++; | ||
} | ||
|
||
if (inputs.length != expectedInputs || outputs.length != 1) { | ||
throw Exception( | ||
'FlipFlop has exactly $expectedInputs inputs and one output.'); | ||
} | ||
|
||
final clk = inputs[_clkName]!; | ||
final d = inputs[_dName]!; | ||
final q = outputs[_qName]!; | ||
|
||
if (_isEnableProvided) { | ||
final en = inputs[_enName]!; | ||
return 'always_ff @(posedge $clk) if($en) $q <= $d; // $instanceName'; | ||
} else { | ||
return 'always_ff @(posedge $clk) $q <= $d; // $instanceName'; | ||
final svBuffer = StringBuffer('always_ff @(posedge $clk) '); | ||
|
||
if (_reset != null) { | ||
final resetValueString = _resetValuePort != null | ||
? inputs[_resetValueName]! | ||
: _resetValueConst.toString(); | ||
svBuffer | ||
.write('if(${inputs[_resetName]}) $q <= $resetValueString; else '); | ||
} | ||
|
||
if (_en != null) { | ||
svBuffer.write('if(${inputs[_enName]!}) '); | ||
} | ||
|
||
svBuffer.write('$q <= $d; // $instanceName'); | ||
|
||
return svBuffer.toString(); | ||
} | ||
} |
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
Oops, something went wrong.