GenericMultiplyAccumulate constructor
- Logic a,
- Logic b,
- Logic c,
- Multiplier mulGen(}), {
- Adder adderGen(}) = NativeAdder.new,
- String multiplierIdentity = 'native',
- String adderIdentity = 'native',
- Logic? clk,
- Logic? reset,
- Logic? enable,
- dynamic signedMultiplicand,
- dynamic signedMultiplier,
- dynamic signedAddend,
- int? outputWidth,
- String name = 'generic_multiply_accumulate',
- bool reserveName = false,
- bool reserveDefinitionName = false,
- String? definitionName,
Construct a MultiplyAccumulate that multiplies a and b using
mulGen, then adds c using adderGen to produce accumulate.
If clk is not null then a flop latches the final sum. reset and
enable are optional inputs to control that flop when clk is
provided.
The optional outputWidth parameter configures the width of
accumulate, as described in MultiplyAccumulate.
multiplierIdentity and adderIdentity must stably identify the
generated multiplier and adder configurations so automatic definition
names remain unique when custom generators are used.
Implementation
GenericMultiplyAccumulate(
super.a,
super.b,
super.c,
Multiplier Function(Logic a, Logic b,
{dynamic signedMultiplicand, dynamic signedMultiplier})
mulGen, {
Adder Function(Logic a, Logic b, {Logic? carryIn}) adderGen =
NativeAdder.new,
String multiplierIdentity = 'native',
String adderIdentity = 'native',
super.clk,
super.reset,
super.enable,
super.signedMultiplicand,
super.signedMultiplier,
super.signedAddend,
super.outputWidth,
super.name = 'generic_multiply_accumulate',
super.reserveName,
super.reserveDefinitionName,
String? definitionName,
}) : super(
definitionName: definitionName ??
'GenericMultiplyAccumulate_W${a.width}x${b.width}_'
'Acc${c.width}_Out'
'${outputWidth ?? (a.width + b.width + 1)}_'
'Mul${multiplierIdentity}_Add${adderIdentity}_'
'${Multiplier.signedMD(signedMultiplicand)}_'
'${Multiplier.signedML(signedMultiplier)}_'
'${MultiplyAccumulate.signedAD(signedAddend)}') {
// Copy the configuration using this module's internal runtime input.
final multiply = mulGen(a, b,
signedMultiplicand: StaticOrRuntimeParameter(
name: 'selectSignedMultiplicand',
runtimeConfig: signedMultiplicandParameter.tryRuntimeInput(this),
staticConfig: signedMultiplicandParameter.runtimeConfig == null
? signedMultiplicandParameter.staticConfig
: null),
signedMultiplier: StaticOrRuntimeParameter(
name: 'selectSignedMultiplier',
runtimeConfig: signedMultiplierParameter.tryRuntimeInput(this),
staticConfig: signedMultiplierParameter.runtimeConfig == null
? signedMultiplierParameter.staticConfig
: null));
final product = multiply.product;
// The wrapper needs the generated multiplier's signedness metadata.
// ignore: invalid_use_of_protected_member
final productSigned = multiply.isProductSigned;
final addendSigned = selectSignedAddend ?? Const(signedAddend ? 1 : 0);
// Reserve one bit for each operand's possible unsigned-to-signed
// extension, plus one bit for the addition itself. This preserves mixed
// signedness sums such as an unsigned product plus a positive signed
// addend without turning the valid result into a negative value.
final commonWidth = (product.width < c.width ? c.width : product.width) + 2;
final extendedProduct = mux(productSigned, product.signExtend(commonWidth),
product.zeroExtend(commonWidth))
.named('extendedProduct');
final extendedAddend =
mux(addendSigned, c.signExtend(commonWidth), c.zeroExtend(commonWidth))
.named('extendedAddend');
// [Adder] always appends its own extra output bit for an *unsigned*
// carry-out. Since [commonWidth] already provides enough headroom that
// the true sum cannot overflow it, that carry-out is always 0 here, so
// it's dropped: the low `commonWidth` bits alone are the correct
// two's-complement (or unsigned) result at that width. This matters
// because passing the raw, wider `adder.sum` (whose extra top bit is a
// carry flag, not a sign bit) into `fitAccumulateWidth`'s sign-extension
// logic would corrupt negative results when widening further.
final adder = adderGen(extendedProduct, extendedAddend);
final naturalResult =
adder.sum.slice(commonWidth - 1, 0).named('naturalResult');
final rawResult = condFlop(clk, naturalResult, reset: reset, en: enable)
.named('rawResult');
final rawIsAccumulateSigned =
condFlop(clk, isAccumulateSigned, reset: reset, en: enable)
.named('rawIsAccumulateSigned');
accumulate <= fitAccumulateWidth(rawResult, signed: rawIsAccumulateSigned);
}