mirror of
https://github.com/YosysHQ/yosys
synced 2025-06-06 06:03:23 +00:00
Add flooring division operator
The $div and $mod cells use truncating division semantics (rounding towards 0), as defined by e.g. Verilog. Another rounding mode, flooring (rounding towards negative infinity), can be used in e.g. VHDL. The new $divfloor cell provides this flooring division. This commit also fixes the handling of $div in opt_expr, which was previously optimized as if it was $divfloor.
This commit is contained in:
parent
17163cf43a
commit
edd8ff2c07
19 changed files with 213 additions and 24 deletions
|
@ -864,7 +864,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
|
|||
skip_fine_alu:
|
||||
|
||||
if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($shift), ID($shiftx), ID($shl), ID($shr), ID($sshl), ID($sshr),
|
||||
ID($lt), ID($le), ID($ge), ID($gt), ID($neg), ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($modfloor), ID($pow)))
|
||||
ID($lt), ID($le), ID($ge), ID($gt), ID($neg), ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow)))
|
||||
{
|
||||
RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A));
|
||||
RTLIL::SigSpec sig_b = cell->hasPort(ID::B) ? assign_map(cell->getPort(ID::B)) : RTLIL::SigSpec();
|
||||
|
@ -883,7 +883,7 @@ skip_fine_alu:
|
|||
if (0) {
|
||||
found_the_x_bit:
|
||||
cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
|
||||
"$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$modfloor", "$pow", cell->type.str());
|
||||
"$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$divfloor", "$modfloor", "$pow", cell->type.str());
|
||||
if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($lt), ID($le), ID($ge), ID($gt)))
|
||||
replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::State::Sx);
|
||||
else
|
||||
|
@ -1469,6 +1469,7 @@ skip_identity:
|
|||
FOLD_2ARG_CELL(mul)
|
||||
FOLD_2ARG_CELL(div)
|
||||
FOLD_2ARG_CELL(mod)
|
||||
FOLD_2ARG_CELL(divfloor)
|
||||
FOLD_2ARG_CELL(modfloor)
|
||||
FOLD_2ARG_CELL(pow)
|
||||
|
||||
|
@ -1584,7 +1585,7 @@ skip_identity:
|
|||
}
|
||||
}
|
||||
|
||||
if (!keepdc && cell->type.in(ID($div), ID($mod), ID($modfloor)))
|
||||
if (!keepdc && cell->type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor)))
|
||||
{
|
||||
bool a_signed = cell->parameters[ID::A_SIGNED].as_bool();
|
||||
bool b_signed = cell->parameters[ID::B_SIGNED].as_bool();
|
||||
|
@ -1613,11 +1614,13 @@ skip_identity:
|
|||
for (int i = 1; i < (b_signed ? sig_b.size()-1 : sig_b.size()); i++)
|
||||
if (b_val == (1 << i))
|
||||
{
|
||||
if (cell->type == ID($div))
|
||||
if (cell->type.in(ID($div), ID($divfloor)))
|
||||
{
|
||||
cover("opt.opt_expr.div_shift");
|
||||
|
||||
log_debug("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
|
||||
bool is_truncating = cell->type == ID($div);
|
||||
log_debug("Replacing %s-divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
|
||||
is_truncating ? "truncating" : "flooring",
|
||||
b_val, cell->name.c_str(), module->name.c_str(), i);
|
||||
|
||||
std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6);
|
||||
|
@ -1625,10 +1628,26 @@ skip_identity:
|
|||
while (GetSize(new_b) > 1 && new_b.back() == RTLIL::State::S0)
|
||||
new_b.pop_back();
|
||||
|
||||
cell->type = ID($shr);
|
||||
cell->type = ID($sshr);
|
||||
cell->parameters[ID::B_WIDTH] = GetSize(new_b);
|
||||
cell->parameters[ID::B_SIGNED] = false;
|
||||
cell->setPort(ID::B, new_b);
|
||||
|
||||
// Truncating division is the same as flooring division, except when
|
||||
// the result is negative and there is a remainder - then trunc = floor + 1
|
||||
if (is_truncating && a_signed) {
|
||||
Wire *flooring = module->addWire(NEW_ID, sig_y.size());
|
||||
cell->setPort(ID::Y, flooring);
|
||||
|
||||
Wire *result_neg = module->addWire(NEW_ID);
|
||||
module->addXor(NEW_ID, sig_a[sig_a.size()-1], sig_b[sig_b.size()-1], result_neg);
|
||||
Wire *rem_nonzero = module->addWire(NEW_ID);
|
||||
module->addReduceOr(NEW_ID, sig_a.extract(0, i), rem_nonzero);
|
||||
Wire *should_add = module->addWire(NEW_ID);
|
||||
module->addAnd(NEW_ID, result_neg, rem_nonzero, should_add);
|
||||
module->addAdd(NEW_ID, flooring, should_add, sig_y);
|
||||
}
|
||||
|
||||
cell->check();
|
||||
}
|
||||
else if (cell->type.in(ID($mod), ID($modfloor)))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue