mirror of https://github.com/YosysHQ/yosys.git
91 lines
2.4 KiB
Plaintext
91 lines
2.4 KiB
Plaintext
pattern muldiv_c
|
|
//
|
|
// Authored by Akash Levy and Alain Dargelas of Silimate, Inc. under ISC license.
|
|
// Transforms mul->div into const->mul when b and c are divisible constants:
|
|
// y = (a * b_const) / c_const ===> a * eval(b_const / c_const)
|
|
//
|
|
|
|
state <SigSpec> a b_const mul_y
|
|
|
|
match mul
|
|
// Select multiplier
|
|
select mul->type == $mul
|
|
endmatch
|
|
|
|
code a b_const mul_y
|
|
// Get multiplier signals
|
|
a = port(mul, \A);
|
|
b_const = port(mul, \B);
|
|
mul_y = port(mul, \Y);
|
|
|
|
// Fanout of each multiplier Y bit should be 1 (no bit-split)
|
|
if (nusers(mul_y) != 2)
|
|
reject;
|
|
|
|
// A and B can be interchanged
|
|
branch;
|
|
std::swap(a, b_const);
|
|
endcode
|
|
|
|
match div
|
|
// Select div of form (a * b_const) / c_const
|
|
select div->type == $div
|
|
|
|
// Check that b_const and c_const is constant
|
|
filter b_const.is_fully_const()
|
|
filter port(div, \B).is_fully_const()
|
|
index <SigSpec> remove_bottom_padding(port(div, \A)) === mul_y
|
|
endmatch
|
|
|
|
code
|
|
// Get div signals
|
|
SigSpec div_a = port(div, \A);
|
|
SigSpec c_const = port(div, \B);
|
|
SigSpec div_y = port(div, \Y);
|
|
|
|
// Get offset of multiplier result chunk in divider
|
|
int offset = GetSize(div_a) - GetSize(mul_y);
|
|
|
|
// Get properties and values of b_const and c_const
|
|
int b_const_width = mul->getParam(ID::B_WIDTH).as_int();
|
|
bool b_const_signed = mul->getParam(ID::B_SIGNED).as_bool();
|
|
bool c_const_signed = div->getParam(ID::B_SIGNED).as_bool();
|
|
int b_const_int = b_const.as_int(b_const_signed);
|
|
int c_const_int = c_const.as_int(c_const_signed);
|
|
int b_const_int_shifted = b_const_int << offset;
|
|
|
|
if (mul->getParam(ID::B_WIDTH).size() > 64)
|
|
reject;
|
|
if (b_const.size() > 64)
|
|
reject;
|
|
if (c_const.size() > 64)
|
|
reject;
|
|
|
|
// Check that there are only zeros before offset
|
|
if (offset < 0 || !div_a.extract(0, offset).is_fully_zero())
|
|
reject;
|
|
|
|
// Check that b is divisible by c
|
|
if (b_const_int_shifted % c_const_int != 0)
|
|
reject;
|
|
|
|
// Check that every single output bit of the multiplier is connected consecutively to the div operator (offset accounted for)
|
|
for (int i = 0; i < mul_y.size(); i++) {
|
|
if (sigmap(mul_y[i]) != sigmap(div_a[i + offset])) {
|
|
reject;
|
|
}
|
|
}
|
|
|
|
// Rewire to only keep multiplier
|
|
mul->setPort(\B, Const(b_const_int_shifted / c_const_int, b_const_width));
|
|
mul->setPort(\Y, div_y);
|
|
|
|
// Remove divider
|
|
autoremove(div);
|
|
|
|
// Log, fixup, accept
|
|
log("muldiv_const pattern in %s: mul=%s, div=%s\n", log_id(module), log_id(mul), log_id(div));
|
|
mul->fixup_parameters();
|
|
accept;
|
|
endcode
|