aboutsummaryrefslogtreecommitdiffstats
path: root/frontends/ast/genrtlil.cc
diff options
context:
space:
mode:
authorwhitequark <whitequark@whitequark.org>2021-02-21 20:56:04 +0000
committerGitHub <noreply@github.com>2021-02-21 20:56:04 +0000
commit01ccb80b708b45926b3690949479715ebf5e2853 (patch)
treeaa2f7cf94cd7b1742568d05d744dc6e21b266306 /frontends/ast/genrtlil.cc
parent3fee43cde0ec424e52ea62f78722b061aaac280a (diff)
parent8de2e863af4233aca0a0ca0eef4477d216f7a227 (diff)
downloadyosys-01ccb80b708b45926b3690949479715ebf5e2853.tar.gz
yosys-01ccb80b708b45926b3690949479715ebf5e2853.tar.bz2
yosys-01ccb80b708b45926b3690949479715ebf5e2853.zip
Merge pull request #2586 from zachjs/tern-recurse
verilog: support recursive functions using ternary expressions
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.