aboutsummaryrefslogtreecommitdiffstats
path: root/frontends/ast/genrtlil.cc
diff options
context:
space:
mode:
authorZachary Snow <zach@zachjs.com>2021-02-12 14:25:34 -0500
committerZachary Snow <zach@zachjs.com>2021-02-12 14:43:42 -0500
commit8de2e863af4233aca0a0ca0eef4477d216f7a227 (patch)
tree4854ab4fb9acbee14151db50dd09795825954bbd /frontends/ast/genrtlil.cc
parent9f7cd10c9887df7a8fb8e0d587955d5a03b60c52 (diff)
downloadyosys-8de2e863af4233aca0a0ca0eef4477d216f7a227.tar.gz
yosys-8de2e863af4233aca0a0ca0eef4477d216f7a227.tar.bz2
yosys-8de2e863af4233aca0a0ca0eef4477d216f7a227.zip
verilog: support recursive functions using ternary expressions
This adds a mechanism for marking certain portions of elaboration as occurring within unevaluated ternary branches. To enable elaboration of the overall ternary, this also adds width detection for these unelaborated function calls.
Diffstat (limited to 'frontends/ast/genrtlil.cc')
-rw-r--r--frontends/ast/genrtlil.cc35
1 files changed, 35 insertions, 0 deletions
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index 24f5e1bef..713e34eb1 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -944,6 +944,41 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
}
break;
}
+ if (current_scope.count(str))
+ {
+ // This width detection is needed for function calls which are
+ // unelaborated, which currently only applies to calls to recursive
+ // functions reached by unevaluated ternary branches.
+ const AstNode *func = current_scope.at(str);
+ if (func->type != AST_FUNCTION)
+ log_file_error(filename, location.first_line, "Function call to %s resolved to something that isn't a function!\n", RTLIL::unescape_id(str).c_str());
+ const AstNode *wire = nullptr;
+ for (const AstNode *child : func->children)
+ if (child->str == func->str) {
+ wire = child;
+ break;
+ }
+ log_assert(wire && wire->type == AST_WIRE);
+ sign_hint = wire->is_signed;
+ width_hint = 1;
+ if (!wire->children.empty())
+ {
+ log_assert(wire->children.size() == 1);
+ const AstNode *range = wire->children.at(0);
+ log_assert(range->type == AST_RANGE && range->children.size() == 2);
+ AstNode *left = range->children.at(0)->clone();
+ AstNode *right = range->children.at(1)->clone();
+ while (left->simplify(true, false, false, 1, -1, false, true)) { }
+ while (right->simplify(true, false, false, 1, -1, false, true)) { }
+ if (left->type != AST_CONSTANT || right->type != AST_CONSTANT)
+ log_file_error(filename, location.first_line, "Function %s has non-constant width!",
+ RTLIL::unescape_id(str).c_str());
+ width_hint = abs(int(left->asInt(true) - right->asInt(true)));
+ delete left;
+ delete right;
+ }
+ break;
+ }
YS_FALLTHROUGH
// everything should have been handled above -> print error if not.