mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-24 01:25:33 +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
|
@ -6,7 +6,7 @@ rm -rf test_cells.tmp
|
|||
mkdir -p test_cells.tmp
|
||||
cd test_cells.tmp
|
||||
|
||||
../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$sop /$macc /$mul /$div /$mod /$modfloor'
|
||||
../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$sop /$macc /$mul /$div /$mod /$divfloor /$modfloor'
|
||||
|
||||
for fn in test_*.il; do
|
||||
../../../yosys -p "
|
||||
|
|
|
@ -7,8 +7,8 @@ mkdir -p test_cells.tmp
|
|||
cd test_cells.tmp
|
||||
|
||||
# don't test $mul to reduce runtime
|
||||
# don't test $div/$mod/$modfloor to reduce runtime and avoid "div by zero" message
|
||||
../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$macc /$mul /$div /$mod /$modfloor'
|
||||
# don't test $div/$mod/$divfloor/$modfloor to reduce runtime and avoid "div by zero" message
|
||||
../../../yosys -p 'test_cell -n 5 -w test all /$alu /$fa /$lcu /$lut /$macc /$mul /$div /$mod /$divfloor /$modfloor'
|
||||
|
||||
cat > template.txt << "EOT"
|
||||
%module main
|
||||
|
|
|
@ -740,6 +740,61 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
#undef HANDLE_UNIOP
|
||||
#undef HANDLE_BINOP
|
||||
|
||||
if (cell->type == ID($divfloor))
|
||||
{
|
||||
// wire [MAXLEN+1:0] _0_, _1_, _2_;
|
||||
// assign _0_ = $signed(A);
|
||||
// assign _1_ = $signed(B);
|
||||
// assign _2_ = (A[-1] == B[-1]) || A == 0 ? _0_ : $signed(_0_ - (B[-1] ? _1_ + 1 : _1_ - 1));
|
||||
// assign Y = $signed(_2_) / $signed(_1_);
|
||||
|
||||
if (cell->getParam(ID::A_SIGNED).as_bool() && cell->getParam(ID::B_SIGNED).as_bool()) {
|
||||
SigSpec sig_a = cell->getPort(ID::A);
|
||||
SigSpec sig_b = cell->getPort(ID::B);
|
||||
|
||||
std::string buf_a = next_auto_id();
|
||||
std::string buf_b = next_auto_id();
|
||||
std::string buf_num = next_auto_id();
|
||||
int size_a = GetSize(sig_a);
|
||||
int size_b = GetSize(sig_b);
|
||||
int size_y = GetSize(cell->getPort(ID::Y));
|
||||
int size_max = std::max(size_a, std::max(size_b, size_y));
|
||||
|
||||
// intentionally one wider than maximum width
|
||||
f << stringf("%s" "wire [%d:0] %s, %s, %s;\n", indent.c_str(), size_max, buf_a.c_str(), buf_b.c_str(), buf_num.c_str());
|
||||
f << stringf("%s" "assign %s = ", indent.c_str(), buf_a.c_str());
|
||||
dump_cell_expr_port(f, cell, "A", true);
|
||||
f << stringf(";\n");
|
||||
f << stringf("%s" "assign %s = ", indent.c_str(), buf_b.c_str());
|
||||
dump_cell_expr_port(f, cell, "B", true);
|
||||
f << stringf(";\n");
|
||||
|
||||
f << stringf("%s" "assign %s = ", indent.c_str(), buf_num.c_str());
|
||||
f << stringf("(");
|
||||
dump_sigspec(f, sig_a.extract(sig_a.size()-1));
|
||||
f << stringf(" == ");
|
||||
dump_sigspec(f, sig_b.extract(sig_b.size()-1));
|
||||
f << stringf(") || ");
|
||||
dump_sigspec(f, sig_a);
|
||||
f << stringf(" == 0 ? %s : ", buf_a.c_str());
|
||||
f << stringf("$signed(%s - (", buf_a.c_str());
|
||||
dump_sigspec(f, sig_b.extract(sig_b.size()-1));
|
||||
f << stringf(" ? %s + 1 : %s - 1));\n", buf_b.c_str(), buf_b.c_str());
|
||||
|
||||
|
||||
f << stringf("%s" "assign ", indent.c_str());
|
||||
dump_sigspec(f, cell->getPort(ID::Y));
|
||||
f << stringf(" = $signed(%s) / ", buf_num.c_str());
|
||||
dump_attributes(f, "", cell->attributes, ' ');
|
||||
f << stringf("$signed(%s);\n", buf_b.c_str());
|
||||
return true;
|
||||
} else {
|
||||
// same as truncating division
|
||||
dump_cell_expr_binop(f, indent, cell, "/");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (cell->type == ID($modfloor))
|
||||
{
|
||||
// wire truncated = $signed(A) % $signed(B);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue