3
0
Fork 0
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:
Xiretza 2020-04-21 12:51:58 +02:00
parent 17163cf43a
commit edd8ff2c07
No known key found for this signature in database
GPG key ID: 17B78226F7139993
19 changed files with 213 additions and 24 deletions

View file

@ -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 "

View file

@ -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

View file

@ -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);