mirror of https://github.com/YosysHQ/yosys.git
Merge pull request #3873 from povik/peepopt-work
This commit is contained in:
commit
edee11bcc1
|
@ -42,7 +42,8 @@ GENFILES += passes/pmgen/peepopt_pm.h
|
||||||
passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h
|
passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h
|
||||||
$(eval $(call add_extra_objs,passes/pmgen/peepopt_pm.h))
|
$(eval $(call add_extra_objs,passes/pmgen/peepopt_pm.h))
|
||||||
|
|
||||||
PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul.pmg
|
PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul_right.pmg
|
||||||
|
PEEPOPT_PATTERN += passes/pmgen/peepopt_shiftmul_left.pmg
|
||||||
PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg
|
PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg
|
||||||
|
|
||||||
passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
|
passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
|
||||||
|
|
|
@ -212,7 +212,7 @@ second argument, and the matcher will iterate over those options:
|
||||||
index <SigSpec> port(eq, BA) === bar
|
index <SigSpec> port(eq, BA) === bar
|
||||||
set eq_ab AB
|
set eq_ab AB
|
||||||
set eq_ba BA
|
set eq_ba BA
|
||||||
generate
|
endmatch
|
||||||
|
|
||||||
Notice how `define` can be used to define additional local variables similar
|
Notice how `define` can be used to define additional local variables similar
|
||||||
to the loop variables defined by `slice` and `choice`.
|
to the loop variables defined by `slice` and `choice`.
|
||||||
|
|
|
@ -24,11 +24,8 @@ USING_YOSYS_NAMESPACE
|
||||||
PRIVATE_NAMESPACE_BEGIN
|
PRIVATE_NAMESPACE_BEGIN
|
||||||
|
|
||||||
bool did_something;
|
bool did_something;
|
||||||
dict<SigBit, State> initbits;
|
|
||||||
pool<SigBit> rminitbits;
|
|
||||||
|
|
||||||
#include "passes/pmgen/peepopt_pm.h"
|
#include "passes/pmgen/peepopt_pm.h"
|
||||||
#include "generate.h"
|
|
||||||
|
|
||||||
struct PeepoptPass : public Pass {
|
struct PeepoptPass : public Pass {
|
||||||
PeepoptPass() : Pass("peepopt", "collection of peephole optimizers") { }
|
PeepoptPass() : Pass("peepopt", "collection of peephole optimizers") { }
|
||||||
|
@ -40,38 +37,29 @@ struct PeepoptPass : public Pass {
|
||||||
log("\n");
|
log("\n");
|
||||||
log("This pass applies a collection of peephole optimizers to the current design.\n");
|
log("This pass applies a collection of peephole optimizers to the current design.\n");
|
||||||
log("\n");
|
log("\n");
|
||||||
|
log("This pass employs the following rules:\n");
|
||||||
|
log("\n");
|
||||||
|
log(" * muldiv - Replace (A*B)/B with A\n");
|
||||||
|
log("\n");
|
||||||
|
log(" * shiftmul - Replace A>>(B*C) with A'>>(B<<K) where C and K are constants\n");
|
||||||
|
log(" and A' is derived from A by appropriately inserting padding\n");
|
||||||
|
log(" into the signal. (right variant)\n");
|
||||||
|
log("\n");
|
||||||
|
log(" Analogously, replace A<<(B*C) with appropriate selection of\n");
|
||||||
|
log(" output bits from A<<(B<<K). (left variant)\n");
|
||||||
|
log("\n");
|
||||||
}
|
}
|
||||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||||
{
|
{
|
||||||
std::string genmode;
|
|
||||||
|
|
||||||
log_header(design, "Executing PEEPOPT pass (run peephole optimizers).\n");
|
log_header(design, "Executing PEEPOPT pass (run peephole optimizers).\n");
|
||||||
|
|
||||||
size_t argidx;
|
size_t argidx;
|
||||||
for (argidx = 1; argidx < args.size(); argidx++)
|
for (argidx = 1; argidx < args.size(); argidx++)
|
||||||
{
|
{
|
||||||
if (args[argidx] == "-generate" && argidx+1 < args.size()) {
|
|
||||||
genmode = args[++argidx];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
|
||||||
if (!genmode.empty())
|
|
||||||
{
|
|
||||||
initbits.clear();
|
|
||||||
rminitbits.clear();
|
|
||||||
|
|
||||||
if (genmode == "shiftmul")
|
|
||||||
GENERATE_PATTERN(peepopt_pm, shiftmul);
|
|
||||||
else if (genmode == "muldiv")
|
|
||||||
GENERATE_PATTERN(peepopt_pm, muldiv);
|
|
||||||
else
|
|
||||||
log_abort();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto module : design->selected_modules())
|
for (auto module : design->selected_modules())
|
||||||
{
|
{
|
||||||
did_something = true;
|
did_something = true;
|
||||||
|
@ -79,47 +67,14 @@ struct PeepoptPass : public Pass {
|
||||||
while (did_something)
|
while (did_something)
|
||||||
{
|
{
|
||||||
did_something = false;
|
did_something = false;
|
||||||
initbits.clear();
|
|
||||||
rminitbits.clear();
|
|
||||||
|
|
||||||
peepopt_pm pm(module);
|
peepopt_pm pm(module);
|
||||||
|
|
||||||
for (auto w : module->wires()) {
|
|
||||||
auto it = w->attributes.find(ID::init);
|
|
||||||
if (it != w->attributes.end()) {
|
|
||||||
SigSpec sig = pm.sigmap(w);
|
|
||||||
Const val = it->second;
|
|
||||||
int len = std::min(GetSize(sig), GetSize(val));
|
|
||||||
for (int i = 0; i < len; i++) {
|
|
||||||
if (sig[i].wire == nullptr)
|
|
||||||
continue;
|
|
||||||
if (val[i] != State::S0 && val[i] != State::S1)
|
|
||||||
continue;
|
|
||||||
initbits[sig[i]] = val[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pm.setup(module->selected_cells());
|
pm.setup(module->selected_cells());
|
||||||
|
|
||||||
pm.run_shiftmul();
|
pm.run_shiftmul_right();
|
||||||
|
pm.run_shiftmul_left();
|
||||||
pm.run_muldiv();
|
pm.run_muldiv();
|
||||||
|
|
||||||
for (auto w : module->wires()) {
|
|
||||||
auto it = w->attributes.find(ID::init);
|
|
||||||
if (it != w->attributes.end()) {
|
|
||||||
SigSpec sig = pm.sigmap(w);
|
|
||||||
Const &val = it->second;
|
|
||||||
int len = std::min(GetSize(sig), GetSize(val));
|
|
||||||
for (int i = 0; i < len; i++) {
|
|
||||||
if (rminitbits.count(sig[i]))
|
|
||||||
val[i] = State::Sx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
initbits.clear();
|
|
||||||
rminitbits.clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,92 +0,0 @@
|
||||||
pattern shiftmul
|
|
||||||
//
|
|
||||||
// Optimize mul+shift pairs that result from expressions such as foo[s*W+:W]
|
|
||||||
//
|
|
||||||
|
|
||||||
state <SigSpec> shamt
|
|
||||||
|
|
||||||
match shift
|
|
||||||
select shift->type.in($shift, $shiftx, $shr)
|
|
||||||
endmatch
|
|
||||||
|
|
||||||
code shamt
|
|
||||||
shamt = port(shift, \B);
|
|
||||||
if (shamt.empty())
|
|
||||||
reject;
|
|
||||||
if (shamt[GetSize(shamt)-1] == State::S0) {
|
|
||||||
do {
|
|
||||||
shamt.remove(GetSize(shamt)-1);
|
|
||||||
if (shamt.empty())
|
|
||||||
reject;
|
|
||||||
} while (shamt[GetSize(shamt)-1] == State::S0);
|
|
||||||
} else
|
|
||||||
if (shift->type.in($shift, $shiftx) && param(shift, \B_SIGNED).as_bool()) {
|
|
||||||
reject;
|
|
||||||
}
|
|
||||||
if (GetSize(shamt) > 20)
|
|
||||||
reject;
|
|
||||||
endcode
|
|
||||||
|
|
||||||
match mul
|
|
||||||
select mul->type.in($mul)
|
|
||||||
select port(mul, \A).is_fully_const() || port(mul, \B).is_fully_const()
|
|
||||||
index <SigSpec> port(mul, \Y) === shamt
|
|
||||||
filter !param(mul, \A_SIGNED).as_bool()
|
|
||||||
endmatch
|
|
||||||
|
|
||||||
code
|
|
||||||
{
|
|
||||||
IdString const_factor_port = port(mul, \A).is_fully_const() ? \A : \B;
|
|
||||||
Const const_factor_cnst = port(mul, const_factor_port).as_const();
|
|
||||||
int const_factor = const_factor_cnst.as_int();
|
|
||||||
|
|
||||||
if (GetSize(const_factor_cnst) == 0)
|
|
||||||
reject;
|
|
||||||
|
|
||||||
if (GetSize(const_factor_cnst) > 20)
|
|
||||||
reject;
|
|
||||||
|
|
||||||
if (GetSize(port(shift, \Y)) > const_factor)
|
|
||||||
reject;
|
|
||||||
|
|
||||||
int factor_bits = ceil_log2(const_factor);
|
|
||||||
SigSpec mul_din = port(mul, const_factor_port == \A ? \B : \A);
|
|
||||||
|
|
||||||
if (GetSize(shamt) < factor_bits+GetSize(mul_din))
|
|
||||||
reject;
|
|
||||||
|
|
||||||
did_something = true;
|
|
||||||
log("shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul));
|
|
||||||
|
|
||||||
int new_const_factor = 1 << factor_bits;
|
|
||||||
SigSpec padding(State::Sx, new_const_factor-const_factor);
|
|
||||||
SigSpec old_a = port(shift, \A), new_a;
|
|
||||||
int trunc = 0;
|
|
||||||
|
|
||||||
if (GetSize(old_a) % const_factor != 0) {
|
|
||||||
trunc = const_factor - GetSize(old_a) % const_factor;
|
|
||||||
old_a.append(SigSpec(State::Sx, trunc));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i*const_factor < GetSize(old_a); i++) {
|
|
||||||
SigSpec slice = old_a.extract(i*const_factor, const_factor);
|
|
||||||
new_a.append(slice);
|
|
||||||
new_a.append(padding);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trunc > 0)
|
|
||||||
new_a.remove(GetSize(new_a)-trunc, trunc);
|
|
||||||
|
|
||||||
SigSpec new_b = {mul_din, SigSpec(State::S0, factor_bits)};
|
|
||||||
if (param(shift, \B_SIGNED).as_bool())
|
|
||||||
new_b.append(State::S0);
|
|
||||||
|
|
||||||
shift->setPort(\A, new_a);
|
|
||||||
shift->setParam(\A_WIDTH, GetSize(new_a));
|
|
||||||
shift->setPort(\B, new_b);
|
|
||||||
shift->setParam(\B_WIDTH, GetSize(new_b));
|
|
||||||
|
|
||||||
blacklist(shift);
|
|
||||||
accept;
|
|
||||||
}
|
|
||||||
endcode
|
|
|
@ -0,0 +1,160 @@
|
||||||
|
pattern shiftmul_left
|
||||||
|
//
|
||||||
|
// Optimize mul+shift pairs that result from expressions such as foo[s*W+:W]
|
||||||
|
//
|
||||||
|
|
||||||
|
match shift
|
||||||
|
select shift->type.in($shift, $shiftx, $shl)
|
||||||
|
select shift->type.in($shl) || param(shift, \B_SIGNED).as_bool()
|
||||||
|
filter !port(shift, \B).empty()
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
match neg
|
||||||
|
if shift->type.in($shift, $shiftx)
|
||||||
|
select neg->type == $neg
|
||||||
|
index <SigSpec> port(neg, \Y) === port(shift, \B)
|
||||||
|
filter !port(shift, \A).empty()
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
// the left shift amount
|
||||||
|
state <SigSpec> shift_amount
|
||||||
|
// log2 scale factor in interpreting of shift_amount
|
||||||
|
// due to zero padding on the shift cell's B port
|
||||||
|
state <int> log2scale
|
||||||
|
|
||||||
|
code shift_amount log2scale
|
||||||
|
if (neg) {
|
||||||
|
// case of `$shift`, `$shiftx`
|
||||||
|
shift_amount = port(neg, \A);
|
||||||
|
if (!param(neg, \A_SIGNED).as_bool())
|
||||||
|
shift_amount.append(State::S0);
|
||||||
|
} else {
|
||||||
|
// case of `$shl`
|
||||||
|
shift_amount = port(shift, \B);
|
||||||
|
if (!param(shift, \B_SIGNED).as_bool())
|
||||||
|
shift_amount.append(State::S0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// at this point shift_amount is signed, make
|
||||||
|
// sure we can never go negative
|
||||||
|
if (shift_amount.bits().back() != State::S0)
|
||||||
|
reject;
|
||||||
|
|
||||||
|
while (shift_amount.bits().back() == State::S0) {
|
||||||
|
shift_amount.remove(GetSize(shift_amount) - 1);
|
||||||
|
if (shift_amount.empty()) reject;
|
||||||
|
}
|
||||||
|
|
||||||
|
log2scale = 0;
|
||||||
|
while (shift_amount[0] == State::S0) {
|
||||||
|
shift_amount.remove(0);
|
||||||
|
if (shift_amount.empty()) reject;
|
||||||
|
log2scale++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetSize(shift_amount) > 20)
|
||||||
|
reject;
|
||||||
|
endcode
|
||||||
|
|
||||||
|
state <SigSpec> mul_din
|
||||||
|
state <Const> mul_const
|
||||||
|
|
||||||
|
match mul
|
||||||
|
select mul->type.in($mul)
|
||||||
|
index <SigSpec> port(mul, \Y) === shift_amount
|
||||||
|
filter !param(mul, \A_SIGNED).as_bool()
|
||||||
|
|
||||||
|
choice <IdString> constport {\A, \B}
|
||||||
|
filter port(mul, constport).is_fully_const()
|
||||||
|
|
||||||
|
define <IdString> varport (constport == \A ? \B : \A)
|
||||||
|
set mul_const SigSpec({port(mul, constport), SigSpec(State::S0, log2scale)}).as_const()
|
||||||
|
// get mul_din unmapped (so no `port()` shorthand)
|
||||||
|
// because we will be using it to set the \A port
|
||||||
|
// on the shift cell, and we want to stay close
|
||||||
|
// to the original design
|
||||||
|
set mul_din mul->getPort(varport)
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code
|
||||||
|
{
|
||||||
|
if (mul_const.empty() || GetSize(mul_const) > 20)
|
||||||
|
reject;
|
||||||
|
|
||||||
|
// make sure there's no overlap in the signal
|
||||||
|
// selections by the shiftmul pattern
|
||||||
|
if (GetSize(port(shift, \A)) > mul_const.as_int())
|
||||||
|
reject;
|
||||||
|
|
||||||
|
int factor_bits = ceil_log2(mul_const.as_int());
|
||||||
|
// make sure the multiplication never wraps around
|
||||||
|
if (GetSize(shift_amount) < factor_bits + GetSize(mul_din))
|
||||||
|
reject;
|
||||||
|
|
||||||
|
if (neg) {
|
||||||
|
// make sure the negation never wraps around
|
||||||
|
if (GetSize(port(shift, \B)) < factor_bits + GetSize(mul_din)
|
||||||
|
+ log2scale + 1)
|
||||||
|
reject;
|
||||||
|
}
|
||||||
|
|
||||||
|
did_something = true;
|
||||||
|
log("left shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul));
|
||||||
|
|
||||||
|
int const_factor = mul_const.as_int();
|
||||||
|
int new_const_factor = 1 << factor_bits;
|
||||||
|
SigSpec padding(State::Sm, new_const_factor-const_factor);
|
||||||
|
SigSpec old_y = port(shift, \Y), new_y;
|
||||||
|
int trunc = 0;
|
||||||
|
|
||||||
|
if (GetSize(old_y) % const_factor != 0) {
|
||||||
|
trunc = const_factor - GetSize(old_y) % const_factor;
|
||||||
|
old_y.append(SigSpec(State::Sm, trunc));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i*const_factor < GetSize(old_y); i++) {
|
||||||
|
SigSpec slice = old_y.extract(i*const_factor, const_factor);
|
||||||
|
new_y.append(slice);
|
||||||
|
new_y.append(padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trunc > 0)
|
||||||
|
new_y.remove(GetSize(new_y)-trunc, trunc);
|
||||||
|
|
||||||
|
{
|
||||||
|
// Now replace occurences of Sm in new_y with bits
|
||||||
|
// of a dummy wire
|
||||||
|
int padbits = 0;
|
||||||
|
for (auto bit : new_y)
|
||||||
|
if (bit == SigBit(State::Sm))
|
||||||
|
padbits++;
|
||||||
|
|
||||||
|
SigSpec padwire = module->addWire(NEW_ID, padbits);
|
||||||
|
|
||||||
|
for (int i = new_y.size() - 1; i >= 0; i--)
|
||||||
|
if (new_y[i] == SigBit(State::Sm)) {
|
||||||
|
new_y[i] = padwire.bits().back();
|
||||||
|
padwire.remove(padwire.size() - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SigSpec new_b = {mul_din, SigSpec(State::S0, factor_bits)};
|
||||||
|
|
||||||
|
shift->setPort(\Y, new_y);
|
||||||
|
shift->setParam(\Y_WIDTH, GetSize(new_y));
|
||||||
|
if (shift->type == $shl) {
|
||||||
|
if (param(shift, \B_SIGNED).as_bool())
|
||||||
|
new_b.append(State::S0);
|
||||||
|
shift->setPort(\B, new_b);
|
||||||
|
shift->setParam(\B_WIDTH, GetSize(new_b));
|
||||||
|
} else {
|
||||||
|
SigSpec b_neg = module->addWire(NEW_ID, GetSize(new_b) + 1);
|
||||||
|
module->addNeg(NEW_ID, new_b, b_neg);
|
||||||
|
shift->setPort(\B, b_neg);
|
||||||
|
shift->setParam(\B_WIDTH, GetSize(b_neg));
|
||||||
|
}
|
||||||
|
|
||||||
|
blacklist(shift);
|
||||||
|
accept;
|
||||||
|
}
|
||||||
|
endcode
|
|
@ -0,0 +1,113 @@
|
||||||
|
pattern shiftmul_right
|
||||||
|
//
|
||||||
|
// Optimize mul+shift pairs that result from expressions such as foo[s*W+:W]
|
||||||
|
//
|
||||||
|
|
||||||
|
match shift
|
||||||
|
select shift->type.in($shift, $shiftx, $shr)
|
||||||
|
filter !port(shift, \B).empty()
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
// the right shift amount
|
||||||
|
state <SigSpec> shift_amount
|
||||||
|
// log2 scale factor in interpreting of shift_amount
|
||||||
|
// due to zero padding on the shift cell's B port
|
||||||
|
state <int> log2scale
|
||||||
|
|
||||||
|
code shift_amount log2scale
|
||||||
|
shift_amount = port(shift, \B);
|
||||||
|
if (shift->type.in($shr) || !param(shift, \B_SIGNED).as_bool())
|
||||||
|
shift_amount.append(State::S0);
|
||||||
|
|
||||||
|
// at this point shift_amount is signed, make
|
||||||
|
// sure we can never go negative
|
||||||
|
if (shift_amount.bits().back() != State::S0)
|
||||||
|
reject;
|
||||||
|
|
||||||
|
while (shift_amount.bits().back() == State::S0) {
|
||||||
|
shift_amount.remove(GetSize(shift_amount) - 1);
|
||||||
|
if (shift_amount.empty()) reject;
|
||||||
|
}
|
||||||
|
|
||||||
|
log2scale = 0;
|
||||||
|
while (shift_amount[0] == State::S0) {
|
||||||
|
shift_amount.remove(0);
|
||||||
|
if (shift_amount.empty()) reject;
|
||||||
|
log2scale++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetSize(shift_amount) > 20)
|
||||||
|
reject;
|
||||||
|
endcode
|
||||||
|
|
||||||
|
state <SigSpec> mul_din
|
||||||
|
state <Const> mul_const
|
||||||
|
|
||||||
|
match mul
|
||||||
|
select mul->type.in($mul)
|
||||||
|
index <SigSpec> port(mul, \Y) === shift_amount
|
||||||
|
filter !param(mul, \A_SIGNED).as_bool()
|
||||||
|
|
||||||
|
choice <IdString> constport {\A, \B}
|
||||||
|
filter port(mul, constport).is_fully_const()
|
||||||
|
|
||||||
|
define <IdString> varport (constport == \A ? \B : \A)
|
||||||
|
set mul_const SigSpec({port(mul, constport), SigSpec(State::S0, log2scale)}).as_const()
|
||||||
|
// get mul_din unmapped (so no `port()` shorthand)
|
||||||
|
// because we will be using it to set the \A port
|
||||||
|
// on the shift cell, and we want to stay close
|
||||||
|
// to the original design
|
||||||
|
set mul_din mul->getPort(varport)
|
||||||
|
endmatch
|
||||||
|
|
||||||
|
code
|
||||||
|
{
|
||||||
|
if (mul_const.empty() || GetSize(mul_const) > 20)
|
||||||
|
reject;
|
||||||
|
|
||||||
|
// make sure there's no overlap in the signal
|
||||||
|
// selections by the shiftmul pattern
|
||||||
|
if (GetSize(port(shift, \Y)) > mul_const.as_int())
|
||||||
|
reject;
|
||||||
|
|
||||||
|
int factor_bits = ceil_log2(mul_const.as_int());
|
||||||
|
// make sure the multiplication never wraps around
|
||||||
|
if (GetSize(shift_amount) + log2scale < factor_bits + GetSize(mul_din))
|
||||||
|
reject;
|
||||||
|
|
||||||
|
did_something = true;
|
||||||
|
log("right shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul));
|
||||||
|
|
||||||
|
int const_factor = mul_const.as_int();
|
||||||
|
int new_const_factor = 1 << factor_bits;
|
||||||
|
SigSpec padding(State::Sx, new_const_factor-const_factor);
|
||||||
|
SigSpec old_a = port(shift, \A), new_a;
|
||||||
|
int trunc = 0;
|
||||||
|
|
||||||
|
if (GetSize(old_a) % const_factor != 0) {
|
||||||
|
trunc = const_factor - GetSize(old_a) % const_factor;
|
||||||
|
old_a.append(SigSpec(State::Sx, trunc));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i*const_factor < GetSize(old_a); i++) {
|
||||||
|
SigSpec slice = old_a.extract(i*const_factor, const_factor);
|
||||||
|
new_a.append(slice);
|
||||||
|
new_a.append(padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trunc > 0)
|
||||||
|
new_a.remove(GetSize(new_a)-trunc, trunc);
|
||||||
|
|
||||||
|
SigSpec new_b = {mul_din, SigSpec(State::S0, factor_bits)};
|
||||||
|
if (param(shift, \B_SIGNED).as_bool())
|
||||||
|
new_b.append(State::S0);
|
||||||
|
|
||||||
|
shift->setPort(\A, new_a);
|
||||||
|
shift->setParam(\A_WIDTH, GetSize(new_a));
|
||||||
|
shift->setPort(\B, new_b);
|
||||||
|
shift->setParam(\B_WIDTH, GetSize(new_b));
|
||||||
|
|
||||||
|
blacklist(shift);
|
||||||
|
accept;
|
||||||
|
}
|
||||||
|
endcode
|
Loading…
Reference in New Issue