diff options
author | Xiretza <xiretza@xiretza.xyz> | 2020-04-08 19:30:47 +0200 |
---|---|---|
committer | Xiretza <xiretza@xiretza.xyz> | 2020-05-28 22:59:03 +0200 |
commit | 17163cf43a6b6eec9aac44f6a4463dda54b8ed68 (patch) | |
tree | 02dd1e144c36eb40565cbb792726c7d8d4573eb4 /backends/verilog | |
parent | 0d99522b3c2ca2502129110e09f9988874e37abc (diff) | |
download | yosys-17163cf43a6b6eec9aac44f6a4463dda54b8ed68.tar.gz yosys-17163cf43a6b6eec9aac44f6a4463dda54b8ed68.tar.bz2 yosys-17163cf43a6b6eec9aac44f6a4463dda54b8ed68.zip |
Add flooring modulo 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 $modfloor cell provides this flooring modulo (also known as "remainder"
in several languages, but this name is ambiguous).
This commit also fixes the handling of $mod in opt_expr, which was
previously optimized as if it was $modfloor.
Diffstat (limited to 'backends/verilog')
-rw-r--r-- | backends/verilog/verilog_backend.cc | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 11b2ae10f..368b76793 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -740,6 +740,40 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) #undef HANDLE_UNIOP #undef HANDLE_BINOP + if (cell->type == ID($modfloor)) + { + // wire truncated = $signed(A) % $signed(B); + // assign Y = (A[-1] == B[-1]) || truncated == 0 ? truncated : $signed(B) + $signed(truncated); + + 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 temp_id = next_auto_id(); + f << stringf("%s" "wire [%d:0] %s = ", indent.c_str(), GetSize(cell->getPort(ID::A))-1, temp_id.c_str()); + dump_cell_expr_port(f, cell, "A", true); + f << stringf(" %% "); + dump_attributes(f, "", cell->attributes, ' '); + dump_cell_expr_port(f, cell, "B", true); + f << stringf(";\n"); + + f << stringf("%s" "assign ", indent.c_str()); + dump_sigspec(f, cell->getPort(ID::Y)); + 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(") || %s == 0 ? %s : ", temp_id.c_str(), temp_id.c_str()); + dump_cell_expr_port(f, cell, "B", true); + f << stringf(" + $signed(%s);\n", temp_id.c_str()); + return true; + } else { + // same as truncating modulo + dump_cell_expr_binop(f, indent, cell, "%"); + return true; + } + } + if (cell->type == ID($shift)) { f << stringf("%s" "assign ", indent.c_str()); |