Created basic support for function calls in parameter values

This commit is contained in:
Clifford Wolf 2014-02-14 19:56:44 +01:00
parent 3121d19d95
commit 534c1a5dd0
4 changed files with 184 additions and 49 deletions

View File

@ -772,7 +772,7 @@ static AstModule* process_module(AstNode *ast, bool defer)
if (!defer)
{
while (ast->simplify(!flag_noopt, false, false, 0, -1, false)) { }
while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { }
if (flag_dump_ast2) {
log("Dumping verilog AST after simplification:\n");

View File

@ -190,7 +190,7 @@ namespace AST
// simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc.
// it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL()
bool simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint);
bool simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param);
void expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map);
void replace_ids(std::map<std::string, std::string> &rules);
void mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>> &mem2reg_places,
@ -198,6 +198,11 @@ namespace AST
void mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block);
void meminfo(int &mem_width, int &mem_size, int &addr_bits);
// additional functionality for evaluating constant functions
struct varinfo_t { RTLIL::Const val; int offset; bool is_signed; };
void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall);
AstNode *eval_const_function(AstNode *fcall);
// create a human-readable text representation of the AST (for debugging)
void dumpAst(FILE *f, std::string indent);
void dumpVlog(FILE *f, std::string indent);

View File

@ -648,8 +648,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint)
else if (!range->range_valid) {
AstNode *left_at_zero_ast = children[0]->children[0]->clone();
AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : left_at_zero_ast->clone();
while (left_at_zero_ast->simplify(true, true, false, 1, -1, false)) { }
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false)) { }
while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
str.c_str(), filename.c_str(), linenum);
@ -665,7 +665,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint)
break;
case AST_TO_BITS:
while (children[0]->simplify(true, false, false, 1, -1, false) == true) { }
while (children[0]->simplify(true, false, false, 1, -1, false, false) == true) { }
if (children[0]->type != AST_CONSTANT)
log_error("Left operand of tobits expression is not constant at %s:%d!\n", filename.c_str(), linenum);
children[1]->detectSignWidthWorker(sub_width_hint, sign_hint);
@ -693,7 +693,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint)
break;
case AST_REPLICATE:
while (children[0]->simplify(true, false, false, 1, -1, false) == true) { }
while (children[0]->simplify(true, false, false, 1, -1, false, false) == true) { }
if (children[0]->type != AST_CONSTANT)
log_error("Left operand of replicate expression is not constant at %s:%d!\n", filename.c_str(), linenum);
children[1]->detectSignWidthWorker(sub_width_hint, sub_sign_hint);
@ -961,8 +961,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (!children[0]->range_valid) {
AstNode *left_at_zero_ast = children[0]->children[0]->clone();
AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : left_at_zero_ast->clone();
while (left_at_zero_ast->simplify(true, true, false, 1, -1, false)) { }
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false)) { }
while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
str.c_str(), filename.c_str(), linenum);

View File

