mirror of https://github.com/YosysHQ/yosys.git
Merge pull request #2573 from zachjs/repeat-call
verilog: refactored constant function evaluation
This commit is contained in:
commit
326f1c9db4
|
@ -264,10 +264,9 @@ namespace AST
|
||||||
|
|
||||||
// additional functionality for evaluating constant functions
|
// additional functionality for evaluating constant functions
|
||||||
struct varinfo_t { RTLIL::Const val; int offset; bool is_signed; };
|
struct varinfo_t { RTLIL::Const val; int offset; bool is_signed; };
|
||||||
bool has_const_only_constructs(bool &recommend_const_eval);
|
bool has_const_only_constructs();
|
||||||
bool has_const_only_constructs(std::set<std::string>& visited, bool &recommend_const_eval);
|
bool replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall, bool must_succeed);
|
||||||
void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall);
|
AstNode *eval_const_function(AstNode *fcall, bool must_succeed);
|
||||||
AstNode *eval_const_function(AstNode *fcall);
|
|
||||||
bool is_simple_const_expr();
|
bool is_simple_const_expr();
|
||||||
std::string process_format_str(const std::string &sformat, int next_arg, int stage, int width_hint, bool sign_hint);
|
std::string process_format_str(const std::string &sformat, int next_arg, int stage, int width_hint, bool sign_hint);
|
||||||
|
|
||||||
|
|
|
@ -1218,11 +1218,6 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
||||||
current_block = this;
|
current_block = this;
|
||||||
current_block_child = children[i];
|
current_block_child = children[i];
|
||||||
}
|
}
|
||||||
if (!in_param_here && type == AST_FCALL) {
|
|
||||||
bool recommend_const_eval = false;
|
|
||||||
bool require_const_eval = has_const_only_constructs(recommend_const_eval);
|
|
||||||
in_param_here = recommend_const_eval || require_const_eval;
|
|
||||||
}
|
|
||||||
if ((type == AST_ALWAYS || type == AST_INITIAL) && children[i]->type == AST_BLOCK)
|
if ((type == AST_ALWAYS || type == AST_INITIAL) && children[i]->type == AST_BLOCK)
|
||||||
current_top_block = children[i];
|
current_top_block = children[i];
|
||||||
if (i == 0 && child_0_is_self_determined)
|
if (i == 0 && child_0_is_self_determined)
|
||||||
|
@ -3186,10 +3181,9 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
decl->replace_result_wire_name_in_function(str, "$result"); // enables recursion
|
decl->replace_result_wire_name_in_function(str, "$result"); // enables recursion
|
||||||
decl->expand_genblock(prefix);
|
decl->expand_genblock(prefix);
|
||||||
|
|
||||||
bool recommend_const_eval = false;
|
if (decl->type == AST_FUNCTION && !decl->attributes.count(ID::via_celltype))
|
||||||
bool require_const_eval = in_param ? false : has_const_only_constructs(recommend_const_eval);
|
|
||||||
if ((in_param || recommend_const_eval || require_const_eval) && !decl->attributes.count(ID::via_celltype))
|
|
||||||
{
|
{
|
||||||
|
bool require_const_eval = decl->has_const_only_constructs();
|
||||||
bool all_args_const = true;
|
bool all_args_const = true;
|
||||||
for (auto child : children) {
|
for (auto child : children) {
|
||||||
while (child->simplify(true, false, false, 1, -1, false, true)) { }
|
while (child->simplify(true, false, false, 1, -1, false, true)) { }
|
||||||
|
@ -3200,10 +3194,12 @@ skip_dynamic_range_lvalue_expansion:;
|
||||||
if (all_args_const) {
|
if (all_args_const) {
|
||||||
AstNode *func_workspace = decl->clone();
|
AstNode *func_workspace = decl->clone();
|
||||||
func_workspace->str = prefix_id(prefix, "$result");
|
func_workspace->str = prefix_id(prefix, "$result");
|
||||||
newNode = func_workspace->eval_const_function(this);
|
newNode = func_workspace->eval_const_function(this, in_param || require_const_eval);
|
||||||
delete func_workspace;
|
delete func_workspace;
|
||||||
delete decl;
|
if (newNode) {
|
||||||
goto apply_newNode;
|
delete decl;
|
||||||
|
goto apply_newNode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_param)
|
if (in_param)
|
||||||
|
@ -4502,33 +4498,12 @@ bool AstNode::detect_latch(const std::string &var)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AstNode::has_const_only_constructs(bool &recommend_const_eval)
|
bool AstNode::has_const_only_constructs()
|
||||||
{
|
{
|
||||||
std::set<std::string> visited;
|
|
||||||
return has_const_only_constructs(visited, recommend_const_eval);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AstNode::has_const_only_constructs(std::set<std::string>& visited, bool &recommend_const_eval)
|
|
||||||
{
|
|
||||||
if (type == AST_FUNCTION || type == AST_TASK)
|
|
||||||
{
|
|
||||||
if (visited.count(str))
|
|
||||||
{
|
|
||||||
recommend_const_eval = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
visited.insert(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == AST_FOR)
|
|
||||||
recommend_const_eval = true;
|
|
||||||
if (type == AST_WHILE || type == AST_REPEAT)
|
if (type == AST_WHILE || type == AST_REPEAT)
|
||||||
return true;
|
return true;
|
||||||
if (type == AST_FCALL && current_scope.count(str))
|
|
||||||
if (current_scope[str]->has_const_only_constructs(visited, recommend_const_eval))
|
|
||||||
return true;
|
|
||||||
for (auto child : children)
|
for (auto child : children)
|
||||||
if (child->AstNode::has_const_only_constructs(visited, recommend_const_eval))
|
if (child->has_const_only_constructs())
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -4544,19 +4519,26 @@ bool AstNode::is_simple_const_expr()
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper function for AstNode::eval_const_function()
|
// helper function for AstNode::eval_const_function()
|
||||||
void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &variables, AstNode *fcall)
|
bool AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &variables, AstNode *fcall, bool must_succeed)
|
||||||
{
|
{
|
||||||
if (type == AST_IDENTIFIER && variables.count(str)) {
|
if (type == AST_IDENTIFIER && variables.count(str)) {
|
||||||
int offset = variables.at(str).offset, width = variables.at(str).val.bits.size();
|
int offset = variables.at(str).offset, width = variables.at(str).val.bits.size();
|
||||||
if (!children.empty()) {
|
if (!children.empty()) {
|
||||||
if (children.size() != 1 || children.at(0)->type != AST_RANGE)
|
if (children.size() != 1 || children.at(0)->type != AST_RANGE) {
|
||||||
|
if (!must_succeed)
|
||||||
|
return false;
|
||||||
log_file_error(filename, location.first_line, "Memory access in constant function is not supported\n%s:%d.%d-%d.%d: ...called from here.\n",
|
log_file_error(filename, location.first_line, "Memory access in constant function is not supported\n%s:%d.%d-%d.%d: ...called from here.\n",
|
||||||
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
||||||
children.at(0)->replace_variables(variables, fcall);
|
}
|
||||||
|
if (!children.at(0)->replace_variables(variables, fcall, must_succeed))
|
||||||
|
return false;
|
||||||
while (simplify(true, false, false, 1, -1, false, true)) { }
|
while (simplify(true, false, false, 1, -1, false, true)) { }
|
||||||
if (!children.at(0)->range_valid)
|
if (!children.at(0)->range_valid) {
|
||||||
|
if (!must_succeed)
|
||||||
|
return false;
|
||||||
log_file_error(filename, location.first_line, "Non-constant range\n%s:%d.%d-%d.%d: ... called from here.\n",
|
log_file_error(filename, location.first_line, "Non-constant range\n%s:%d.%d-%d.%d: ... called from here.\n",
|
||||||
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
||||||
|
}
|
||||||
offset = min(children.at(0)->range_left, children.at(0)->range_right);
|
offset = min(children.at(0)->range_left, children.at(0)->range_right);
|
||||||
width = min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width);
|
width = min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width);
|
||||||
}
|
}
|
||||||
|
@ -4566,19 +4548,22 @@ void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &varia
|
||||||
AstNode *newNode = mkconst_bits(new_bits, variables.at(str).is_signed);
|
AstNode *newNode = mkconst_bits(new_bits, variables.at(str).is_signed);
|
||||||
newNode->cloneInto(this);
|
newNode->cloneInto(this);
|
||||||
delete newNode;
|
delete newNode;
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &child : children)
|
for (auto &child : children)
|
||||||
child->replace_variables(variables, fcall);
|
if (!child->replace_variables(variables, fcall, must_succeed))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// evaluate functions with all-const arguments
|
// attempt to statically evaluate a functions with all-const arguments
|
||||||
AstNode *AstNode::eval_const_function(AstNode *fcall)
|
AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed)
|
||||||
{
|
{
|
||||||
std::map<std::string, AstNode*> backup_scope;
|
std::map<std::string, AstNode*> backup_scope = current_scope;
|
||||||
std::map<std::string, AstNode::varinfo_t> variables;
|
std::map<std::string, AstNode::varinfo_t> variables;
|
||||||
AstNode *block = new AstNode(AST_BLOCK);
|
AstNode *block = new AstNode(AST_BLOCK);
|
||||||
|
AstNode *result = nullptr;
|
||||||
|
|
||||||
size_t argidx = 0;
|
size_t argidx = 0;
|
||||||
for (auto child : children)
|
for (auto child : children)
|
||||||
|
@ -4600,9 +4585,12 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
|
||||||
if (stmt->type == AST_WIRE)
|
if (stmt->type == AST_WIRE)
|
||||||
{
|
{
|
||||||
while (stmt->simplify(true, false, false, 1, -1, false, true)) { }
|
while (stmt->simplify(true, false, false, 1, -1, false, true)) { }
|
||||||
if (!stmt->range_valid)
|
if (!stmt->range_valid) {
|
||||||
|
if (!must_succeed)
|
||||||
|
goto finished;
|
||||||
log_file_error(stmt->filename, stmt->location.first_line, "Can't determine size of variable %s\n%s:%d.%d-%d.%d: ... called from here.\n",
|
log_file_error(stmt->filename, stmt->location.first_line, "Can't determine size of variable %s\n%s:%d.%d-%d.%d: ... called from here.\n",
|
||||||
stmt->str.c_str(), fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
stmt->str.c_str(), fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
||||||
|
}
|
||||||
variables[stmt->str].val = RTLIL::Const(RTLIL::State::Sx, abs(stmt->range_left - stmt->range_right)+1);
|
variables[stmt->str].val = RTLIL::Const(RTLIL::State::Sx, abs(stmt->range_left - stmt->range_right)+1);
|
||||||
variables[stmt->str].offset = min(stmt->range_left, stmt->range_right);
|
variables[stmt->str].offset = min(stmt->range_left, stmt->range_right);
|
||||||
variables[stmt->str].is_signed = stmt->is_signed;
|
variables[stmt->str].is_signed = stmt->is_signed;
|
||||||
|
@ -4616,8 +4604,6 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
|
||||||
variables[stmt->str].val = arg_node->realAsConst(width);
|
variables[stmt->str].val = arg_node->realAsConst(width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!backup_scope.count(stmt->str))
|
|
||||||
backup_scope[stmt->str] = current_scope[stmt->str];
|
|
||||||
current_scope[stmt->str] = stmt;
|
current_scope[stmt->str] = stmt;
|
||||||
|
|
||||||
block->children.erase(block->children.begin());
|
block->children.erase(block->children.begin());
|
||||||
|
@ -4630,8 +4616,6 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
|
||||||
{
|
{
|
||||||
while (stmt->simplify(true, false, false, 1, -1, false, true)) { }
|
while (stmt->simplify(true, false, false, 1, -1, false, true)) { }
|
||||||
|
|
||||||
if (!backup_scope.count(stmt->str))
|
|
||||||
backup_scope[stmt->str] = current_scope[stmt->str];
|
|
||||||
current_scope[stmt->str] = stmt;
|
current_scope[stmt->str] = stmt;
|
||||||
|
|
||||||
block->children.erase(block->children.begin());
|
block->children.erase(block->children.begin());
|
||||||
|
@ -4642,32 +4626,46 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
|
||||||
{
|
{
|
||||||
if (stmt->children.at(0)->type == AST_IDENTIFIER && stmt->children.at(0)->children.size() != 0 &&
|
if (stmt->children.at(0)->type == AST_IDENTIFIER && stmt->children.at(0)->children.size() != 0 &&
|
||||||
stmt->children.at(0)->children.at(0)->type == AST_RANGE)
|
stmt->children.at(0)->children.at(0)->type == AST_RANGE)
|
||||||
stmt->children.at(0)->children.at(0)->replace_variables(variables, fcall);
|
if (!stmt->children.at(0)->children.at(0)->replace_variables(variables, fcall, must_succeed))
|
||||||
stmt->children.at(1)->replace_variables(variables, fcall);
|
goto finished;
|
||||||
|
if (!stmt->children.at(1)->replace_variables(variables, fcall, must_succeed))
|
||||||
|
goto finished;
|
||||||
while (stmt->simplify(true, false, false, 1, -1, false, true)) { }
|
while (stmt->simplify(true, false, false, 1, -1, false, true)) { }
|
||||||
|
|
||||||
if (stmt->type != AST_ASSIGN_EQ)
|
if (stmt->type != AST_ASSIGN_EQ)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (stmt->children.at(1)->type != AST_CONSTANT)
|
if (stmt->children.at(1)->type != AST_CONSTANT) {
|
||||||
|
if (!must_succeed)
|
||||||
|
goto finished;
|
||||||
log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s:%d.%d-%d.%d: ... called from here. X\n",
|
log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s:%d.%d-%d.%d: ... called from here. X\n",
|
||||||
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
||||||
|
}
|
||||||
|
|
||||||
if (stmt->children.at(0)->type != AST_IDENTIFIER)
|
if (stmt->children.at(0)->type != AST_IDENTIFIER) {
|
||||||
|
if (!must_succeed)
|
||||||
|
goto finished;
|
||||||
log_file_error(stmt->filename, stmt->location.first_line, "Unsupported composite left hand side in constant function\n%s:%d.%d-%d.%d: ... called from here.\n",
|
log_file_error(stmt->filename, stmt->location.first_line, "Unsupported composite left hand side in constant function\n%s:%d.%d-%d.%d: ... called from here.\n",
|
||||||
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
||||||
|
}
|
||||||
|
|
||||||
if (!variables.count(stmt->children.at(0)->str))
|
if (!variables.count(stmt->children.at(0)->str)) {
|
||||||
|
if (!must_succeed)
|
||||||
|
goto finished;
|
||||||
log_file_error(stmt->filename, stmt->location.first_line, "Assignment to non-local variable in constant function\n%s:%d.%d-%d.%d: ... called from here.\n",
|
log_file_error(stmt->filename, stmt->location.first_line, "Assignment to non-local variable in constant function\n%s:%d.%d-%d.%d: ... called from here.\n",
|
||||||
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
||||||
|
}
|
||||||
|
|
||||||
if (stmt->children.at(0)->children.empty()) {
|
if (stmt->children.at(0)->children.empty()) {
|
||||||
variables[stmt->children.at(0)->str].val = stmt->children.at(1)->bitsAsConst(variables[stmt->children.at(0)->str].val.bits.size());
|
variables[stmt->children.at(0)->str].val = stmt->children.at(1)->bitsAsConst(variables[stmt->children.at(0)->str].val.bits.size());
|
||||||
} else {
|
} else {
|
||||||
AstNode *range = stmt->children.at(0)->children.at(0);
|
AstNode *range = stmt->children.at(0)->children.at(0);
|
||||||
if (!range->range_valid)
|
if (!range->range_valid) {
|
||||||
|
if (!must_succeed)
|
||||||
|
goto finished;
|
||||||
log_file_error(range->filename, range->location.first_line, "Non-constant range\n%s:%d.%d-%d.%d: ... called from here.\n",
|
log_file_error(range->filename, range->location.first_line, "Non-constant range\n%s:%d.%d-%d.%d: ... called from here.\n",
|
||||||
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
||||||
|
}
|
||||||
int offset = min(range->range_left, range->range_right);
|
int offset = min(range->range_left, range->range_right);
|
||||||
int width = std::abs(range->range_left - range->range_right) + 1;
|
int width = std::abs(range->range_left - range->range_right) + 1;
|
||||||
varinfo_t &v = variables[stmt->children.at(0)->str];
|
varinfo_t &v = variables[stmt->children.at(0)->str];
|
||||||
|
@ -4694,12 +4692,16 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
|
||||||
if (stmt->type == AST_WHILE)
|
if (stmt->type == AST_WHILE)
|
||||||
{
|
{
|
||||||
AstNode *cond = stmt->children.at(0)->clone();
|
AstNode *cond = stmt->children.at(0)->clone();
|
||||||
cond->replace_variables(variables, fcall);
|
if (!cond->replace_variables(variables, fcall, must_succeed))
|
||||||
|
goto finished;
|
||||||
while (cond->simplify(true, false, false, 1, -1, false, true)) { }
|
while (cond->simplify(true, false, false, 1, -1, false, true)) { }
|
||||||
|
|
||||||
if (cond->type != AST_CONSTANT)
|
if (cond->type != AST_CONSTANT) {
|
||||||
|
if (!must_succeed)
|
||||||
|
goto finished;
|
||||||
log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s:%d.%d-%d.%d: ... called from here.\n",
|
log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s:%d.%d-%d.%d: ... called from here.\n",
|
||||||
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
||||||
|
}
|
||||||
|
|
||||||
if (cond->asBool()) {
|
if (cond->asBool()) {
|
||||||
block->children.insert(block->children.begin(), stmt->children.at(1)->clone());
|
block->children.insert(block->children.begin(), stmt->children.at(1)->clone());
|
||||||
|
@ -4715,12 +4717,16 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
|
||||||
if (stmt->type == AST_REPEAT)
|
if (stmt->type == AST_REPEAT)
|
||||||
{
|
{
|
||||||
AstNode *num = stmt->children.at(0)->clone();
|
AstNode *num = stmt->children.at(0)->clone();
|
||||||
num->replace_variables(variables, fcall);
|
if (!num->replace_variables(variables, fcall, must_succeed))
|
||||||
|
goto finished;
|
||||||
while (num->simplify(true, false, false, 1, -1, false, true)) { }
|
while (num->simplify(true, false, false, 1, -1, false, true)) { }
|
||||||
|
|
||||||
if (num->type != AST_CONSTANT)
|
if (num->type != AST_CONSTANT) {
|
||||||
|
if (!must_succeed)
|
||||||
|
goto finished;
|
||||||
log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s:%d.%d-%d.%d: ... called from here.\n",
|
log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s:%d.%d-%d.%d: ... called from here.\n",
|
||||||
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
||||||
|
}
|
||||||
|
|
||||||
block->children.erase(block->children.begin());
|
block->children.erase(block->children.begin());
|
||||||
for (int i = 0; i < num->bitsAsConst().as_int(); i++)
|
for (int i = 0; i < num->bitsAsConst().as_int(); i++)
|
||||||
|
@ -4734,7 +4740,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
|
||||||
if (stmt->type == AST_CASE)
|
if (stmt->type == AST_CASE)
|
||||||
{
|
{
|
||||||
AstNode *expr = stmt->children.at(0)->clone();
|
AstNode *expr = stmt->children.at(0)->clone();
|
||||||
expr->replace_variables(variables, fcall);
|
if (!expr->replace_variables(variables, fcall, must_succeed))
|
||||||
|
goto finished;
|
||||||
while (expr->simplify(true, false, false, 1, -1, false, true)) { }
|
while (expr->simplify(true, false, false, 1, -1, false, true)) { }
|
||||||
|
|
||||||
AstNode *sel_case = NULL;
|
AstNode *sel_case = NULL;
|
||||||
|
@ -4751,14 +4758,18 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
|
||||||
for (size_t j = 0; j+1 < stmt->children.at(i)->children.size() && !found_match; j++)
|
for (size_t j = 0; j+1 < stmt->children.at(i)->children.size() && !found_match; j++)
|
||||||
{
|
{
|
||||||
AstNode *cond = stmt->children.at(i)->children.at(j)->clone();
|
AstNode *cond = stmt->children.at(i)->children.at(j)->clone();
|
||||||
cond->replace_variables(variables, fcall);
|
if (!cond->replace_variables(variables, fcall, must_succeed))
|
||||||
|
goto finished;
|
||||||
|
|
||||||
cond = new AstNode(AST_EQ, expr->clone(), cond);
|
cond = new AstNode(AST_EQ, expr->clone(), cond);
|
||||||
while (cond->simplify(true, false, false, 1, -1, false, true)) { }
|
while (cond->simplify(true, false, false, 1, -1, false, true)) { }
|
||||||
|
|
||||||
if (cond->type != AST_CONSTANT)
|
if (cond->type != AST_CONSTANT) {
|
||||||
|
if (!must_succeed)
|
||||||
|
goto finished;
|
||||||
log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s:%d.%d-%d.%d: ... called from here.\n",
|
log_file_error(stmt->filename, stmt->location.first_line, "Non-constant expression in constant function\n%s:%d.%d-%d.%d: ... called from here.\n",
|
||||||
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
||||||
|
}
|
||||||
|
|
||||||
found_match = cond->asBool();
|
found_match = cond->asBool();
|
||||||
delete cond;
|
delete cond;
|
||||||
|
@ -4790,20 +4801,20 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!must_succeed)
|
||||||
|
goto finished;
|
||||||
log_file_error(stmt->filename, stmt->location.first_line, "Unsupported language construct in constant function\n%s:%d.%d-%d.%d: ... called from here.\n",
|
log_file_error(stmt->filename, stmt->location.first_line, "Unsupported language construct in constant function\n%s:%d.%d-%d.%d: ... called from here.\n",
|
||||||
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
fcall->filename.c_str(), fcall->location.first_line, fcall->location.first_column, fcall->location.last_line, fcall->location.last_column);
|
||||||
log_abort();
|
log_abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result = AstNode::mkconst_bits(variables.at(str).val.bits, variables.at(str).is_signed);
|
||||||
|
|
||||||
|
finished:
|
||||||
delete block;
|
delete block;
|
||||||
|
current_scope = backup_scope;
|
||||||
|
|
||||||
for (auto &it : backup_scope)
|
return result;
|
||||||
if (it.second == NULL)
|
|
||||||
current_scope.erase(it.first);
|
|
||||||
else
|
|
||||||
current_scope[it.first] = it.second;
|
|
||||||
|
|
||||||
return AstNode::mkconst_bits(variables.at(str).val.bits, variables.at(str).is_signed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AstNode::allocateDefaultEnumValues()
|
void AstNode::allocateDefaultEnumValues()
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
module top(
|
||||||
|
input wire [3:0] inp,
|
||||||
|
output wire [3:0] out1, out2, out3, out4, out5,
|
||||||
|
output reg [3:0] out6
|
||||||
|
);
|
||||||
|
function automatic [3:0] flip;
|
||||||
|
input [3:0] inp;
|
||||||
|
flip = ~inp;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic [3:0] help;
|
||||||
|
input [3:0] inp;
|
||||||
|
help = flip(inp);
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
// while loops are const-eval-only
|
||||||
|
function automatic [3:0] loop;
|
||||||
|
input [3:0] inp;
|
||||||
|
reg [3:0] val;
|
||||||
|
begin
|
||||||
|
val = inp;
|
||||||
|
loop = 1;
|
||||||
|
while (val != inp) begin
|
||||||
|
loop = loop * 2;
|
||||||
|
val = val + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
// not const-eval-only, despite calling a const-eval-only function
|
||||||
|
function automatic [3:0] help_mul;
|
||||||
|
input [3:0] inp;
|
||||||
|
help_mul = inp * loop(2);
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
// can be elaborated so long as exp is a constant
|
||||||
|
function automatic [3:0] pow_flip_a;
|
||||||
|
input [3:0] base, exp;
|
||||||
|
begin
|
||||||
|
pow_flip_a = 1;
|
||||||
|
if (exp > 0)
|
||||||
|
pow_flip_a = base * pow_flip_a(flip(base), exp - 1);
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function automatic [3:0] pow_flip_b;
|
||||||
|
input [3:0] base, exp;
|
||||||
|
begin
|
||||||
|
out6[exp] = base & 1;
|
||||||
|
pow_flip_b = 1;
|
||||||
|
if (exp > 0)
|
||||||
|
pow_flip_b = base * pow_flip_b(flip(base), exp - 1);
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
assign out1 = flip(flip(inp));
|
||||||
|
assign out2 = help(flip(inp));
|
||||||
|
assign out3 = help_mul(inp);
|
||||||
|
assign out4 = pow_flip_a(flip(inp), 3);
|
||||||
|
assign out5 = pow_flip_b(2, 2);
|
||||||
|
endmodule
|
|
@ -0,0 +1,33 @@
|
||||||
|
module top(w, x, y, z);
|
||||||
|
function [11:0] func;
|
||||||
|
input reg [2:0] x;
|
||||||
|
input reg [2:0] y;
|
||||||
|
begin
|
||||||
|
x = x * (y + 1);
|
||||||
|
begin : foo
|
||||||
|
reg [2:0] y;
|
||||||
|
y = x + 1;
|
||||||
|
begin : bar
|
||||||
|
reg [2:0] x;
|
||||||
|
x = y + 1;
|
||||||
|
begin : blah
|
||||||
|
reg [2:0] y;
|
||||||
|
y = x + 1;
|
||||||
|
func[2:0] = y;
|
||||||
|
end
|
||||||
|
func[5:3] = x;
|
||||||
|
end
|
||||||
|
func[8:6] = y;
|
||||||
|
end
|
||||||
|
func[11:9] = x;
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
output wire [func(2, 3) - 1:0] w;
|
||||||
|
output wire [func(1, 3) - 1:0] x;
|
||||||
|
output wire [func(3, 1) - 1:0] y;
|
||||||
|
output wire [func(5, 2) - 1:0] z;
|
||||||
|
assign w = 1'sb1;
|
||||||
|
assign x = 1'sb1;
|
||||||
|
assign y = 1'sb1;
|
||||||
|
assign z = 1'sb1;
|
||||||
|
endmodule
|
Loading…
Reference in New Issue