Skip to content
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

Transition to using a different addition syntax for lint avoidance #478

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 90 additions & 4 deletions lib/src/modules/gates.dart
Original file line number Diff line number Diff line change
Expand Up @@ -469,13 +469,99 @@ class Power extends _TwoInputBitwiseGate {
}

/// A two-input addition module.
class Add extends _TwoInputBitwiseGate {
class Add extends Module with CustomSystemVerilog {
/// Name for a first input port of this module.
late final String _in0Name;

/// Name for a second input port of this module.
late final String _in1Name;

/// Name for the output port of this module.
late final String _outName;

/// Name for the carry bit.
///
/// Note that the carry bit is *not* actually driven by anything, this is just
/// a signal generated for lint avoidance as ROHD makes output width the same
/// as input width for addition operations.
late final String _carryName;

/// An input to this gate.
late final Logic _in0 = input(_in0Name);

/// An input to this gate.
late final Logic _in1 = input(_in1Name);

/// The output of this gate.
late final Logic out = output(_outName);

/// The output of this gate.
///
/// Deprecated: use [out] instead.
@Deprecated('Use `out` instead.')
Logic get y => out;

/// The functional operation to perform for this gate.
LogicValue _op(LogicValue in0, LogicValue in1) => in0 + in1;

/// The `String` representing the operation to perform in generated code.
final String _opStr = '+';

/// The width of the inputs and outputs for this operation.
final int width;

/// Calculates the sum of [in0] and [in1].
///
/// [in1] can be either a [Logic] or [int].
Add(Logic in0, dynamic in1, {String name = 'add'})
: super((a, b) => a + b, '+', in0, in1,
name: name, outputSvWidthExpansion: 1);
Add(Logic in0, dynamic in1, {super.name = 'add'}) : width = in0.width {
if (in1 is Logic && in0.width != in1.width) {
throw PortWidthMismatchException.equalWidth(in0, in1);
}

final in1Logic = in1 is Logic ? in1 : Const(in1, width: width);

_in0Name = Naming.unpreferredName('in0_${in0.name}');
_in1Name = Naming.unpreferredName('in1_${in1Logic.name}');
_outName = Naming.unpreferredName('${in0.name}_${name}_${in1Logic.name}');
_carryName = Naming.unpreferredName('carry_$_outName');

addInput(_in0Name, in0, width: width);
addInput(_in1Name, in1Logic, width: width);
addOutput(_outName, width: width);
addOutput(_carryName); // just for SV generation, not used

_setup();
}

/// Performs setup steps for custom functional behavior.
void _setup() {
_execute(); // for initial values
_in0.glitch.listen((args) {
_execute();
});
_in1.glitch.listen((args) {
_execute();
});
}

/// Executes the functional behavior of this gate.
void _execute() {
out.put(_op(_in0.value, _in1.value));
}

@override
String instantiationVerilog(String instanceType, String instanceName,
Map<String, String> inputs, Map<String, String> outputs) {
assert(inputs.length == 2, 'Gate has exactly two inputs');
assert(outputs.length == 2, 'Gate has exactly two outputs');

final in0 = inputs[_in0Name]!;
final in1 = inputs[_in1Name]!;
final out = outputs[_outName]!;
final carry = outputs[_carryName]!;

return 'assign {$carry, $out} = $in0 $_opStr $in1;';
}
}

/// A two-input subtraction module.
Expand Down
10 changes: 0 additions & 10 deletions test/math_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,6 @@ void main() {
final sv = gtm.generateSynth();
final lines = sv.split('\n');

// should never assign directly off a +
expect(lines.where(RegExp(r'plus.*\+').hasMatch), isEmpty);

// ensure the width of intermediate signals appropriate for add
for (final line in lines) {
if (RegExp('logic.*a_add').hasMatch(line)) {
expect(line, contains('8:0'));
}
}

// ensure we never lshift by a constant directly
for (final line in lines) {
if (RegExp('assign.*a_sl_const.*=').hasMatch(line)) {
Expand Down
Loading