@ -43,7 +43,7 @@ using namespace AST_INTERNAL;
//
// this function also does all name resolving and sets the id2ast member of all
// nodes that link to a different node using names and lexical scoping.
bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint)
bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param)
{
AstNode *newNode = NULL;
bool did_something = false;
@ -52,7 +52,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
{
assert(type == AST_MODULE);
while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint)) { }
while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { }
if (!flag_nomem2reg && !get_bool_attribute("\\nomem2reg"))
{
@ -114,7 +114,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
reg->is_reg = true;
reg->is_signed = node->is_signed;
children.push_back(reg);
while (reg->simplify(true, false, false, 1, -1, false)) { }
while (reg->simplify(true, false, false, 1, -1, false, false)) { }
}
}
@ -128,7 +128,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
}
while (simplify(const_fold, at_zero, in_lvalue, 2, width_hint, sign_hint)) { }
while (simplify(const_fold, at_zero, in_lvalue, 2, width_hint, sign_hint, in_param)) { }
return false;
}
@ -148,7 +148,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// activate const folding if this is anything that must be evaluated statically (ranges, parameters, attributes, etc.)
if (type == AST_WIRE || type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_RANGE || type == AST_PREFIX)
const_fold = true;
const_fold = true, in_param = true;
if (type == AST_IDENTIFIER && current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM))
const_fold = true;
@ -215,7 +215,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
for (size_t i = 0; i < children.size(); i++) {
AstNode *node = children[i];
if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE)
while (node->simplify(true, false, false, 1, -1, false)) { }
while (node->simplify(true, false, false, 1, -1, false, node->type == AST_PARAMETER || node->type == AST_LOCALPARAM)) { }
}
}
@ -237,8 +237,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
case AST_ASSIGN_EQ:
case AST_ASSIGN_LE:
case AST_ASSIGN:
while (!children[0]->basic_prep && children[0]->simplify(false, false, true, stage, -1, false) == true) { }
while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false) == true) { }
while (!children[0]->basic_prep && children[0]->simplify(false, false, true, stage, -1, false, false) == true) { }
while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false, false) == true) { }
children[0]->detectSignWidth(backup_width_hint, backup_sign_hint);
children[1]->detectSignWidth(width_hint, sign_hint);
width_hint = std::max(width_hint, backup_width_hint);
@ -247,11 +247,11 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
case AST_PARAMETER:
case AST_LOCALPARAM:
while (!children[0]->basic_prep && children[0]->simplify(false, false, false, stage, -1, false) == true) { }
while (!children[0]->basic_prep && children[0]->simplify(false, false, false, stage, -1, false, true) == true) { }
children[0]->detectSignWidth(width_hint, sign_hint);
if (children.size() > 1) {
assert(children[1]->type == AST_RANGE);
while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false) == true) { }
while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false, true) == true) { }
if (!children[1]->range_valid)
log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum);
width_hint = std::max(width_hint, children[1]->range_left - children[1]->range_right + 1);
@ -307,7 +307,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
width_hint = -1;
sign_hint = true;
for (auto child : children) {
while (!child->basic_prep && child->simplify(false, false, in_lvalue, stage, -1, false) == true) { }
while (!child->basic_prep && child->simplify(false, false, in_lvalue, stage, -1, false, in_param) == true) { }
child->detectSignWidthWorker(width_hint, sign_hint);
}
reset_width_after_children = true;
@ -337,9 +337,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (detect_width_simple && width_hint < 0) {
for (auto child : children)
while (!child->basic_prep && child->simplify(false, false, in_lvalue, stage, -1, false) == true) { }
while (!child->basic_prep && child->simplify(false, false, in_lvalue, stage, -1, false, in_param) == true) { }
if (type == AST_REPLICATE)
while (children[0]->simplify(true, false, in_lvalue, stage, -1, false) == true) { }
while (children[0]->simplify(true, false, in_lvalue, stage, -1, false, in_param) == true) { }
detectSignWidth(width_hint, sign_hint);
}
@ -379,13 +379,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
width_hint_here = -1, sign_hint_here = false;
if (children_are_self_determined)
width_hint_here = -1, sign_hint_here = false;
did_something_here = children[i]->simplify(const_fold_here, at_zero, in_lvalue_here, stage, width_hint_here, sign_hint_here);
did_something_here = children[i]->simplify(const_fold_here, at_zero, in_lvalue_here, stage, width_hint_here, sign_hint_here, in_param);
if (did_something_here)
did_something = true;
}
}
for (auto &attr : attributes) {
while (attr.second->simplify(true, false, false, stage, -1, false)) { }
while (attr.second->simplify(true, false, false, stage, -1, false, true)) { }
}
if (reset_width_after_children) {
@ -556,7 +556,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (current_block)
wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
current_ast_mod->children.push_back(wire);
while (wire->simplify(true, false, false, 1, -1, false)) { }
while (wire->simplify(true, false, false, 1, -1, false, false)) { }
AstNode *data = clone();
delete data->children[1];
@ -621,7 +621,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// eval 1st expression
AstNode *varbuf = init_ast->children[1]->clone();
while (varbuf->simplify(true, false, false, stage, width_hint, sign_hint)) { }
while (varbuf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (varbuf->type != AST_CONSTANT)
log_error("Right hand side of 1st expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum);
@ -643,7 +643,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
{
// eval 2nd expression
AstNode *buf = while_ast->clone();
while (buf->simplify(true, false, false, stage, width_hint, sign_hint)) { }
while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (buf->type != AST_CONSTANT)
log_error("2nd expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum);
@ -672,7 +672,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_GENFOR) {
for (size_t i = 0; i < buf->children.size(); i++) {
buf->children[i]->simplify(false, false, false, stage, -1, false);
buf->children[i]->simplify(false, false, false, stage, -1, false, false);
current_ast_mod->children.push_back(buf->children[i]);
}
} else {
@ -684,7 +684,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// eval 3rd expression
buf = next_ast->children[1]->clone();
while (buf->simplify(true, false, false, stage, width_hint, sign_hint)) { }
while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (buf->type != AST_CONSTANT)
log_error("Right hand side of 3rd expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum);
@ -708,7 +708,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
std::vector<AstNode*> new_children;
for (size_t i = 0; i < children.size(); i++)
if (children[i]->type == AST_WIRE) {
children[i]->simplify(false, false, false, stage, -1, false);
children[i]->simplify(false, false, false, stage, -1, false, false);
current_ast_mod->children.push_back(children[i]);
} else
new_children.push_back(children[i]);
@ -727,7 +727,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
for (size_t i = 0; i < children.size(); i++) {
children[i]->simplify(false, false, false, stage, -1, false);
children[i]->simplify(false, false, false, stage, -1, false, false);
current_ast_mod->children.push_back(children[i]);
}
@ -739,7 +739,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_GENIF && children.size() != 0)
{
AstNode *buf = children[0]->clone();
while (buf->simplify(true, false, false, stage, width_hint, sign_hint)) { }
while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (buf->type != AST_CONSTANT) {
// for (auto f : log_files)
// dumpAst(f, "verilog-ast> ");
@ -764,7 +764,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
for (size_t i = 0; i < buf->children.size(); i++) {
buf->children[i]->simplify(false, false, false, stage, -1, false);
buf->children[i]->simplify(false, false, false, stage, -1, false, false);
current_ast_mod->children.push_back(buf->children[i]);
}
@ -780,7 +780,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_GENCASE && children.size() != 0)
{
AstNode *buf = children[0]->clone();
while (buf->simplify(true, false, false, stage, width_hint, sign_hint)) { }
while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (buf->type != AST_CONSTANT) {
// for (auto f : log_files)
// dumpAst(f, "verilog-ast> ");
@ -814,7 +814,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
continue;
buf = child->clone();
while (buf->simplify(true, false, false, stage, width_hint, sign_hint)) { }
while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (buf->type != AST_CONSTANT) {
// for (auto f : log_files)
// dumpAst(f, "verilog-ast> ");
@ -840,7 +840,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
for (size_t i = 0; i < buf->children.size(); i++) {
buf->children[i]->simplify(false, false, false, stage, -1, false);
buf->children[i]->simplify(false, false, false, stage, -1, false, false);
current_ast_mod->children.push_back(buf->children[i]);
}
@ -955,8 +955,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
shift_expr = range->children[1]->clone();
AstNode *left_at_zero_ast = range->children[0]->clone();
AstNode *right_at_zero_ast = range->children[1]->clone();
while (left_at_zero_ast->simplify(true, true, false, stage, -1, false)) { }
while (right_at_zero_ast->simplify(true, true, false, stage, -1, false)) { }
while (left_at_zero_ast->simplify(true, true, false, stage, -1, false, false)) { }
while (right_at_zero_ast->simplify(true, true, false, stage, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
str.c_str(), filename.c_str(), linenum);
@ -988,7 +988,7 @@ skip_dynamic_range_lvalue_expansion:;
wire_check->str = id_check;
current_ast_mod->children.push_back(wire_check);
current_scope[wire_check->str] = wire_check;
while (wire_check->simplify(true, false, false, 1, -1, false)) { }
while (wire_check->simplify(true, false, false, 1, -1, false, false)) { }
AstNode *wire_en = new AstNode(AST_WIRE);
wire_en->str = id_en;
@ -996,7 +996,7 @@ skip_dynamic_range_lvalue_expansion:;
current_ast_mod->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1)))));
current_ast_mod->children.back()->children[0]->children[0]->children[0]->str = id_en;
current_scope[wire_en->str] = wire_en;
while (wire_en->simplify(true, false, false, 1, -1, false)) { }
while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
std::vector<RTLIL::State> x_bit;
x_bit.push_back(RTLIL::State::Sx);
@ -1070,19 +1070,19 @@ skip_dynamic_range_lvalue_expansion:;
wire_addr->str = id_addr;
current_ast_mod->children.push_back(wire_addr);
current_scope[wire_addr->str] = wire_addr;
while (wire_addr->simplify(true, false, false, 1, -1, false)) { }
while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { }
AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
wire_data->str = id_data;
current_ast_mod->children.push_back(wire_data);
current_scope[wire_data->str] = wire_data;
while (wire_data->simplify(true, false, false, 1, -1, false)) { }
while (wire_data->simplify(true, false, false, 1, -1, false, false)) { }
AstNode *wire_en = new AstNode(AST_WIRE);
wire_en->str = id_en;
current_ast_mod->children.push_back(wire_en);
current_scope[wire_en->str] = wire_en;
while (wire_en->simplify(true, false, false, 1, -1, false)) { }
while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
std::vector<RTLIL::State> x_bits;
for (int i = 0; i < mem_width; i++)
@ -1138,7 +1138,7 @@ skip_dynamic_range_lvalue_expansion:;
if (str == "\\$clog2")
{
AstNode *buf = children[0]->clone();
while (buf->simplify(true, false, false, stage, width_hint, sign_hint)) { }
while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (buf->type != AST_CONSTANT)
log_error("Failed to evaluate system function `%s' with non-constant value at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
@ -1160,6 +1160,23 @@ skip_dynamic_range_lvalue_expansion:;
log_error("Can't resolve task name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
}
if (in_param)
{
bool all_args_const = true;
for (auto child : children)
if (child->type != AST_CONSTANT)
all_args_const = false;
if (all_args_const) {
AstNode *func_workspace = current_scope[str]->clone();
newNode = func_workspace->eval_const_function(this);
delete func_workspace;
goto apply_newNode;
}
log_error("Non-constant function call in constant expression at %s:%d.\n", filename.c_str(), linenum);
}
AstNode *decl = current_scope[str];
std::stringstream sstr;
sstr << "$func$" << str << "$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++) << "$";
@ -1184,7 +1201,7 @@ skip_dynamic_range_lvalue_expansion:;
wire->is_output = false;
current_ast_mod->children.push_back(wire);
while (wire->simplify(true, false, false, 1, -1, false)) { }
while (wire->simplify(true, false, false, 1, -1, false, false)) { }
AstNode *lvalue = new AstNode(AST_IDENTIFIER);
lvalue->str = wire->str;
@ -1206,7 +1223,7 @@ skip_dynamic_range_lvalue_expansion:;
wire->is_input = false;
wire->is_output = false;
current_ast_mod->children.push_back(wire);
while (wire->simplify(true, false, false, 1, -1, false)) { }
while (wire->simplify(true, false, false, 1, -1, false, false)) { }
replace_rules[child->str] = wire->str;
@ -1628,14 +1645,14 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
wire_addr->is_reg = true;
wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
mod->children.push_back(wire_addr);
while (wire_addr->simplify(true, false, false, 1, -1, false)) { }
while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { }
AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
wire_data->str = id_data;
wire_data->is_reg = true;
wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
mod->children.push_back(wire_data);
while (wire_data->simplify(true, false, false, 1, -1, false)) { }
while (wire_data->simplify(true, false, false, 1, -1, false, false)) { }
assert(block != NULL);
size_t assign_idx = 0;
@ -1694,7 +1711,7 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
if (block)
wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
mod->children.push_back(wire_addr);
while (wire_addr->simplify(true, false, false, 1, -1, false)) { }
while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { }
AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
wire_data->str = id_data;
@ -1702,7 +1719,7 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
if (block)
wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
mod->children.push_back(wire_data);
while (wire_data->simplify(true, false, false, 1, -1, false)) { }
while (wire_data->simplify(true, false, false, 1, -1, false, false)) { }
AstNode *assign_addr = new AstNode(block ? AST_ASSIGN_EQ : AST_ASSIGN, new AstNode(AST_IDENTIFIER), children[0]->children[0]->clone());
assign_addr->children[0]->str = id_addr;
@ -1779,3 +1796,116 @@ void AstNode::meminfo(int &mem_width, int &mem_size, int &addr_bits)
addr_bits++;
}
// helper function for AstNode::eval_const_function()
void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &variables, AstNode *fcall)
{
if (type == AST_IDENTIFIER && variables.count(str)) {
int offset = variables.at(str).offset, width = variables.at(str).val.bits.size();
if (!children.empty()) {
while (simplify(true, false, false, 1, -1, false, true)) { }
if (!range_valid)
log_error("Non-constant range in %s:%d (called from %s:%d).\n",
filename.c_str(), linenum, fcall->filename.c_str(), fcall->linenum);
offset = std::min(range_left, range_right);
width = std::min(std::abs(range_left - range_right) + 1, width);
}
offset -= variables.at(str).offset;
std::vector<RTLIL::State> &var_bits = variables.at(str).val.bits;
std::vector<RTLIL::State> new_bits(var_bits.begin() + offset, var_bits.begin() + offset + width);
AstNode *newNode = mkconst_bits(new_bits, variables.at(str).is_signed);
newNode->cloneInto(this);
delete newNode;
return;
}
for (auto &child : children)
child->replace_variables(variables, fcall);
}
// evaluate functions with all-const arguments
AstNode *AstNode::eval_const_function(AstNode *fcall)
{
std::map<std::string, AstNode*> backup_scope;
std::map<std::string, AstNode::varinfo_t> variables;
AstNode *block = NULL;
size_t argidx = 0;
for (auto child : children)
{
if (child->type == AST_BLOCK)
{
log_assert(block == NULL);
block = child;
continue;
}
if (child->type == AST_WIRE)
{
while (child->simplify(true, false, false, 1, -1, false, true)) { }
if (!child->range_valid)
log_error("Can't determine size of variable %s in %s:%d (called from %s:%d).\n",
child->str.c_str(), child->filename.c_str(), child->linenum, fcall->filename.c_str(), fcall->linenum);
variables[child->str].val = RTLIL::Const(RTLIL::State::Sx, abs(child->range_left - child->range_right)+1);
variables[child->str].offset = std::min(child->range_left, child->range_right);
variables[child->str].is_signed = child->is_signed;
if (child->is_input && argidx < fcall->children.size())
variables[child->str].val = fcall->children.at(argidx++)->bitsAsConst(variables[child->str].val.bits.size());
backup_scope[child->str] = current_scope[child->str];
current_scope[child->str] = child;
continue;
}
log_abort();
}
log_assert(block != NULL);
log_assert(variables.count(str));
while (!block->children.empty())
{
AstNode *stmt = block->children.front();
#if 0
log("-----------------------------------\n");
for (auto &it : variables)
log("%20s %40s\n", it.first.c_str(), log_signal(it.second.val));
stmt->dumpAst(NULL, "stmt> ");
#endif
if (stmt->type == AST_ASSIGN_EQ)
{
stmt->children.at(1)->replace_variables(variables, fcall);
while (stmt->simplify(true, false, false, 1, -1, false, true)) { }
if (stmt->children.at(1)->type != AST_CONSTANT)
log_error("Non-constant expression in constant function at %s:%d (called from %s:%d).\n",
stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
if (stmt->children.at(0)->type != AST_IDENTIFIER || !stmt->children.at(0)->children.empty())
log_error("Unsupported composite left hand side in constant function at %s:%d (called from %s:%d).\n",
stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
if (!variables.count(stmt->children.at(0)->str))
log_error("Assignment to non-local variable in constant function at %s:%d (called from %s:%d).\n",
stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
variables[stmt->children.at(0)->str].val = stmt->children.at(1)->bitsAsConst(variables[stmt->children.at(0)->str].val.bits.size());
block->children.erase(block->children.begin());
continue;
}
log_error("Unsupported language construct in constant function at %s:%d (called from %s:%d).\n",
stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
log_abort();
}
for (auto &it : backup_scope)
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);
}