From 534c1a5dd009b41629d2d05acfde747ce6fbc19c Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 14 Feb 2014 19:56:44 +0100 Subject: Created basic support for function calls in parameter values --- frontends/ast/simplify.cc | 212 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 171 insertions(+), 41 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index b51079ce5..85dc1d3c2 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -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 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 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 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 &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 &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 &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 &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 &var_bits = variables.at(str).val.bits; + std::vector 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 backup_scope; + std::map 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); +} + -- cgit v1.2.3 From e8af3def7fbefa1608e72609e1c534091fc7c88e Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 14 Feb 2014 20:33:22 +0100 Subject: Added support for FOR loops in function calls in parameters --- frontends/ast/simplify.cc | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 85dc1d3c2..236843d5d 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1891,10 +1891,51 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) variables[stmt->children.at(0)->str].val = stmt->children.at(1)->bitsAsConst(variables[stmt->children.at(0)->str].val.bits.size()); + delete block->children.front(); block->children.erase(block->children.begin()); continue; } + if (stmt->type == AST_FOR) + { + block->children.insert(block->children.begin(), stmt->children.at(0)); + stmt->children.at(3)->children.push_back(stmt->children.at(2)); + stmt->children.erase(stmt->children.begin() + 2); + stmt->children.erase(stmt->children.begin()); + stmt->type = AST_WHILE; + continue; + } + + if (stmt->type == AST_WHILE) + { + AstNode *cond = stmt->children.at(0)->clone(); + cond->replace_variables(variables, fcall); + while (cond->simplify(true, false, false, 1, -1, false, true)) { } + + if (cond->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 (cond->asBool()) { + block->children.insert(block->children.begin(), stmt->children.at(1)->clone()); + } else { + delete block->children.front(); + block->children.erase(block->children.begin()); + } + + delete cond; + continue; + } + + if (stmt->type == AST_BLOCK) + { + block->children.erase(block->children.begin()); + block->children.insert(block->children.begin(), stmt->children.begin(), stmt->children.end()); + stmt->children.clear(); + delete stmt; + 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(); -- cgit v1.2.3 From 45d2b6ffce24c3a4254ef7f80f300cc7840fec25 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 14 Feb 2014 20:45:30 +0100 Subject: Be more conservative with new const-function code --- frontends/ast/simplify.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 236843d5d..2ae3cae08 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -148,10 +148,14 @@ 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, in_param = true; + const_fold = 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; + // in certain cases a function must be evaluated constant. this is what in_param controls. + if (type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_PREFIX) + in_param = true; + std::map backup_scope; // create name resolution entries for all objects with names -- cgit v1.2.3 From 7ac524e8e8d1745dec4605c32944e318f46daf4e Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 16 Feb 2014 13:16:38 +0100 Subject: Improved support for constant functions --- frontends/ast/simplify.cc | 51 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 2ae3cae08..5e37911d3 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1167,9 +1167,11 @@ skip_dynamic_range_lvalue_expansion:; if (in_param) { bool all_args_const = true; - for (auto child : children) + for (auto child : children) { + while (child->simplify(true, false, false, 1, -1, false, true)) { } if (child->type != AST_CONSTANT) all_args_const = false; + } if (all_args_const) { AstNode *func_workspace = current_scope[str]->clone(); @@ -1931,6 +1933,53 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) continue; } + if (stmt->type == AST_CASE) + { + AstNode *expr = stmt->children.at(0)->clone(); + expr->replace_variables(variables, fcall); + while (expr->simplify(true, false, false, 1, -1, false, true)) { } + + AstNode *sel_case = NULL; + for (size_t i = 1; i < stmt->children.size(); i++) + { + bool found_match = false; + log_assert(stmt->children.at(i)->type == AST_COND); + + if (stmt->children.at(i)->children.front()->type == AST_DEFAULT) { + sel_case = stmt->children.at(i)->children.back(); + continue; + } + + 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(); + cond->replace_variables(variables, fcall); + + cond = new AstNode(AST_EQ, expr->clone(), cond); + while (cond->simplify(true, false, false, 1, -1, false, true)) { } + + if (cond->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); + + found_match = cond->asBool(); + delete cond; + } + + if (found_match) { + sel_case = stmt->children.at(i)->children.back(); + break; + } + } + + block->children.erase(block->children.begin()); + if (sel_case) + block->children.insert(block->children.begin(), sel_case->clone()); + delete stmt; + delete expr; + continue; + } + if (stmt->type == AST_BLOCK) { block->children.erase(block->children.begin()); -- cgit v1.2.3 From f8c9143b2b232e2f22e6cfbf9c431b2a1b756afa Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 22 Feb 2014 17:08:00 +0100 Subject: Fixed bug in generation of undefs for $memwr MUXes --- frontends/ast/simplify.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 5e37911d3..55ed28b01 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1088,14 +1088,16 @@ skip_dynamic_range_lvalue_expansion:; current_scope[wire_en->str] = wire_en; while (wire_en->simplify(true, false, false, 1, -1, false, false)) { } - std::vector x_bits; + std::vector x_bits_addr, x_bits_data; + for (int i = 0; i < addr_bits; i++) + x_bits_addr.push_back(RTLIL::State::Sx); for (int i = 0; i < mem_width; i++) - x_bits.push_back(RTLIL::State::Sx); + x_bits_data.push_back(RTLIL::State::Sx); - AstNode *assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits, false)); + AstNode *assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false)); assign_addr->children[0]->str = id_addr; - AstNode *assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits, false)); + AstNode *assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false)); assign_data->children[0]->str = id_data; AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, 1)); -- cgit v1.2.3 From de7bd12004f24b7e9fff3ba1f253537704db4e44 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 5 Mar 2014 19:45:33 +0100 Subject: Bugfix in recursive AST simplification --- frontends/ast/simplify.cc | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 55ed28b01..72d90e4ae 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -219,7 +219,8 @@ 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, node->type == AST_PARAMETER || node->type == AST_LOCALPARAM)) { } + while (node->simplify(true, false, false, 1, -1, false, node->type == AST_PARAMETER || node->type == AST_LOCALPARAM)) + did_something = true; } } @@ -241,8 +242,10 @@ 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, false) == true) { } - while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false, false) == true) { } + while (!children[0]->basic_prep && children[0]->simplify(false, false, true, stage, -1, false, false) == true) + did_something = true; + while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false, false) == true) + did_something = 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); @@ -251,11 +254,13 @@ 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) == true) { } + while (!children[0]->basic_prep && children[0]->simplify(false, false, false, stage, -1, false, true) == true) + did_something = 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) == true) { } + while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false, true) == true) + did_something = 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); @@ -311,7 +316,8 @@ 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, in_param) == true) { } + while (!child->basic_prep && child->simplify(false, false, in_lvalue, stage, -1, false, in_param) == true) + did_something = true; child->detectSignWidthWorker(width_hint, sign_hint); } reset_width_after_children = true; @@ -341,9 +347,11 @@ 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, in_param) == true) { } + while (!child->basic_prep && child->simplify(false, false, in_lvalue, stage, -1, false, in_param) == true) + did_something = true; if (type == AST_REPLICATE) - while (children[0]->simplify(true, false, in_lvalue, stage, -1, false, in_param) == true) { } + while (children[0]->simplify(true, false, in_lvalue, stage, -1, false, in_param) == true) + did_something = true; detectSignWidth(width_hint, sign_hint); } @@ -389,7 +397,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } } for (auto &attr : attributes) { - while (attr.second->simplify(true, false, false, stage, -1, false, true)) { } + while (attr.second->simplify(true, false, false, stage, -1, false, true)) + did_something = true; } if (reset_width_after_children) { @@ -539,7 +548,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, current_scope[str] = auto_wire; did_something = true; } - id2ast = current_scope[str]; + if (id2ast != current_scope[str]) { + id2ast = current_scope[str]; + did_something = true; + } } // split memory access with bit select to individual statements -- cgit v1.2.3 From d6a01fe412419d32ec5b0d91f9076849d1ed489d Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 5 Mar 2014 19:55:58 +0100 Subject: Fixed merging of compatible wire decls in AST frontend --- frontends/ast/simplify.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 72d90e4ae..a20aacff5 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -206,10 +206,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, did_something = true; delete node; continue; + wires_are_incompatible: + if (stage > 1) + log_error("Incompatible re-declaration of wire %s at %s:%d.\n", node->str.c_str(), filename.c_str(), linenum); + continue; } this_wire_scope[node->str] = node; } - wires_are_incompatible: if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_GENVAR || node->type == AST_MEMORY || node->type == AST_FUNCTION || node->type == AST_TASK || node->type == AST_CELL) { backup_scope[node->str] = current_scope[node->str]; -- cgit v1.2.3 From ab54ce17c82e55cb26bf5c0dd7512decbd941b12 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 6 Jun 2014 17:40:45 +0200 Subject: improved ast simplify of const functions --- frontends/ast/simplify.cc | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index a20aacff5..5f40b60a8 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -140,7 +140,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (type == AST_FUNCTION || type == AST_TASK) return false; - // deactivate all calls non-synthesis system taks + // deactivate all calls to non-synthesis system taks if ((type == AST_FCALL || type == AST_TCALL) && (str == "$display" || str == "$stop" || str == "$finish")) { delete_children(); str = std::string(); @@ -245,9 +245,9 @@ 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, false) == true) + while (!children[0]->basic_prep && children[0]->simplify(false, false, true, stage, -1, false, in_param) == true) did_something = true; - while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false, false) == true) + while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false, in_param) == true) did_something = true; children[0]->detectSignWidth(backup_width_hint, backup_sign_hint); children[1]->detectSignWidth(width_hint, sign_hint); @@ -1825,12 +1825,16 @@ void AstNode::replace_variables(std::map &varia if (type == AST_IDENTIFIER && variables.count(str)) { int offset = variables.at(str).offset, width = variables.at(str).val.bits.size(); if (!children.empty()) { + if (children.size() != 1 || children.at(0)->type != AST_RANGE) + log_error("Memory access in constant function is not supported in %s:%d (called from %s:%d).\n", + filename.c_str(), linenum, fcall->filename.c_str(), fcall->linenum); + children.at(0)->replace_variables(variables, fcall); while (simplify(true, false, false, 1, -1, false, true)) { } - if (!range_valid) + if (!children.at(0)->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 = std::min(children.at(0)->range_left, children.at(0)->range_right); + width = std::min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width); } offset -= variables.at(str).offset; std::vector &var_bits = variables.at(str).val.bits; @@ -1850,6 +1854,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) { std::map backup_scope; std::map variables; + bool delete_temp_block = false; AstNode *block = NULL; size_t argidx = 0; @@ -1878,6 +1883,16 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) continue; } + if (child->type == AST_ASSIGN_EQ) + { + log_assert(block == NULL); + delete_temp_block = true; + block = new AstNode(AST_BLOCK); + block->children.push_back(child->clone()); + continue; + } + + child->dumpAst(NULL, "unexpected> "); log_abort(); } @@ -1900,8 +1915,11 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) stmt->children.at(1)->replace_variables(variables, fcall); while (stmt->simplify(true, false, false, 1, -1, false, true)) { } + if (stmt->type != AST_ASSIGN_EQ) + continue; + if (stmt->children.at(1)->type != AST_CONSTANT) - log_error("Non-constant expression in constant function at %s:%d (called from %s:%d).\n", + log_error("Non-constant expression in constant function at %s:%d (called from %s:%d). X\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()) @@ -2011,6 +2029,9 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) log_abort(); } + if (delete_temp_block) + delete block; + for (auto &it : backup_scope) if (it.second == NULL) current_scope.erase(it.first); -- cgit v1.2.3 From 5c10d2ee364c8807d10069ba7be3d1da3d252fa1 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 6 Jun 2014 21:29:23 +0200 Subject: fix functions with no block (but single statement, loop, etc.) --- frontends/ast/simplify.cc | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 5f40b60a8..47ea880c6 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1883,17 +1883,10 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) continue; } - if (child->type == AST_ASSIGN_EQ) - { - log_assert(block == NULL); - delete_temp_block = true; - block = new AstNode(AST_BLOCK); - block->children.push_back(child->clone()); - continue; - } - - child->dumpAst(NULL, "unexpected> "); - log_abort(); + log_assert(block == NULL); + delete_temp_block = true; + block = new AstNode(AST_BLOCK); + block->children.push_back(child->clone()); } log_assert(block != NULL); -- cgit v1.2.3 From 76da2fe172ed6b0822a9e4a8cf9483ef7c8f5f40 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 6 Jun 2014 22:55:02 +0200 Subject: improved const function support --- frontends/ast/simplify.cc | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 47ea880c6..71e7cbc6d 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -606,6 +606,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, goto apply_newNode; } + if (type == AST_WHILE) + log_error("While loops are only allowed in constant functions at %s:%d!\n", filename.c_str(), linenum); + + if (type == AST_REPEAT) + log_error("Repeat loops are only allowed in constant functions at %s:%d!\n", filename.c_str(), linenum); + // unroll for loops and generate-for blocks if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0) { @@ -1181,7 +1187,7 @@ 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) + if (in_param || current_scope[str]->has_const_only_constructs()) { bool all_args_const = true; for (auto child : children) { @@ -1197,7 +1203,10 @@ skip_dynamic_range_lvalue_expansion:; goto apply_newNode; } - log_error("Non-constant function call in constant expression at %s:%d.\n", filename.c_str(), linenum); + if (in_param) + log_error("Non-constant function call in constant expression at %s:%d.\n", filename.c_str(), linenum); + else + log_error("Function %s can only be called with constant arguments at %s:%d.\n", str.c_str(), filename.c_str(), linenum); } AstNode *decl = current_scope[str]; @@ -1819,6 +1828,19 @@ void AstNode::meminfo(int &mem_width, int &mem_size, int &addr_bits) addr_bits++; } +bool AstNode::has_const_only_constructs() +{ + if (type == AST_WHILE || type == AST_REPEAT) + return true; + if (type == AST_FCALL && current_scope.count(str)) + if (current_scope[str]->has_const_only_constructs()) + return true; + for (auto child : children) + if (child->AstNode::has_const_only_constructs()) + return true; + return false; +} + // helper function for AstNode::eval_const_function() void AstNode::replace_variables(std::map &variables, AstNode *fcall) { @@ -1915,7 +1937,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) log_error("Non-constant expression in constant function at %s:%d (called from %s:%d). X\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()) + if (stmt->children.at(0)->type != AST_IDENTIFIER) 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); @@ -1923,7 +1945,20 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) 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()); + 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()); + } else { + AstNode *range = stmt->children.at(0)->children.at(0); + if (!range->range_valid) + log_error("Non-constant range in %s:%d (called from %s:%d).\n", + range->filename.c_str(), range->linenum, fcall->filename.c_str(), fcall->linenum); + int offset = std::min(range->range_left, range->range_right); + int width = std::min(std::abs(range->range_left - range->range_right) + 1, width); + varinfo_t &v = variables[stmt->children.at(0)->str]; + RTLIL::Const r = stmt->children.at(1)->bitsAsConst(v.val.bits.size()); + for (int i = 0; i < width; i++) + v.val.bits.at(i+offset-v.offset) = r.bits.at(i); + } delete block->children.front(); block->children.erase(block->children.begin()); -- cgit v1.2.3 From 7c8a7b2131aa672d04ee0ed641f3e6b120f3ec49 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 7 Jun 2014 00:02:05 +0200 Subject: further improved const function support --- frontends/ast/simplify.cc | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 71e7cbc6d..8a4d42e1b 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -349,12 +349,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } if (detect_width_simple && width_hint < 0) { + if (type == AST_REPLICATE) + while (children[0]->simplify(true, false, in_lvalue, stage, -1, false, true) == true) + did_something = true; for (auto child : children) while (!child->basic_prep && child->simplify(false, false, in_lvalue, stage, -1, false, in_param) == true) did_something = true; - if (type == AST_REPLICATE) - while (children[0]->simplify(true, false, in_lvalue, stage, -1, false, in_param) == true) - did_something = true; detectSignWidth(width_hint, sign_hint); } @@ -376,8 +376,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, bool const_fold_here = const_fold, in_lvalue_here = in_lvalue; int width_hint_here = width_hint; bool sign_hint_here = sign_hint; - if (i == 0 && type == AST_REPLICATE) - const_fold_here = true; + bool in_param_here = in_param; + if (i == 0 && (type == AST_REPLICATE || type == AST_WIRE)) + const_fold_here = true, in_param_here = true; if (type == AST_PARAMETER || type == AST_LOCALPARAM) const_fold_here = true; if (i == 0 && (type == AST_ASSIGN || type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE)) @@ -394,7 +395,7 @@ 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, in_param); + did_something_here = children[i]->simplify(const_fold_here, at_zero, in_lvalue_here, stage, width_hint_here, sign_hint_here, in_param_here); if (did_something_here) did_something = true; } @@ -1187,7 +1188,9 @@ 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 || current_scope[str]->has_const_only_constructs()) + bool recommend_const_eval = false; + bool require_const_eval = in_param ? false : has_const_only_constructs(recommend_const_eval); + if (in_param || recommend_const_eval || require_const_eval) { bool all_args_const = true; for (auto child : children) { @@ -1205,7 +1208,7 @@ skip_dynamic_range_lvalue_expansion:; if (in_param) log_error("Non-constant function call in constant expression at %s:%d.\n", filename.c_str(), linenum); - else + if (require_const_eval) log_error("Function %s can only be called with constant arguments at %s:%d.\n", str.c_str(), filename.c_str(), linenum); } @@ -1828,15 +1831,17 @@ void AstNode::meminfo(int &mem_width, int &mem_size, int &addr_bits) addr_bits++; } -bool AstNode::has_const_only_constructs() +bool AstNode::has_const_only_constructs(bool &recommend_const_eval) { + if (type == AST_FOR) + recommend_const_eval = true; if (type == AST_WHILE || type == AST_REPEAT) return true; if (type == AST_FCALL && current_scope.count(str)) - if (current_scope[str]->has_const_only_constructs()) + if (current_scope[str]->has_const_only_constructs(recommend_const_eval)) return true; for (auto child : children) - if (child->AstNode::has_const_only_constructs()) + if (child->AstNode::has_const_only_constructs(recommend_const_eval)) return true; return false; } -- cgit v1.2.3 From 0b1ce63a19025f73fe4d2a54253134ea9a4de625 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 7 Jun 2014 10:47:53 +0200 Subject: Added support for repeat stmt in const functions --- frontends/ast/simplify.cc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 8a4d42e1b..e5e8980a2 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -2001,6 +2001,25 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) continue; } + if (stmt->type == AST_REPEAT) + { + AstNode *num = stmt->children.at(0)->clone(); + num->replace_variables(variables, fcall); + while (num->simplify(true, false, false, 1, -1, false, true)) { } + + if (num->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); + + block->children.erase(block->children.begin()); + for (int i = 0; i < num->bitsAsConst().as_int(); i++) + block->children.insert(block->children.begin(), stmt->children.at(1)->clone()); + + delete stmt; + delete num; + continue; + } + if (stmt->type == AST_CASE) { AstNode *expr = stmt->children.at(0)->clone(); -- cgit v1.2.3 From e275e8eef9ae47670075bd73a671f3acd3c0ca52 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 7 Jun 2014 11:48:50 +0200 Subject: Add support for cell arrays --- frontends/ast/simplify.cc | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index e5e8980a2..fc040baac 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -878,6 +878,31 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, did_something = true; } + // unroll cell arrays + if (type == AST_CELLARRAY) + { + if (!children.at(0)->range_valid) + log_error("Non-constant array range on cell array at %s:%d.\n", filename.c_str(), linenum); + + newNode = new AstNode(AST_GENBLOCK); + int num = std::max(children.at(0)->range_left, children.at(0)->range_right) - std::min(children.at(0)->range_left, children.at(0)->range_right) + 1; + + for (int i = 0; i < num; i++) { + int idx = children.at(0)->range_left > children.at(0)->range_right ? children.at(0)->range_right + i : children.at(0)->range_right - i; + AstNode *new_cell = children.at(1)->clone(); + newNode->children.push_back(new_cell); + new_cell->str += stringf("[%d]", idx); + if (new_cell->type == AST_PRIMITIVE) { + log_error("Cell arrays of primitives are currently not supported at %s:%d.\n", filename.c_str(), linenum); + } else { + log_assert(new_cell->children.at(0)->type == AST_CELLTYPE); + new_cell->children.at(0)->str = stringf("$array:%d:%d:%s", i, num, new_cell->children.at(0)->str.c_str()); + } + } + + goto apply_newNode; + } + // replace primitives with assignmens if (type == AST_PRIMITIVE) { -- cgit v1.2.3 From 442a8e2875eab679ed3b31aee3d9725b87dbf4fc Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 14 Jun 2014 08:51:22 +0200 Subject: Implemented basic real arithmetic --- frontends/ast/simplify.cc | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index fc040baac..7e4c265bd 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -32,7 +32,7 @@ #include #include -#include +#include using namespace AST; using namespace AST_INTERNAL; @@ -1433,10 +1433,22 @@ skip_dynamic_range_lvalue_expansion:; if (0) { case AST_MUL: const_func = RTLIL::const_mul; } if (0) { case AST_DIV: const_func = RTLIL::const_div; } if (0) { case AST_MOD: const_func = RTLIL::const_mod; } - if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) { - RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), - children[1]->bitsAsConst(width_hint, sign_hint), sign_hint, sign_hint, width_hint); - newNode = mkconst_bits(y.bits, sign_hint); + if (children[0]->isConst() && children[1]->isConst()) { + if (children[0]->isConst() + children[1]->isConst() > 2) { + newNode = new AstNode(AST_REALVALUE); + switch (type) { + case AST_ADD: newNode->realvalue = children[0]->asReal(sign_hint) + children[1]->asReal(sign_hint); break; + case AST_SUB: newNode->realvalue = children[0]->asReal(sign_hint) - children[1]->asReal(sign_hint); break; + case AST_MUL: newNode->realvalue = children[0]->asReal(sign_hint) * children[1]->asReal(sign_hint); break; + case AST_DIV: newNode->realvalue = children[0]->asReal(sign_hint) / children[1]->asReal(sign_hint); break; + case AST_MOD: newNode->realvalue = fmod(children[0]->asReal(sign_hint), children[1]->asReal(sign_hint)); break; + default: log_abort(); + } + } else { + RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), + children[1]->bitsAsConst(width_hint, sign_hint), sign_hint, sign_hint, width_hint); + newNode = mkconst_bits(y.bits, sign_hint); + } } break; if (0) { case AST_POS: const_func = RTLIL::const_pos; } -- cgit v1.2.3 From fc7b6d172a67965c89d84696e5f2cf1218855ea5 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 14 Jun 2014 11:27:05 +0200 Subject: Implemented more real arithmetic --- frontends/ast/simplify.cc | 97 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 70 insertions(+), 27 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 7e4c265bd..77bab6b0d 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1348,7 +1348,9 @@ skip_dynamic_range_lvalue_expansion:; } else if (children.size() == 0) newNode = current_scope[str]->children[0]->clone(); - } + } else + if (current_scope[str]->children[0]->isConst()) + newNode = current_scope[str]->children[0]->clone(); } else if (at_zero && current_scope.count(str) > 0 && (current_scope[str]->type == AST_WIRE || current_scope[str]->type == AST_AUTOWIRE)) { newNode = mkconst_int(0, sign_hint, width_hint); @@ -1391,6 +1393,9 @@ skip_dynamic_range_lvalue_expansion:; if (children[0]->type == AST_CONSTANT) { RTLIL::Const y = RTLIL::const_logic_not(RTLIL::Const(children[0]->bits), dummy_arg, children[0]->is_signed, false, -1); newNode = mkconst_bits(y.bits, false); + } else + if (children[0]->isConst()) { + newNode = mkconst_int(children[0]->asReal(sign_hint) == 0, false, 1); } break; if (0) { case AST_LOGIC_AND: const_func = RTLIL::const_logic_and; } @@ -1399,6 +1404,12 @@ skip_dynamic_range_lvalue_expansion:; RTLIL::Const y = const_func(RTLIL::Const(children[0]->bits), RTLIL::Const(children[1]->bits), children[0]->is_signed, children[1]->is_signed, -1); newNode = mkconst_bits(y.bits, false); + } else + if (children[0]->isConst() && children[1]->isConst()) { + if (type == AST_LOGIC_AND) + newNode = mkconst_int((children[0]->asReal(sign_hint) != 0) && (children[1]->asReal(sign_hint) != 0), false, 1); + else + newNode = mkconst_int((children[0]->asReal(sign_hint) != 0) || (children[1]->asReal(sign_hint) != 0), false, 1); } break; if (0) { case AST_SHIFT_LEFT: const_func = RTLIL::const_shl; } @@ -1410,6 +1421,10 @@ skip_dynamic_range_lvalue_expansion:; RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), RTLIL::Const(children[1]->bits), sign_hint, type == AST_POW ? children[1]->is_signed : false, width_hint); newNode = mkconst_bits(y.bits, sign_hint); + } else + if (type == AST_POW && children[0]->isConst() && children[1]->isConst()) { + newNode = new AstNode(AST_REALVALUE); + newNode->realvalue = pow(children[0]->asReal(sign_hint), children[1]->asReal(sign_hint)); } break; if (0) { case AST_LT: const_func = RTLIL::const_lt; } @@ -1426,6 +1441,19 @@ skip_dynamic_range_lvalue_expansion:; RTLIL::Const y = const_func(children[0]->bitsAsConst(cmp_width, cmp_signed), children[1]->bitsAsConst(cmp_width, cmp_signed), cmp_signed, cmp_signed, 1); newNode = mkconst_bits(y.bits, false); + } else + if (children[0]->isConst() && children[1]->isConst()) { + switch (type) { + case AST_LT: newNode = mkconst_int(children[0]->asReal(sign_hint) < children[1]->asReal(sign_hint), false, 1); + case AST_LE: newNode = mkconst_int(children[0]->asReal(sign_hint) <= children[1]->asReal(sign_hint), false, 1); + case AST_EQ: newNode = mkconst_int(children[0]->asReal(sign_hint) == children[1]->asReal(sign_hint), false, 1); + case AST_NE: newNode = mkconst_int(children[0]->asReal(sign_hint) != children[1]->asReal(sign_hint), false, 1); + case AST_EQX: newNode = mkconst_int(children[0]->asReal(sign_hint) == children[1]->asReal(sign_hint), false, 1); + case AST_NEX: newNode = mkconst_int(children[0]->asReal(sign_hint) != children[1]->asReal(sign_hint), false, 1); + case AST_GE: newNode = mkconst_int(children[0]->asReal(sign_hint) >= children[1]->asReal(sign_hint), false, 1); + case AST_GT: newNode = mkconst_int(children[0]->asReal(sign_hint) > children[1]->asReal(sign_hint), false, 1); + default: log_abort(); + } } break; if (0) { case AST_ADD: const_func = RTLIL::const_add; } @@ -1433,21 +1461,20 @@ skip_dynamic_range_lvalue_expansion:; if (0) { case AST_MUL: const_func = RTLIL::const_mul; } if (0) { case AST_DIV: const_func = RTLIL::const_div; } if (0) { case AST_MOD: const_func = RTLIL::const_mod; } + if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) { + RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), + children[1]->bitsAsConst(width_hint, sign_hint), sign_hint, sign_hint, width_hint); + newNode = mkconst_bits(y.bits, sign_hint); + } else if (children[0]->isConst() && children[1]->isConst()) { - if (children[0]->isConst() + children[1]->isConst() > 2) { - newNode = new AstNode(AST_REALVALUE); - switch (type) { - case AST_ADD: newNode->realvalue = children[0]->asReal(sign_hint) + children[1]->asReal(sign_hint); break; - case AST_SUB: newNode->realvalue = children[0]->asReal(sign_hint) - children[1]->asReal(sign_hint); break; - case AST_MUL: newNode->realvalue = children[0]->asReal(sign_hint) * children[1]->asReal(sign_hint); break; - case AST_DIV: newNode->realvalue = children[0]->asReal(sign_hint) / children[1]->asReal(sign_hint); break; - case AST_MOD: newNode->realvalue = fmod(children[0]->asReal(sign_hint), children[1]->asReal(sign_hint)); break; - default: log_abort(); - } - } else { - RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), - children[1]->bitsAsConst(width_hint, sign_hint), sign_hint, sign_hint, width_hint); - newNode = mkconst_bits(y.bits, sign_hint); + newNode = new AstNode(AST_REALVALUE); + switch (type) { + case AST_ADD: newNode->realvalue = children[0]->asReal(sign_hint) + children[1]->asReal(sign_hint); break; + case AST_SUB: newNode->realvalue = children[0]->asReal(sign_hint) - children[1]->asReal(sign_hint); break; + case AST_MUL: newNode->realvalue = children[0]->asReal(sign_hint) * children[1]->asReal(sign_hint); break; + case AST_DIV: newNode->realvalue = children[0]->asReal(sign_hint) / children[1]->asReal(sign_hint); break; + case AST_MOD: newNode->realvalue = fmod(children[0]->asReal(sign_hint), children[1]->asReal(sign_hint)); break; + default: log_abort(); } } break; @@ -1456,29 +1483,45 @@ skip_dynamic_range_lvalue_expansion:; if (children[0]->type == AST_CONSTANT) { RTLIL::Const y = const_func(children[0]->bitsAsConst(width_hint, sign_hint), dummy_arg, sign_hint, false, width_hint); newNode = mkconst_bits(y.bits, sign_hint); + } else + if (children[0]->isConst()) { + newNode = new AstNode(AST_REALVALUE); + if (type == AST_POS) + newNode->realvalue = +children[0]->asReal(sign_hint); + else + newNode->realvalue = -children[0]->asReal(sign_hint); } break; case AST_TERNARY: - if (children[0]->type == AST_CONSTANT) { + if (children[0]->isConst()) { bool found_sure_true = false; bool found_maybe_true = false; - for (auto &bit : children[0]->bits) { - if (bit == RTLIL::State::S1) - found_sure_true = true; - if (bit > RTLIL::State::S1) - found_maybe_true = true; + if (children[0]->type == AST_CONSTANT) { + for (auto &bit : children[0]->bits) { + if (bit == RTLIL::State::S1) + found_sure_true = true; + if (bit > RTLIL::State::S1) + found_maybe_true = true; + } + } else { + found_sure_true = children[0]->asReal(false) != 0; } AstNode *choice = NULL; if (found_sure_true) choice = children[1]; else if (!found_maybe_true) choice = children[2]; - if (choice != NULL && choice->type == AST_CONSTANT) { - RTLIL::Const y = choice->bitsAsConst(width_hint, sign_hint); - if (choice->is_string && y.bits.size() % 8 == 0 && sign_hint == false) - newNode = mkconst_str(y.bits); - else - newNode = mkconst_bits(y.bits, sign_hint); + if (choice != NULL) { + if (choice->type == AST_CONSTANT) { + RTLIL::Const y = choice->bitsAsConst(width_hint, sign_hint); + if (choice->is_string && y.bits.size() % 8 == 0 && sign_hint == false) + newNode = mkconst_str(y.bits); + else + newNode = mkconst_bits(y.bits, sign_hint); + } else + if (choice->isConst()) { + newNode = choice->clone(); + } } else if (children[1]->type == AST_CONSTANT && children[2]->type == AST_CONSTANT) { RTLIL::Const a = children[1]->bitsAsConst(width_hint, sign_hint); RTLIL::Const b = children[2]->bitsAsConst(width_hint, sign_hint); -- cgit v1.2.3 From 9bd7d5c46856f25fd7befcdfe20198fd8eb59ccd Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 14 Jun 2014 12:00:47 +0200 Subject: Added handling of real-valued parameters/localparams --- frontends/ast/simplify.cc | 51 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 13 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 77bab6b0d..a5c4d0230 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -48,6 +48,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, AstNode *newNode = NULL; bool did_something = false; +#if 0 + log("-------------\n"); + log("const_fold=%d, at_zero=%d, in_lvalue=%d, stage=%d, width_hint=%d, sign_hint=%d, in_param=%d\n", + int(const_fold), int(at_zero), int(in_lvalue), int(stage), int(width_hint), int(sign_hint), int(in_param)); + dumpAst(NULL, "> "); +#endif + if (stage == 0) { assert(type == AST_MODULE); @@ -260,8 +267,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, while (!children[0]->basic_prep && children[0]->simplify(false, false, false, stage, -1, false, true) == true) did_something = true; children[0]->detectSignWidth(width_hint, sign_hint); - if (children.size() > 1) { - assert(children[1]->type == AST_RANGE); + if (children.size() > 1 && children[1]->type == AST_RANGE) { while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false, true) == true) did_something = true; if (!children[1]->range_valid) @@ -519,18 +525,37 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } // trim/extend parameters - if ((type == AST_PARAMETER || type == AST_LOCALPARAM) && children[0]->type == AST_CONSTANT && children.size() > 1) { - if (!children[1]->range_valid) - log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum); - int width = children[1]->range_left - children[1]->range_right + 1; - if (width != int(children[0]->bits.size())) { - RTLIL::SigSpec sig(children[0]->bits); - sig.extend_u0(width, children[0]->is_signed); - AstNode *old_child_0 = children[0]; - children[0] = mkconst_bits(sig.as_const().bits, children[0]->is_signed); - delete old_child_0; + if (type == AST_PARAMETER || type == AST_LOCALPARAM) { + if (children.size() > 1 && children[1]->type == AST_RANGE) { + if (children[0]->type == AST_REALVALUE) { + int intvalue = round(children[0]->realvalue); + log("Warning: converting real value %e to integer %d at %s:%d.\n", + children[0]->realvalue, intvalue, filename.c_str(), linenum); + delete children[0]; + children[0] = mkconst_int(intvalue, sign_hint); + did_something = true; + } + if (children[0]->type == AST_CONSTANT) { + if (!children[1]->range_valid) + log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum); + int width = children[1]->range_left - children[1]->range_right + 1; + if (width != int(children[0]->bits.size())) { + RTLIL::SigSpec sig(children[0]->bits); + sig.extend_u0(width, children[0]->is_signed); + AstNode *old_child_0 = children[0]; + children[0] = mkconst_bits(sig.as_const().bits, children[0]->is_signed); + delete old_child_0; + } + children[0]->is_signed = is_signed; + } + } else + if (children.size() > 1 && children[1]->type == AST_REALVALUE && children[0]->type == AST_CONSTANT) { + double as_realvalue = children[0]->asReal(sign_hint); + delete children[0]; + children[0] = new AstNode(AST_REALVALUE); + children[0]->realvalue = as_realvalue; + did_something = true; } - children[0]->is_signed = is_signed; } // annotate identifiers using scope resolution and create auto-wires as needed -- cgit v1.2.3 From f3b4a9dd2466d243fdb1b4ebf8c5e1e0d05d21af Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 14 Jun 2014 13:36:23 +0200 Subject: Added support for math functions --- frontends/ast/simplify.cc | 70 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index a5c4d0230..89dc8ef73 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1215,6 +1215,10 @@ skip_dynamic_range_lvalue_expansion:; { if (str == "\\$clog2") { + if (children.size() != 1) + log_error("System function %s got %d arguments, expected 1 at %s:%d.\n", + RTLIL::id2cstr(str), int(children.size()), filename.c_str(), linenum); + AstNode *buf = children[0]->clone(); while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } if (buf->type != AST_CONSTANT) @@ -1230,6 +1234,72 @@ skip_dynamic_range_lvalue_expansion:; goto apply_newNode; } + if (str == "\\$ln" || str == "\\$log10" || str == "\\$exp" || str == "\\$sqrt" || str == "\\$pow" || + str == "\\$floor" || str == "\\$ceil" || str == "\\$sin" || str == "\\$cos" || str == "\\$tan" || + str == "\\$asin" || str == "\\$acos" || str == "\\$atan" || str == "\\$atan2" || str == "\\$hypot" || + str == "\\$sinh" || str == "\\$cosh" || str == "\\$tanh" || str == "\\$asinh" || str == "\\$acosh" || str == "\\$atanh") + { + bool func_with_two_arguments = str == "\\$pow" || str == "\\$atan2" || str == "\\$hypot"; + double x = 0, y = 0; + + if (func_with_two_arguments) { + if (children.size() != 2) + log_error("System function %s got %d arguments, expected 2 at %s:%d.\n", + RTLIL::id2cstr(str), int(children.size()), filename.c_str(), linenum); + } else { + if (children.size() != 1) + log_error("System function %s got %d arguments, expected 1 at %s:%d.\n", + RTLIL::id2cstr(str), int(children.size()), filename.c_str(), linenum); + } + + if (children.size() >= 1) { + while (children[0]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } + if (!children[0]->isConst()) + log_error("Failed to evaluate system function `%s' with non-constant argument at %s:%d.\n", + RTLIL::id2cstr(str), filename.c_str(), linenum); + int child_width_hint = width_hint; + bool child_sign_hint = sign_hint; + children[0]->detectSignWidth(child_width_hint, child_sign_hint); + x = children[0]->asReal(child_sign_hint); + } + + if (children.size() >= 2) { + while (children[1]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } + if (!children[1]->isConst()) + log_error("Failed to evaluate system function `%s' with non-constant argument at %s:%d.\n", + RTLIL::id2cstr(str), filename.c_str(), linenum); + int child_width_hint = width_hint; + bool child_sign_hint = sign_hint; + children[1]->detectSignWidth(child_width_hint, child_sign_hint); + y = children[1]->asReal(child_sign_hint); + } + + newNode = new AstNode(AST_REALVALUE); + if (str == "\\$ln") newNode->realvalue = log(x); + else if (str == "\\$log10") newNode->realvalue = log10(x); + else if (str == "\\$exp") newNode->realvalue = exp(x); + else if (str == "\\$sqrt") newNode->realvalue = sqrt(x); + else if (str == "\\$pow") newNode->realvalue = pow(x, y); + else if (str == "\\$floor") newNode->realvalue = floor(x); + else if (str == "\\$ceil") newNode->realvalue = ceil(x); + else if (str == "\\$sin") newNode->realvalue = sin(x); + else if (str == "\\$cos") newNode->realvalue = cos(x); + else if (str == "\\$tan") newNode->realvalue = tan(x); + else if (str == "\\$asin") newNode->realvalue = asin(x); + else if (str == "\\$acos") newNode->realvalue = acos(x); + else if (str == "\\$atan") newNode->realvalue = atan(x); + else if (str == "\\$atan2") newNode->realvalue = atan2(x, y); + else if (str == "\\$hypot") newNode->realvalue = hypot(x, y); + else if (str == "\\$sinh") newNode->realvalue = sinh(x); + else if (str == "\\$cosh") newNode->realvalue = cosh(x); + else if (str == "\\$tanh") newNode->realvalue = tanh(x); + else if (str == "\\$asinh") newNode->realvalue = asinh(x); + else if (str == "\\$acosh") newNode->realvalue = acosh(x); + else if (str == "\\$atanh") newNode->realvalue = atanh(x); + else log_abort(); + goto apply_newNode; + } + if (current_scope.count(str) == 0 || current_scope[str]->type != AST_FUNCTION) log_error("Can't resolve function name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum); } -- cgit v1.2.3 From d5765b5e14319c20a62a20f470e8ec5dc48d0010 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 14 Jun 2014 19:33:58 +0200 Subject: Fixed relational operators for const real expressions --- frontends/ast/simplify.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 89dc8ef73..61bc03b9f 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1539,14 +1539,14 @@ skip_dynamic_range_lvalue_expansion:; } else if (children[0]->isConst() && children[1]->isConst()) { switch (type) { - case AST_LT: newNode = mkconst_int(children[0]->asReal(sign_hint) < children[1]->asReal(sign_hint), false, 1); - case AST_LE: newNode = mkconst_int(children[0]->asReal(sign_hint) <= children[1]->asReal(sign_hint), false, 1); - case AST_EQ: newNode = mkconst_int(children[0]->asReal(sign_hint) == children[1]->asReal(sign_hint), false, 1); - case AST_NE: newNode = mkconst_int(children[0]->asReal(sign_hint) != children[1]->asReal(sign_hint), false, 1); - case AST_EQX: newNode = mkconst_int(children[0]->asReal(sign_hint) == children[1]->asReal(sign_hint), false, 1); - case AST_NEX: newNode = mkconst_int(children[0]->asReal(sign_hint) != children[1]->asReal(sign_hint), false, 1); - case AST_GE: newNode = mkconst_int(children[0]->asReal(sign_hint) >= children[1]->asReal(sign_hint), false, 1); - case AST_GT: newNode = mkconst_int(children[0]->asReal(sign_hint) > children[1]->asReal(sign_hint), false, 1); + case AST_LT: newNode = mkconst_int(children[0]->asReal(sign_hint) < children[1]->asReal(sign_hint), false, 1); break; + case AST_LE: newNode = mkconst_int(children[0]->asReal(sign_hint) <= children[1]->asReal(sign_hint), false, 1); break; + case AST_EQ: newNode = mkconst_int(children[0]->asReal(sign_hint) == children[1]->asReal(sign_hint), false, 1); break; + case AST_NE: newNode = mkconst_int(children[0]->asReal(sign_hint) != children[1]->asReal(sign_hint), false, 1); break; + case AST_EQX: newNode = mkconst_int(children[0]->asReal(sign_hint) == children[1]->asReal(sign_hint), false, 1); break; + case AST_NEX: newNode = mkconst_int(children[0]->asReal(sign_hint) != children[1]->asReal(sign_hint), false, 1); break; + case AST_GE: newNode = mkconst_int(children[0]->asReal(sign_hint) >= children[1]->asReal(sign_hint), false, 1); break; + case AST_GT: newNode = mkconst_int(children[0]->asReal(sign_hint) > children[1]->asReal(sign_hint), false, 1); break; default: log_abort(); } } -- cgit v1.2.3 From 149fe83a8dbe37fecc16326163bbc40400147a9a Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 14 Jun 2014 20:38:05 +0200 Subject: improved (fixed) conversion of real values to bit vectors --- frontends/ast/simplify.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 61bc03b9f..ed5ee1721 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -527,18 +527,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, // trim/extend parameters if (type == AST_PARAMETER || type == AST_LOCALPARAM) { if (children.size() > 1 && children[1]->type == AST_RANGE) { + if (!children[1]->range_valid) + log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum); + int width = children[1]->range_left - children[1]->range_right + 1; if (children[0]->type == AST_REALVALUE) { - int intvalue = round(children[0]->realvalue); - log("Warning: converting real value %e to integer %d at %s:%d.\n", - children[0]->realvalue, intvalue, filename.c_str(), linenum); + RTLIL::Const constvalue = children[0]->realAsConst(width); + log("Warning: converting real value %e to binary %s at %s:%d.\n", + realvalue, log_signal(constvalue), filename.c_str(), linenum); delete children[0]; - children[0] = mkconst_int(intvalue, sign_hint); + children[0] = mkconst_bits(constvalue.bits, sign_hint); did_something = true; } if (children[0]->type == AST_CONSTANT) { - if (!children[1]->range_valid) - log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum); - int width = children[1]->range_left - children[1]->range_right + 1; if (width != int(children[0]->bits.size())) { RTLIL::SigSpec sig(children[0]->bits); sig.extend_u0(width, children[0]->is_signed); -- cgit v1.2.3 From 48dc6ab98dbd74bd7eb00f14b4bd8429531166f3 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 15 Jun 2014 08:38:31 +0200 Subject: Improved AstNode::asReal for large integers --- frontends/ast/simplify.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index ed5ee1721..80fd28d55 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -533,7 +533,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (children[0]->type == AST_REALVALUE) { RTLIL::Const constvalue = children[0]->realAsConst(width); log("Warning: converting real value %e to binary %s at %s:%d.\n", - realvalue, log_signal(constvalue), filename.c_str(), linenum); + children[0]->realvalue, log_signal(constvalue), filename.c_str(), linenum); delete children[0]; children[0] = mkconst_bits(constvalue.bits, sign_hint); did_something = true; -- cgit v1.2.3 From 82bbd2f0772e62555eb669eb64883d75de4ca29a Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 16 Jun 2014 15:05:37 +0200 Subject: Use undef (x/z vs. NaN) rules for real values from IEEE Std 1800-2012 --- frontends/ast/simplify.cc | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 80fd28d55..3f712510b 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1625,6 +1625,15 @@ skip_dynamic_range_lvalue_expansion:; if (a.bits[i] != b.bits[i]) a.bits[i] = RTLIL::State::Sx; newNode = mkconst_bits(a.bits, sign_hint); + } else if (children[1]->isConst() && children[2]->isConst()) { + newNode = new AstNode(AST_REALVALUE); + if (children[1]->asReal(sign_hint) == children[2]->asReal(sign_hint)) + newNode->realvalue = children[1]->asReal(sign_hint); + else + // IEEE Std 1800-2012 Sec. 11.4.11 states that the entry in Table 7-1 for + // the data type in question should be returned if the ?: is ambiguous. The + // value in Table 7-1 for the 'real' type is 0.0. + newNode->realvalue = 0.0; } } break; -- cgit v1.2.3 From 6c17d4f242ae2acb1581869b3ca904a0adbddc13 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 16 Jun 2014 15:12:24 +0200 Subject: Improved ternary support for real values --- frontends/ast/simplify.cc | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 3f712510b..7be287d19 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1588,31 +1588,42 @@ skip_dynamic_range_lvalue_expansion:; } break; case AST_TERNARY: - if (children[0]->isConst()) { + if (children[0]->isConst()) + { bool found_sure_true = false; bool found_maybe_true = false; - if (children[0]->type == AST_CONSTANT) { + + if (children[0]->type == AST_CONSTANT) for (auto &bit : children[0]->bits) { if (bit == RTLIL::State::S1) found_sure_true = true; if (bit > RTLIL::State::S1) found_maybe_true = true; } - } else { - found_sure_true = children[0]->asReal(false) != 0; - } - AstNode *choice = NULL; + else + found_sure_true = children[0]->asReal(sign_hint) != 0; + + AstNode *choice = NULL, *not_choice = NULL; if (found_sure_true) - choice = children[1]; + choice = children[1], not_choice = children[2]; else if (!found_maybe_true) - choice = children[2]; + choice = children[2], not_choice = children[1]; + if (choice != NULL) { if (choice->type == AST_CONSTANT) { - RTLIL::Const y = choice->bitsAsConst(width_hint, sign_hint); - if (choice->is_string && y.bits.size() % 8 == 0 && sign_hint == false) - newNode = mkconst_str(y.bits); - else - newNode = mkconst_bits(y.bits, sign_hint); + int other_width_hint = width_hint; + bool other_sign_hint = sign_hint, other_real = false; + not_choice->detectSignWidth(other_width_hint, other_sign_hint, &other_real); + if (other_real) { + newNode = new AstNode(AST_REALVALUE); + newNode->realvalue = choice->asReal(sign_hint); + } else { + RTLIL::Const y = choice->bitsAsConst(width_hint, sign_hint); + if (choice->is_string && y.bits.size() % 8 == 0 && sign_hint == false) + newNode = mkconst_str(y.bits); + else + newNode = mkconst_bits(y.bits, sign_hint); + } } else if (choice->isConst()) { newNode = choice->clone(); -- cgit v1.2.3 From 798ff88855a6e9b8eb82a48fb4d39f78807200d9 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 17 Jun 2014 12:47:51 +0200 Subject: Improved handling of relational op of real values --- frontends/ast/simplify.cc | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 7be287d19..7a98e2712 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1538,15 +1538,16 @@ skip_dynamic_range_lvalue_expansion:; newNode = mkconst_bits(y.bits, false); } else if (children[0]->isConst() && children[1]->isConst()) { + bool cmp_signed = (children[0]->type == AST_REALVALUE || children[0]->is_signed) && (children[1]->type == AST_REALVALUE || children[1]->is_signed); switch (type) { - case AST_LT: newNode = mkconst_int(children[0]->asReal(sign_hint) < children[1]->asReal(sign_hint), false, 1); break; - case AST_LE: newNode = mkconst_int(children[0]->asReal(sign_hint) <= children[1]->asReal(sign_hint), false, 1); break; - case AST_EQ: newNode = mkconst_int(children[0]->asReal(sign_hint) == children[1]->asReal(sign_hint), false, 1); break; - case AST_NE: newNode = mkconst_int(children[0]->asReal(sign_hint) != children[1]->asReal(sign_hint), false, 1); break; - case AST_EQX: newNode = mkconst_int(children[0]->asReal(sign_hint) == children[1]->asReal(sign_hint), false, 1); break; - case AST_NEX: newNode = mkconst_int(children[0]->asReal(sign_hint) != children[1]->asReal(sign_hint), false, 1); break; - case AST_GE: newNode = mkconst_int(children[0]->asReal(sign_hint) >= children[1]->asReal(sign_hint), false, 1); break; - case AST_GT: newNode = mkconst_int(children[0]->asReal(sign_hint) > children[1]->asReal(sign_hint), false, 1); break; + case AST_LT: newNode = mkconst_int(children[0]->asReal(cmp_signed) < children[1]->asReal(cmp_signed), false, 1); break; + case AST_LE: newNode = mkconst_int(children[0]->asReal(cmp_signed) <= children[1]->asReal(cmp_signed), false, 1); break; + case AST_EQ: newNode = mkconst_int(children[0]->asReal(cmp_signed) == children[1]->asReal(cmp_signed), false, 1); break; + case AST_NE: newNode = mkconst_int(children[0]->asReal(cmp_signed) != children[1]->asReal(cmp_signed), false, 1); break; + case AST_EQX: newNode = mkconst_int(children[0]->asReal(cmp_signed) == children[1]->asReal(cmp_signed), false, 1); break; + case AST_NEX: newNode = mkconst_int(children[0]->asReal(cmp_signed) != children[1]->asReal(cmp_signed), false, 1); break; + case AST_GE: newNode = mkconst_int(children[0]->asReal(cmp_signed) >= children[1]->asReal(cmp_signed), false, 1); break; + case AST_GT: newNode = mkconst_int(children[0]->asReal(cmp_signed) > children[1]->asReal(cmp_signed), false, 1); break; default: log_abort(); } } -- cgit v1.2.3 From 80e459469576b82975a5cf663b4aba2e044d9476 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 17 Jun 2014 21:39:25 +0200 Subject: Added AstNode::MEM2REG_FL_CMPLX_LHS --- frontends/ast/simplify.cc | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 7a98e2712..0b0e46f2c 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -90,6 +90,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if ((memflags & AstNode::MEM2REG_FL_SET_INIT) && (memflags & AstNode::MEM2REG_FL_SET_ELSE)) goto verbose_activate; + if (memflags & AstNode::MEM2REG_FL_CMPLX_LHS) + goto verbose_activate; + // log("Note: Not replacing memory %s with list of registers (flags=0x%08lx).\n", mem->str.c_str(), long(memflags)); continue; @@ -1757,6 +1760,21 @@ void AstNode::replace_ids(std::map &rules) child->replace_ids(rules); } +// helper function for mem2reg_as_needed_pass1 +static void mark_memories_assign_lhs_complex(std::map> &mem2reg_places, + std::map &mem2reg_candidates, AstNode *that) +{ + for (auto &child : that->children) + mark_memories_assign_lhs_complex(mem2reg_places, mem2reg_candidates, child); + + if (that->type == AST_IDENTIFIER && that->id2ast && that->id2ast->type == AST_MEMORY) { + AstNode *mem = that->id2ast; + if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_CMPLX_LHS)) + mem2reg_places[mem].insert(stringf("%s:%d", that->filename.c_str(), that->linenum)); + mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CMPLX_LHS; + } +} + // find memories that should be replaced by registers void AstNode::mem2reg_as_needed_pass1(std::map> &mem2reg_places, std::map &mem2reg_candidates, std::map &proc_flags, uint32_t &flags) @@ -1766,6 +1784,10 @@ void AstNode::mem2reg_as_needed_pass1(std::map> if (type == AST_ASSIGN || type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) { + // mark all memories that are used in a complex expression on the left side of an assignment + for (auto &lhs_child : children[0]->children) + mark_memories_assign_lhs_complex(mem2reg_places, mem2reg_candidates, lhs_child); + if (children[0]->type == AST_IDENTIFIER && children[0]->id2ast && children[0]->id2ast->type == AST_MEMORY) { AstNode *mem = children[0]->id2ast; -- cgit v1.2.3 From 076182c34e34b5e59eb5d89d5001f7547102bb4d Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 25 Jun 2014 10:05:36 +0200 Subject: Fixed handling of mixed real/int ternary expressions --- frontends/ast/simplify.cc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 0b0e46f2c..db7f5ca34 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -247,6 +247,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, bool detect_width_simple = false; bool child_0_is_self_determined = false; bool child_1_is_self_determined = false; + bool child_2_is_self_determined = false; bool children_are_self_determined = false; bool reset_width_after_children = false; @@ -367,6 +368,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, detectSignWidth(width_hint, sign_hint); } + if (type == AST_TERNARY) { + int width_hint_left, width_hint_right; + bool sign_hint_left, sign_hint_right; + bool found_real_left, found_real_right; + children[1]->detectSignWidth(width_hint_left, sign_hint_left, &found_real_left); + children[2]->detectSignWidth(width_hint_right, sign_hint_right, &found_real_right); + if (found_real_left || found_real_right) { + child_1_is_self_determined = true; + child_2_is_self_determined = true; + } + } + // simplify all children first // (iterate by index as e.g. auto wires can add new children in the process) for (size_t i = 0; i < children.size(); i++) { @@ -402,6 +415,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, width_hint_here = -1, sign_hint_here = false; if (i == 1 && child_1_is_self_determined) width_hint_here = -1, sign_hint_here = false; + if (i == 2 && child_2_is_self_determined) + 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, in_param_here); @@ -1620,6 +1635,7 @@ skip_dynamic_range_lvalue_expansion:; not_choice->detectSignWidth(other_width_hint, other_sign_hint, &other_real); if (other_real) { newNode = new AstNode(AST_REALVALUE); + choice->detectSignWidth(width_hint, sign_hint); newNode->realvalue = choice->asReal(sign_hint); } else { RTLIL::Const y = choice->bitsAsConst(width_hint, sign_hint); -- cgit v1.2.3 From 55a1b8dbac91373979289c535bed61a32717f62b Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 11 Jul 2014 13:05:53 +0200 Subject: Fixed processing of initial values for block-local variables --- frontends/ast/simplify.cc | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index db7f5ca34..e547ede36 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -423,6 +423,11 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (did_something_here) did_something = true; } + if (stage == 2 && children[i]->type == AST_INITIAL && current_ast_mod != this) { + current_ast_mod->children.push_back(children[i]); + children.erase(children.begin() + (i--)); + did_something = true; + } } for (auto &attr : attributes) { while (attr.second->simplify(true, false, false, stage, -1, false, true)) -- cgit v1.2.3 From 543551b80a257ce0d55ce2d97fed165da7750360 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 16 Jul 2014 12:23:47 +0200 Subject: changes in verilog frontend for new $mem/$memwr WR_EN interface --- frontends/ast/simplify.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index e547ede36..ba0dca139 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1177,17 +1177,19 @@ skip_dynamic_range_lvalue_expansion:; current_scope[wire_data->str] = wire_data; while (wire_data->simplify(true, false, false, 1, -1, false, false)) { } - AstNode *wire_en = new AstNode(AST_WIRE); + AstNode *wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); 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, false)) { } - std::vector x_bits_addr, x_bits_data; + std::vector x_bits_addr, x_bits_data, set_bits_en; for (int i = 0; i < addr_bits; i++) x_bits_addr.push_back(RTLIL::State::Sx); for (int i = 0; i < mem_width; i++) x_bits_data.push_back(RTLIL::State::Sx); + for (int i = 0; i < mem_width; i++) + set_bits_en.push_back(RTLIL::State::S1); AstNode *assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false)); assign_addr->children[0]->str = id_addr; @@ -1195,7 +1197,7 @@ skip_dynamic_range_lvalue_expansion:; AstNode *assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false)); assign_data->children[0]->str = id_data; - AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, 1)); + AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); assign_en->children[0]->str = id_en; AstNode *default_signals = new AstNode(AST_BLOCK); @@ -1210,7 +1212,7 @@ skip_dynamic_range_lvalue_expansion:; assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[1]->clone()); assign_data->children[0]->str = id_data; - assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1)); + assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); assign_en->children[0]->str = id_en; newNode = new AstNode(AST_BLOCK); -- cgit v1.2.3 From 6d69d4aaa81f176ec97654b5103f6f59eb98c211 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 17 Jul 2014 13:13:21 +0200 Subject: Added support for constant bit- or part-select for memory writes --- frontends/ast/simplify.cc | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index ba0dca139..320c80d72 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -607,9 +607,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } // split memory access with bit select to individual statements - if (type == AST_IDENTIFIER && children.size() == 2 && children[0]->type == AST_RANGE && children[1]->type == AST_RANGE) + if (type == AST_IDENTIFIER && children.size() == 2 && children[0]->type == AST_RANGE && children[1]->type == AST_RANGE && !in_lvalue) { - if (id2ast == NULL || id2ast->type != AST_MEMORY || children[0]->children.size() != 1 || in_lvalue) + if (id2ast == NULL || id2ast->type != AST_MEMORY || children[0]->children.size() != 1) log_error("Invalid bit-select on memory access at %s:%d!\n", filename.c_str(), linenum); int mem_width, mem_size, addr_bits; @@ -1150,9 +1150,9 @@ skip_dynamic_range_lvalue_expansion:; // assignment with memory in left-hand side expression -> replace with memory write port if (stage > 1 && (type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE) && children[0]->type == AST_IDENTIFIER && - children[0]->children.size() == 1 && children[0]->id2ast && children[0]->id2ast->type == AST_MEMORY && - children[0]->id2ast->children.size() >= 2 && children[0]->id2ast->children[0]->range_valid && - children[0]->id2ast->children[1]->range_valid) + children[0]->id2ast && children[0]->id2ast->type == AST_MEMORY && children[0]->id2ast->children.size() >= 2 && + children[0]->id2ast->children[0]->range_valid && children[0]->id2ast->children[1]->range_valid && + (children[0]->children.size() == 1 || children[0]->children.size() == 2)) { std::stringstream sstr; sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++); @@ -1209,11 +1209,38 @@ skip_dynamic_range_lvalue_expansion:; assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; - assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[1]->clone()); - assign_data->children[0]->str = id_data; + if (children[0]->children.size() == 2) + { + if (children[0]->children[1]->range_valid) + { + int offset = children[0]->children[1]->range_right; + int width = children[0]->children[1]->range_left - offset + 1; - assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); - assign_en->children[0]->str = id_en; + std::vector padding_x(offset, RTLIL::State::Sx); + + for (int i = 0; i < mem_width; i++) + set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0; + + assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), + new AstNode(AST_CONCAT, mkconst_bits(padding_x, false), children[1]->clone())); + assign_data->children[0]->str = id_data; + + assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); + assign_en->children[0]->str = id_en; + } + else + { + log_error("Writing to memories with dynamic bit- or part-select is not supported yet at %s:%d.\n", filename.c_str(), linenum); + } + } + else + { + assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[1]->clone()); + assign_data->children[0]->str = id_data; + + assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); + assign_en->children[0]->str = id_en; + } newNode = new AstNode(AST_BLOCK); newNode->children.push_back(assign_addr); -- cgit v1.2.3 From 5867f6bcdc10cbccc196a6889f5242c0f090a2f1 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 17 Jul 2014 13:49:32 +0200 Subject: Added support for bit/part select to mem2reg rewriter --- frontends/ast/simplify.cc | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 320c80d72..eee5a7b39 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1974,6 +1974,8 @@ void AstNode::mem2reg_as_needed_pass2(std::set &mem2reg_set, AstNode * continue; AstNode *cond_node = new AstNode(AST_COND, AstNode::mkconst_int(i, false, addr_bits), new AstNode(AST_BLOCK)); AstNode *assign_reg = new AstNode(type, new AstNode(AST_IDENTIFIER), new AstNode(AST_IDENTIFIER)); + if (children[0]->children.size() == 2) + assign_reg->children[0]->children.push_back(children[0]->children[1]->clone()); assign_reg->children[0]->str = stringf("%s[%d]", children[0]->str.c_str(), i); assign_reg->children[1]->str = id_data; cond_node->children[1]->children.push_back(assign_reg); @@ -1990,6 +1992,10 @@ void AstNode::mem2reg_as_needed_pass2(std::set &mem2reg_set, AstNode * if (type == AST_IDENTIFIER && id2ast && mem2reg_set.count(id2ast) > 0) { + AstNode *bit_part_sel = NULL; + if (children.size() == 2) + bit_part_sel = children[1]->clone(); + if (children[0]->children[0]->type == AST_CONSTANT) { int id = children[0]->children[0]->integer; @@ -2073,6 +2079,9 @@ void AstNode::mem2reg_as_needed_pass2(std::set &mem2reg_set, AstNode * id2ast = NULL; str = id_data; } + + if (bit_part_sel) + children.push_back(bit_part_sel); } assert(id2ast == NULL || mem2reg_set.count(id2ast) == 0); -- cgit v1.2.3 From 9b183539af4adf7d2a127042ca384806c7e73367 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 17 Jul 2014 16:49:23 +0200 Subject: Implemented dynamic bit-/part-select for memory writes --- frontends/ast/simplify.cc | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index eee5a7b39..f819b2506 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1159,7 +1159,7 @@ skip_dynamic_range_lvalue_expansion:; std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN"; if (type == AST_ASSIGN_EQ) - log("Warining: Blocking assignment to memory in line %s:%d is handled like a non-blocking assignment.\n", + log("Warning: Blocking assignment to memory in line %s:%d is handled like a non-blocking assignment.\n", filename.c_str(), linenum); int mem_width, mem_size, addr_bits; @@ -1230,7 +1230,31 @@ skip_dynamic_range_lvalue_expansion:; } else { - log_error("Writing to memories with dynamic bit- or part-select is not supported yet at %s:%d.\n", filename.c_str(), linenum); + AstNode *the_range = children[0]->children[1]; + AstNode *left_at_zero_ast = the_range->children[0]->clone(); + AstNode *right_at_zero_ast = the_range->children.size() >= 2 ? the_range->children[1]->clone() : left_at_zero_ast->clone(); + AstNode *offset_ast = right_at_zero_ast->clone(); + + 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); + int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1; + + for (int i = 0; i < mem_width; i++) + set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0; + + assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), + new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone())); + assign_data->children[0]->str = id_data; + + assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), + new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone())); + assign_en->children[0]->str = id_en; + + delete left_at_zero_ast; + delete right_at_zero_ast; + delete offset_ast; } } else -- cgit v1.2.3 From 20a7965f61a43b8c367b1042081a57b5a4005b33 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 23 Jul 2014 20:45:27 +0200 Subject: Various small fixes (from gcc compiler warnings) --- frontends/ast/simplify.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index f819b2506..d86bfb3f0 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -2259,7 +2259,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) log_error("Non-constant range in %s:%d (called from %s:%d).\n", range->filename.c_str(), range->linenum, fcall->filename.c_str(), fcall->linenum); int offset = std::min(range->range_left, range->range_right); - int width = std::min(std::abs(range->range_left - range->range_right) + 1, width); + int width = std::abs(range->range_left - range->range_right) + 1; varinfo_t &v = variables[stmt->children.at(0)->str]; RTLIL::Const r = stmt->children.at(1)->bitsAsConst(v.val.bits.size()); for (int i = 0; i < width; i++) -- cgit v1.2.3 From 309d64d46a7ca7390ccb27b06ecb78228c8b54f6 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 25 Jul 2014 13:07:31 +0200 Subject: Fixed two memory leaks in ast simplify --- frontends/ast/simplify.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index d86bfb3f0..6302260a5 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -895,7 +895,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, log_error("Expression in generate case at %s:%d is not constant!\n", filename.c_str(), linenum); } - if (RTLIL::const_eq(ref_value, buf->bitsAsConst(), ref_signed && buf->is_signed, ref_signed && buf->is_signed, 1).as_bool()) { + bool is_selected = RTLIL::const_eq(ref_value, buf->bitsAsConst(), ref_signed && buf->is_signed, ref_signed && buf->is_signed, 1).as_bool(); + delete buf; + + if (is_selected) { selected_case = this_genblock; i = children.size(); break; @@ -1301,6 +1304,8 @@ skip_dynamic_range_lvalue_expansion:; log_error("Failed to evaluate system function `%s' with non-constant value at %s:%d.\n", str.c_str(), filename.c_str(), linenum); RTLIL::Const arg_value = buf->bitsAsConst(); + delete buf; + uint32_t result = 0; for (size_t i = 0; i < arg_value.bits.size(); i++) if (arg_value.bits.at(i) == RTLIL::State::S1) -- cgit v1.2.3 From 7bd2d1064f2eceddc3c93c121c4154a2f594a040 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 28 Jul 2014 11:08:55 +0200 Subject: Using log_assert() instead of assert() --- frontends/ast/simplify.cc | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 6302260a5..2a55adeff 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -57,7 +57,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (stage == 0) { - assert(type == AST_MODULE); + log_assert(type == AST_MODULE); while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { } @@ -73,7 +73,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, { AstNode *mem = it.first; uint32_t memflags = it.second; - assert((memflags & ~0x00ffff00) == 0); + log_assert((memflags & ~0x00ffff00) == 0); if (mem->get_bool_attribute("\\nomem2reg")) continue; @@ -480,7 +480,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, // dumpAst(NULL, "> "); log_error("Index in generate block prefix syntax at %s:%d is not constant!\n", filename.c_str(), linenum); } - assert(children[1]->type == AST_IDENTIFIER); + log_assert(children[1]->type == AST_IDENTIFIER); newNode = children[1]->clone(); const char *second_part = children[1]->str.c_str(); if (second_part[0] == '\\') @@ -506,7 +506,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, range_valid = false; range_left = -1; range_right = 0; - assert(children.size() >= 1); + log_assert(children.size() >= 1); if (children[0]->type == AST_CONSTANT) { range_valid = true; range_left = children[0]->integer; @@ -963,8 +963,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, std::vector children_list; for (auto child : children) { - assert(child->type == AST_ARGUMENT); - assert(child->children.size() == 1); + log_assert(child->type == AST_ARGUMENT); + log_assert(child->children.size() == 1); children_list.push_back(child->children[0]); child->children.clear(); delete child; @@ -1019,7 +1019,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, op_type = AST_POS; if (str == "not") op_type = AST_POS, invert_results = true; - assert(op_type != AST_NONE); + log_assert(op_type != AST_NONE); AstNode *node = children_list[1]; if (op_type != AST_POS) @@ -1423,13 +1423,13 @@ skip_dynamic_range_lvalue_expansion:; if (current_block == NULL) { - assert(type == AST_FCALL); + log_assert(type == AST_FCALL); AstNode *wire = NULL; for (auto child : decl->children) if (child->type == AST_WIRE && child->str == str) wire = child->clone(); - assert(wire != NULL); + log_assert(wire != NULL); wire->str = prefix + str; wire->port_id = 0; @@ -1714,7 +1714,7 @@ skip_dynamic_range_lvalue_expansion:; } else if (children[1]->type == AST_CONSTANT && children[2]->type == AST_CONSTANT) { RTLIL::Const a = children[1]->bitsAsConst(width_hint, sign_hint); RTLIL::Const b = children[2]->bitsAsConst(width_hint, sign_hint); - assert(a.bits.size() == b.bits.size()); + log_assert(a.bits.size() == b.bits.size()); for (size_t i = 0; i < a.bits.size(); i++) if (a.bits[i] != b.bits[i]) a.bits[i] = RTLIL::State::Sx; @@ -1761,7 +1761,7 @@ apply_newNode: // fprintf(stderr, "----\n"); // dumpAst(stderr, "- "); // newNode->dumpAst(stderr, "+ "); - assert(newNode != NULL); + log_assert(newNode != NULL); newNode->filename = filename; newNode->linenum = linenum; newNode->cloneInto(this); @@ -1937,7 +1937,7 @@ void AstNode::mem2reg_as_needed_pass1(std::map> uint32_t backup_flags = flags; flags |= children_flags; - assert((flags & ~0x000000ff) == 0); + log_assert((flags & ~0x000000ff) == 0); for (auto child : children) if (ignore_children_counter > 0) @@ -1986,11 +1986,11 @@ void AstNode::mem2reg_as_needed_pass2(std::set &mem2reg_set, AstNode * mod->children.push_back(wire_data); while (wire_data->simplify(true, false, false, 1, -1, false, false)) { } - assert(block != NULL); + log_assert(block != NULL); size_t assign_idx = 0; while (assign_idx < block->children.size() && block->children[assign_idx] != this) assign_idx++; - assert(assign_idx < block->children.size()); + log_assert(assign_idx < block->children.size()); AstNode *assign_addr = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; @@ -2091,7 +2091,7 @@ void AstNode::mem2reg_as_needed_pass2(std::set &mem2reg_set, AstNode * size_t assign_idx = 0; while (assign_idx < block->children.size() && !block->children[assign_idx]->contains(this)) assign_idx++; - assert(assign_idx < block->children.size()); + log_assert(assign_idx < block->children.size()); block->children.insert(block->children.begin()+assign_idx, case_node); block->children.insert(block->children.begin()+assign_idx, assign_addr); } @@ -2113,7 +2113,7 @@ void AstNode::mem2reg_as_needed_pass2(std::set &mem2reg_set, AstNode * children.push_back(bit_part_sel); } - assert(id2ast == NULL || mem2reg_set.count(id2ast) == 0); + log_assert(id2ast == NULL || mem2reg_set.count(id2ast) == 0); auto children_list = children; for (size_t i = 0; i < children_list.size(); i++) @@ -2123,7 +2123,7 @@ void AstNode::mem2reg_as_needed_pass2(std::set &mem2reg_set, AstNode * // calulate memory dimensions void AstNode::meminfo(int &mem_width, int &mem_size, int &addr_bits) { - assert(type == AST_MEMORY); + log_assert(type == AST_MEMORY); mem_width = children[0]->range_left - children[0]->range_right + 1; mem_size = children[1]->range_left - children[1]->range_right; -- cgit v1.2.3 From 27a872d1e7041be4894bc643a420587ff5894125 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 28 Jul 2014 14:25:03 +0200 Subject: Added support for "upto" wires to Verilog front- and back-end --- frontends/ast/simplify.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 2a55adeff..7aa6d24c3 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -504,6 +504,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (type == AST_RANGE) { bool old_range_valid = range_valid; range_valid = false; + range_swapped = false; range_left = -1; range_right = 0; log_assert(children.size() >= 1); @@ -525,6 +526,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int tmp = range_right; range_right = range_left; range_left = tmp; + range_swapped = true; } } @@ -535,6 +537,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (!range_valid) did_something = true; range_valid = true; + range_swapped = children[0]->range_swapped; range_left = children[0]->range_left; range_right = children[0]->range_right; } @@ -542,6 +545,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (!range_valid) did_something = true; range_valid = true; + range_swapped = false; range_left = 0; range_right = 0; } -- cgit v1.2.3 From ec589659674ba9699b5dc73129ad69f25738e87e Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 28 Jul 2014 16:45:26 +0200 Subject: Fixed part selects of parameters --- frontends/ast/simplify.cc | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 7aa6d24c3..d47bfb5e6 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -575,6 +575,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } children[0]->is_signed = is_signed; } + range_valid = true; + range_swapped = children[1]->range_swapped; + range_left = children[1]->range_left; + range_right = children[1]->range_right; } else if (children.size() > 1 && children[1]->type == AST_REALVALUE && children[0]->type == AST_CONSTANT) { double as_realvalue = children[0]->asReal(sign_hint); @@ -1522,8 +1526,23 @@ skip_dynamic_range_lvalue_expansion:; if (current_scope[str]->children[0]->type == AST_CONSTANT) { if (children.size() != 0 && children[0]->type == AST_RANGE && children[0]->range_valid) { std::vector data; - for (int i = children[0]->range_right; i <= children[0]->range_left; i++) - data.push_back(current_scope[str]->children[0]->bits[i]); + bool param_upto = current_scope[str]->range_valid && current_scope[str]->range_swapped; + int param_offset = current_scope[str]->range_valid ? current_scope[str]->range_right : 0; + int param_width = current_scope[str]->range_valid ? current_scope[str]->range_left - current_scope[str]->range_right + 1 : + SIZE(current_scope[str]->children[0]->bits); + int tmp_range_left = children[0]->range_left, tmp_range_right = children[0]->range_right; + if (param_upto) { + tmp_range_left = (param_width + 2*param_offset) - children[0]->range_right - 1; + tmp_range_right = (param_width + 2*param_offset) - children[0]->range_left - 1; + } + log_dump(param_upto, param_offset, param_width, children[0]->range_left, children[0]->range_right, tmp_range_left, tmp_range_right); + for (int i = tmp_range_right; i <= tmp_range_left; i++) { + int index = i - param_offset; + if (0 <= index && index < param_width) + data.push_back(current_scope[str]->children[0]->bits[index]); + else + data.push_back(RTLIL::State::Sx); + } newNode = mkconst_bits(data, false); } else if (children.size() == 0) -- cgit v1.2.3 From 48822e79a34880c5f0b07e9889e463e7b6d7111b Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 28 Jul 2014 19:38:30 +0200 Subject: Removed left over debug code --- frontends/ast/simplify.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index d47bfb5e6..5665cd43c 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1535,7 +1535,6 @@ skip_dynamic_range_lvalue_expansion:; tmp_range_left = (param_width + 2*param_offset) - children[0]->range_right - 1; tmp_range_right = (param_width + 2*param_offset) - children[0]->range_left - 1; } - log_dump(param_upto, param_offset, param_width, children[0]->range_left, children[0]->range_right, tmp_range_left, tmp_range_right); for (int i = tmp_range_right; i <= tmp_range_left; i++) { int index = i - param_offset; if (0 <= index && index < param_width) -- cgit v1.2.3 From 1cb25c05b37b0172dbc50e140fe20f25d973dd8a Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 31 Jul 2014 13:19:47 +0200 Subject: Moved some stuff to kernel/yosys.{h,cc}, using Yosys:: namespace --- frontends/ast/simplify.cc | 60 +++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 28 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 5665cd43c..c51692f12 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -34,6 +34,8 @@ #include #include +YOSYS_NAMESPACE_BEGIN + using namespace AST; using namespace AST_INTERNAL; @@ -624,7 +626,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, id2ast->meminfo(mem_width, mem_size, addr_bits); std::stringstream sstr; - sstr << "$mem2bits$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++); + sstr << "$mem2bits$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++); std::string wire_id = sstr.str(); AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); @@ -744,7 +746,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, buf = new AstNode(AST_GENBLOCK, body_ast->clone()); if (buf->str.empty()) { std::stringstream sstr; - sstr << "$genblock$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++); + sstr << "$genblock$" << filename << ":" << linenum << "$" << (autoidx++); buf->str = sstr.str(); } std::map name_map; @@ -1091,7 +1093,7 @@ skip_dynamic_range_lvalue_expansion:; if (stage > 1 && type == AST_ASSERT && current_block != NULL) { std::stringstream sstr; - sstr << "$assert$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++); + sstr << "$assert$" << filename << ":" << linenum << "$" << (autoidx++); std::string id_check = sstr.str() + "_CHECK", id_en = sstr.str() + "_EN"; AstNode *wire_check = new AstNode(AST_WIRE); @@ -1166,7 +1168,7 @@ skip_dynamic_range_lvalue_expansion:; (children[0]->children.size() == 1 || children[0]->children.size() == 2)) { std::stringstream sstr; - sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++); + sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN"; if (type == AST_ASSIGN_EQ) @@ -1364,27 +1366,27 @@ skip_dynamic_range_lvalue_expansion:; } newNode = new AstNode(AST_REALVALUE); - if (str == "\\$ln") newNode->realvalue = log(x); - else if (str == "\\$log10") newNode->realvalue = log10(x); - else if (str == "\\$exp") newNode->realvalue = exp(x); - else if (str == "\\$sqrt") newNode->realvalue = sqrt(x); - else if (str == "\\$pow") newNode->realvalue = pow(x, y); - else if (str == "\\$floor") newNode->realvalue = floor(x); - else if (str == "\\$ceil") newNode->realvalue = ceil(x); - else if (str == "\\$sin") newNode->realvalue = sin(x); - else if (str == "\\$cos") newNode->realvalue = cos(x); - else if (str == "\\$tan") newNode->realvalue = tan(x); - else if (str == "\\$asin") newNode->realvalue = asin(x); - else if (str == "\\$acos") newNode->realvalue = acos(x); - else if (str == "\\$atan") newNode->realvalue = atan(x); - else if (str == "\\$atan2") newNode->realvalue = atan2(x, y); - else if (str == "\\$hypot") newNode->realvalue = hypot(x, y); - else if (str == "\\$sinh") newNode->realvalue = sinh(x); - else if (str == "\\$cosh") newNode->realvalue = cosh(x); - else if (str == "\\$tanh") newNode->realvalue = tanh(x); - else if (str == "\\$asinh") newNode->realvalue = asinh(x); - else if (str == "\\$acosh") newNode->realvalue = acosh(x); - else if (str == "\\$atanh") newNode->realvalue = atanh(x); + if (str == "\\$ln") newNode->realvalue = ::log(x); + else if (str == "\\$log10") newNode->realvalue = ::log10(x); + else if (str == "\\$exp") newNode->realvalue = ::exp(x); + else if (str == "\\$sqrt") newNode->realvalue = ::sqrt(x); + else if (str == "\\$pow") newNode->realvalue = ::pow(x, y); + else if (str == "\\$floor") newNode->realvalue = ::floor(x); + else if (str == "\\$ceil") newNode->realvalue = ::ceil(x); + else if (str == "\\$sin") newNode->realvalue = ::sin(x); + else if (str == "\\$cos") newNode->realvalue = ::cos(x); + else if (str == "\\$tan") newNode->realvalue = ::tan(x); + else if (str == "\\$asin") newNode->realvalue = ::asin(x); + else if (str == "\\$acos") newNode->realvalue = ::acos(x); + else if (str == "\\$atan") newNode->realvalue = ::atan(x); + else if (str == "\\$atan2") newNode->realvalue = ::atan2(x, y); + else if (str == "\\$hypot") newNode->realvalue = ::hypot(x, y); + else if (str == "\\$sinh") newNode->realvalue = ::sinh(x); + else if (str == "\\$cosh") newNode->realvalue = ::cosh(x); + else if (str == "\\$tanh") newNode->realvalue = ::tanh(x); + else if (str == "\\$asinh") newNode->realvalue = ::asinh(x); + else if (str == "\\$acosh") newNode->realvalue = ::acosh(x); + else if (str == "\\$atanh") newNode->realvalue = ::atanh(x); else log_abort(); goto apply_newNode; } @@ -1423,7 +1425,7 @@ skip_dynamic_range_lvalue_expansion:; AstNode *decl = current_scope[str]; std::stringstream sstr; - sstr << "$func$" << str << "$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++) << "$"; + sstr << "$func$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++) << "$"; std::string prefix = sstr.str(); size_t arg_count = 0; @@ -1988,7 +1990,7 @@ void AstNode::mem2reg_as_needed_pass2(std::set &mem2reg_set, AstNode * mem2reg_set.count(children[0]->id2ast) > 0 && children[0]->children[0]->children[0]->type != AST_CONSTANT) { std::stringstream sstr; - sstr << "$mem2reg_wr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++); + sstr << "$mem2reg_wr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA"; int mem_width, mem_size, addr_bits; @@ -2059,7 +2061,7 @@ void AstNode::mem2reg_as_needed_pass2(std::set &mem2reg_set, AstNode * else { std::stringstream sstr; - sstr << "$mem2reg_rd$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++); + sstr << "$mem2reg_rd$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA"; int mem_width, mem_size, addr_bits; @@ -2421,3 +2423,5 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) return AstNode::mkconst_bits(variables.at(str).val.bits, variables.at(str).is_signed); } +YOSYS_NAMESPACE_END + -- cgit v1.2.3 From 14412e6c957a34381c33740426b35f7b90a446be Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 2 Aug 2014 00:45:25 +0200 Subject: Preparations for RTLIL::IdString redesign: cleanup of existing code --- frontends/ast/simplify.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index c51692f12..4d71bb394 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -465,7 +465,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, size_t pos = str.rfind('.'); if (pos == std::string::npos) log_error("Defparam `%s' does not contain a dot (module/parameter seperator) at %s:%d!\n", - RTLIL::id2cstr(str.c_str()), filename.c_str(), linenum); + RTLIL::id2cstr(str), filename.c_str(), linenum); std::string modname = str.substr(0, pos), paraname = "\\" + str.substr(pos+1); if (current_scope.count(modname) == 0 || current_scope.at(modname)->type != AST_CELL) log_error("Can't find cell for defparam `%s . %s` at %s:%d!\n", RTLIL::id2cstr(modname), RTLIL::id2cstr(paraname), filename.c_str(), linenum); -- cgit v1.2.3 From 768eb846c4473040dc07bf62ce631c8a21474ae8 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 2 Aug 2014 16:03:18 +0200 Subject: More bugfixes related to new RTLIL::IdString --- frontends/ast/simplify.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 4d71bb394..694f1d4d8 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -465,10 +465,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, size_t pos = str.rfind('.'); if (pos == std::string::npos) log_error("Defparam `%s' does not contain a dot (module/parameter seperator) at %s:%d!\n", - RTLIL::id2cstr(str), filename.c_str(), linenum); + RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); std::string modname = str.substr(0, pos), paraname = "\\" + str.substr(pos+1); if (current_scope.count(modname) == 0 || current_scope.at(modname)->type != AST_CELL) - log_error("Can't find cell for defparam `%s . %s` at %s:%d!\n", RTLIL::id2cstr(modname), RTLIL::id2cstr(paraname), filename.c_str(), linenum); + log_error("Can't find cell for defparam `%s . %s` at %s:%d!\n", RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paraname).c_str(), filename.c_str(), linenum); AstNode *cell = current_scope.at(modname), *paraset = clone(); cell->children.insert(cell->children.begin() + 1, paraset); paraset->type = AST_PARASET; @@ -1306,7 +1306,7 @@ skip_dynamic_range_lvalue_expansion:; { if (children.size() != 1) log_error("System function %s got %d arguments, expected 1 at %s:%d.\n", - RTLIL::id2cstr(str), int(children.size()), filename.c_str(), linenum); + RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); AstNode *buf = children[0]->clone(); while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } @@ -1336,18 +1336,18 @@ skip_dynamic_range_lvalue_expansion:; if (func_with_two_arguments) { if (children.size() != 2) log_error("System function %s got %d arguments, expected 2 at %s:%d.\n", - RTLIL::id2cstr(str), int(children.size()), filename.c_str(), linenum); + RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); } else { if (children.size() != 1) log_error("System function %s got %d arguments, expected 1 at %s:%d.\n", - RTLIL::id2cstr(str), int(children.size()), filename.c_str(), linenum); + RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); } if (children.size() >= 1) { while (children[0]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } if (!children[0]->isConst()) log_error("Failed to evaluate system function `%s' with non-constant argument at %s:%d.\n", - RTLIL::id2cstr(str), filename.c_str(), linenum); + RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); int child_width_hint = width_hint; bool child_sign_hint = sign_hint; children[0]->detectSignWidth(child_width_hint, child_sign_hint); @@ -1358,7 +1358,7 @@ skip_dynamic_range_lvalue_expansion:; while (children[1]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } if (!children[1]->isConst()) log_error("Failed to evaluate system function `%s' with non-constant argument at %s:%d.\n", - RTLIL::id2cstr(str), filename.c_str(), linenum); + RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); int child_width_hint = width_hint; bool child_sign_hint = sign_hint; children[1]->detectSignWidth(child_width_hint, child_sign_hint); -- cgit v1.2.3 From 0129d41efad623ee95878a673c1c1190261ba3ef Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 5 Aug 2014 08:35:51 +0200 Subject: Fixed AST handling of variables declared inside a functions main block --- frontends/ast/simplify.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 694f1d4d8..20edc1739 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1460,7 +1460,6 @@ skip_dynamic_range_lvalue_expansion:; } for (auto child : decl->children) - { if (child->type == AST_WIRE) { AstNode *wire = child->clone(); @@ -1488,7 +1487,9 @@ skip_dynamic_range_lvalue_expansion:; } } } - else + + for (auto child : decl->children) + if (child->type != AST_WIRE) { AstNode *stmt = child->clone(); stmt->replace_ids(replace_rules); @@ -1500,7 +1501,6 @@ skip_dynamic_range_lvalue_expansion:; break; } } - } replace_fcall_with_id: if (type == AST_FCALL) { -- cgit v1.2.3 From 91dd87e60b120119ee34a9961a7b5f33f340282e Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 5 Aug 2014 12:15:53 +0200 Subject: Improved scope resolution of local regs in Verilog+AST frontend --- frontends/ast/simplify.cc | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 20edc1739..29d00be96 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -794,6 +794,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (children[i]->type == AST_WIRE) { children[i]->simplify(false, false, false, stage, -1, false, false); current_ast_mod->children.push_back(children[i]); + current_scope[children[i]->str] = children[i]; } else new_children.push_back(children[i]); @@ -1492,7 +1493,7 @@ skip_dynamic_range_lvalue_expansion:; if (child->type != AST_WIRE) { AstNode *stmt = child->clone(); - stmt->replace_ids(replace_rules); + stmt->replace_ids(prefix, replace_rules); for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) { if (*it != current_block_child) @@ -1855,12 +1856,30 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma } // rename stuff (used when tasks of functions are instanciated) -void AstNode::replace_ids(std::map &rules) +void AstNode::replace_ids(const std::string &prefix, const std::map &rules) { - if (type == AST_IDENTIFIER && rules.count(str) > 0) - str = rules[str]; - for (auto child : children) - child->replace_ids(rules); + if (type == AST_BLOCK) + { + std::map new_rules = rules; + std::string new_prefix = prefix + str; + + for (auto child : children) + if (child->type == AST_WIRE) { + new_rules[child->str] = new_prefix + child->str; + child->str = new_prefix + child->str; + } + + for (auto child : children) + if (child->type != AST_WIRE) + child->replace_ids(new_prefix, new_rules); + } + else + { + if (type == AST_IDENTIFIER && rules.count(str) > 0) + str = rules.at(str); + for (auto child : children) + child->replace_ids(prefix, rules); + } } // helper function for mem2reg_as_needed_pass1 -- cgit v1.2.3 From d259abbda2b9d568228dc8d0bed2d0b0d88d7b4f Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 6 Aug 2014 15:43:46 +0200 Subject: Added AST_MULTIRANGE (arrays with more than 1 dimension) --- frontends/ast/simplify.cc | 52 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 29d00be96..39c472621 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -553,6 +553,56 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } } + // resolve multiranges on memory decl + if (type == AST_MEMORY && children.size() > 1 && children[1]->type == AST_MULTIRANGE) + { + int total_size = 1; + multirange_dimensions.clear(); + for (auto range : children[1]->children) { + if (!range->range_valid) + log_error("Non-constant range on memory decl at %s:%d.\n", filename.c_str(), linenum); + multirange_dimensions.push_back(std::min(range->range_left, range->range_right)); + multirange_dimensions.push_back(std::max(range->range_left, range->range_right) - std::min(range->range_left, range->range_right) + 1); + total_size *= multirange_dimensions.back(); + } + delete children[1]; + children[1] = new AstNode(AST_RANGE, AstNode::mkconst_int(0, true), AstNode::mkconst_int(total_size-1, true)); + did_something = true; + } + + // resolve multiranges on memory access + if (type == AST_IDENTIFIER && id2ast && id2ast->type == AST_MEMORY && children.size() > 0 && children[0]->type == AST_MULTIRANGE) + { + AstNode *index_expr = nullptr; + + for (int i = 0; 2*i < SIZE(id2ast->multirange_dimensions); i++) + { + if (SIZE(children[0]->children) < i) + log_error("Insufficient number of array indices for %s at %s:%d.\n", log_id(str), filename.c_str(), linenum); + + AstNode *new_index_expr = children[0]->children[i]->children.at(0)->clone(); + + if (id2ast->multirange_dimensions[2*i]) + new_index_expr = new AstNode(AST_SUB, new_index_expr, AstNode::mkconst_int(id2ast->multirange_dimensions[2*i], true)); + + if (i == 0) + index_expr = new_index_expr; + else + index_expr = new AstNode(AST_ADD, new AstNode(AST_MUL, index_expr, AstNode::mkconst_int(id2ast->multirange_dimensions[2*i-1], true)), new_index_expr); + } + + for (int i = SIZE(id2ast->multirange_dimensions)/1; i < SIZE(children[0]->children); i++) + children.push_back(children[0]->children[i]->clone()); + + delete children[0]; + if (index_expr == nullptr) + children.erase(children.begin()); + else + children[0] = new AstNode(AST_RANGE, index_expr); + + did_something = true; + } + // trim/extend parameters if (type == AST_PARAMETER || type == AST_LOCALPARAM) { if (children.size() > 1 && children[1]->type == AST_RANGE) { @@ -1166,7 +1216,7 @@ skip_dynamic_range_lvalue_expansion:; if (stage > 1 && (type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE) && children[0]->type == AST_IDENTIFIER && children[0]->id2ast && children[0]->id2ast->type == AST_MEMORY && children[0]->id2ast->children.size() >= 2 && children[0]->id2ast->children[0]->range_valid && children[0]->id2ast->children[1]->range_valid && - (children[0]->children.size() == 1 || children[0]->children.size() == 2)) + (children[0]->children.size() == 1 || children[0]->children.size() == 2) && children[0]->children[0]->type == AST_RANGE) { std::stringstream sstr; sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++); -- cgit v1.2.3 From 85e3cc12ac44c44178185b918aa2a7fe9ca89918 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 14 Aug 2014 22:26:10 +0200 Subject: Fixed handling of task outputs --- frontends/ast/simplify.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 39c472621..76d1f8270 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1523,12 +1523,14 @@ skip_dynamic_range_lvalue_expansion:; replace_rules[child->str] = wire->str; - if (child->is_input && arg_count < children.size()) + if ((child->is_input || child->is_output) && arg_count < children.size()) { AstNode *arg = children[arg_count++]->clone(); AstNode *wire_id = new AstNode(AST_IDENTIFIER); wire_id->str = wire->str; - AstNode *assign = new AstNode(AST_ASSIGN_EQ, wire_id, arg); + AstNode *assign = child->is_input ? + new AstNode(AST_ASSIGN_EQ, wire_id, arg) : + new AstNode(AST_ASSIGN_EQ, arg, wire_id); for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) { if (*it != current_block_child) -- cgit v1.2.3 From acb435b6cf583b6c18f405a9c92566c4e9fb85e5 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 18 Aug 2014 00:02:30 +0200 Subject: Added const folding of AST_CASE to AST simplifier --- frontends/ast/simplify.cc | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 76d1f8270..85671213d 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1567,7 +1567,7 @@ skip_dynamic_range_lvalue_expansion:; } // perform const folding when activated - if (const_fold && newNode == NULL) + if (const_fold) { bool string_op; std::vector tmp_bits; @@ -1746,6 +1746,37 @@ skip_dynamic_range_lvalue_expansion:; newNode->realvalue = -children[0]->asReal(sign_hint); } break; + case AST_CASE: + if (children[0]->type == AST_CONSTANT && children[0]->bits_only_01()) { + std::vector new_children; + new_children.push_back(children[0]); + for (int i = 1; i < SIZE(children); i++) { + AstNode *child = children[i]; + log_assert(child->type == AST_COND); + for (auto v : child->children) { + if (v->type == AST_DEFAULT) + goto keep_const_cond; + if (v->type == AST_BLOCK) + continue; + if (v->type == AST_CONSTANT && v->bits_only_01()) { + if (v->bits == children[0]->bits) { + while (i+1 < SIZE(children)) + delete children[++i]; + goto keep_const_cond; + } + continue; + } + goto keep_const_cond; + } + if (0) + keep_const_cond: + new_children.push_back(child); + else + delete child; + } + new_children.swap(children); + } + break; case AST_TERNARY: if (children[0]->isConst()) { -- cgit v1.2.3 From 640d9fc551c546b511f8d64c0ccfc438937164a1 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 18 Aug 2014 14:29:30 +0200 Subject: Added "via_celltype" attribute on task/func --- frontends/ast/simplify.cc | 75 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 6 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 85671213d..2572fa4a9 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1450,9 +1450,15 @@ skip_dynamic_range_lvalue_expansion:; log_error("Can't resolve task name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum); } + AstNode *decl = current_scope[str]; + + std::stringstream sstr; + sstr << "$func$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++) << "$"; + std::string prefix = sstr.str(); + bool recommend_const_eval = false; bool require_const_eval = in_param ? false : has_const_only_constructs(recommend_const_eval); - if (in_param || recommend_const_eval || require_const_eval) + if ((in_param || recommend_const_eval || require_const_eval) && !decl->attributes.count("\\via_celltype")) { bool all_args_const = true; for (auto child : children) { @@ -1474,11 +1480,6 @@ skip_dynamic_range_lvalue_expansion:; log_error("Function %s can only be called with constant arguments at %s:%d.\n", str.c_str(), filename.c_str(), linenum); } - AstNode *decl = current_scope[str]; - std::stringstream sstr; - sstr << "$func$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++) << "$"; - std::string prefix = sstr.str(); - size_t arg_count = 0; std::map replace_rules; @@ -1510,6 +1511,68 @@ skip_dynamic_range_lvalue_expansion:; goto replace_fcall_with_id; } + if (decl->attributes.count("\\via_celltype")) + { + std::string celltype = decl->attributes.at("\\via_celltype")->asAttrConst().decode_string(); + std::string outport = str; + + if (celltype.find(' ') != std::string::npos) { + int pos = celltype.find(' '); + outport = RTLIL::escape_id(celltype.substr(pos+1)); + celltype = RTLIL::escape_id(celltype.substr(0, pos)); + } else + celltype = RTLIL::escape_id(celltype); + + AstNode *cell = new AstNode(AST_CELL, new AstNode(AST_CELLTYPE)); + cell->str = prefix.substr(0, SIZE(prefix)-1); + cell->children[0]->str = celltype; + + for (auto attr : decl->attributes) + if (attr.first.str().rfind("\\via_celltype_defparam_", 0) == 0) + { + AstNode *cell_arg = new AstNode(AST_PARASET, attr.second->clone()); + cell_arg->str = RTLIL::escape_id(attr.first.str().substr(strlen("\\via_celltype_defparam_"))); + cell->children.push_back(cell_arg); + } + + for (auto child : decl->children) + if (child->type == AST_WIRE && (child->is_input || child->is_output || (type == AST_FCALL && child->str == str))) + { + AstNode *wire = child->clone(); + wire->str = prefix + wire->str; + wire->port_id = 0; + wire->is_input = false; + wire->is_output = false; + current_ast_mod->children.push_back(wire); + while (wire->simplify(true, false, false, 1, -1, false, false)) { } + + AstNode *wire_id = new AstNode(AST_IDENTIFIER); + wire_id->str = wire->str; + + if ((child->is_input || child->is_output) && arg_count < children.size()) + { + AstNode *arg = children[arg_count++]->clone(); + AstNode *assign = child->is_input ? + new AstNode(AST_ASSIGN_EQ, wire_id, arg) : + new AstNode(AST_ASSIGN_EQ, arg, wire_id); + + for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) { + if (*it != current_block_child) + continue; + current_block->children.insert(it, assign); + break; + } + } + + AstNode *cell_arg = new AstNode(AST_ARGUMENT, wire_id->clone()); + cell_arg->str = child->str == str ? outport : child->str; + cell->children.push_back(cell_arg); + } + + current_ast_mod->children.push_back(cell); + goto replace_fcall_with_id; + } + for (auto child : decl->children) if (child->type == AST_WIRE) { -- cgit v1.2.3 From 7bfc4ae12030648cd73686d3779c6d412a3c33c0 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Aug 2014 12:43:51 +0200 Subject: Added Verilog/AST support for DPI functions (dpi_call() still unimplemented) --- frontends/ast/simplify.cc | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 2572fa4a9..19f1d0554 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -226,7 +226,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, this_wire_scope[node->str] = node; } if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_GENVAR || - node->type == AST_MEMORY || node->type == AST_FUNCTION || node->type == AST_TASK || node->type == AST_CELL) { + node->type == AST_MEMORY || node->type == AST_FUNCTION || node->type == AST_TASK || node->type == AST_DPI_FUNCTION || node->type == AST_CELL) { backup_scope[node->str] = current_scope[node->str]; current_scope[node->str] = node; } @@ -646,7 +646,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (current_scope.count(str) == 0) { for (auto node : current_ast_mod->children) { if ((node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_GENVAR || - node->type == AST_MEMORY || node->type == AST_FUNCTION || node->type == AST_TASK) && str == node->str) { + node->type == AST_MEMORY || node->type == AST_FUNCTION || node->type == AST_TASK || node->type == AST_DPI_FUNCTION) && str == node->str) { current_scope[node->str] = node; break; } @@ -1442,6 +1442,34 @@ skip_dynamic_range_lvalue_expansion:; goto apply_newNode; } + if (current_scope.count(str) != 0 && current_scope[str]->type == AST_DPI_FUNCTION) + { + AstNode *dpi_decl = current_scope[str]; + + std::string rtype, fname; + std::vector argtypes; + std::vector args; + + rtype = RTLIL::unescape_id(dpi_decl->children.at(0)->str); + fname = RTLIL::unescape_id(dpi_decl->str); + + for (int i = 1; i < SIZE(dpi_decl->children); i++) + { + if (i-1 >= SIZE(children)) + log_error("Insufficient number of arguments in DPI function call at %s:%d.\n", filename.c_str(), linenum); + + argtypes.push_back(RTLIL::unescape_id(dpi_decl->children.at(i)->str)); + args.push_back(children.at(i-1)->clone()); + while (args.back()->simplify(true, false, false, stage, -1, false, true)) { } + + if (args.back()->type != AST_CONSTANT && args.back()->type != AST_REALVALUE) + log_error("Failed to evaluate DPI function with non-constant argument at %s:%d.\n", filename.c_str(), linenum); + } + + newNode = dpi_call(rtype, fname, argtypes, args); + goto apply_newNode; + } + if (current_scope.count(str) == 0 || current_scope[str]->type != AST_FUNCTION) log_error("Can't resolve function name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum); } -- cgit v1.2.3 From 490d7a5bf2062481dfda656de86bfbeca83c080d Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Aug 2014 13:09:47 +0200 Subject: Fixed memory leak in DPI function calls --- frontends/ast/simplify.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 19f1d0554..5cf64310b 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1467,6 +1467,10 @@ skip_dynamic_range_lvalue_expansion:; } newNode = dpi_call(rtype, fname, argtypes, args); + + for (auto arg : args) + delete arg; + goto apply_newNode; } -- cgit v1.2.3 From 6c5cafcd8bf4d6b12b4d510480a0ccc1adee7212 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Aug 2014 17:22:04 +0200 Subject: Added support for DPI function with different names in C and Verilog --- frontends/ast/simplify.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 5cf64310b..859058cb9 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1451,15 +1451,15 @@ skip_dynamic_range_lvalue_expansion:; std::vector args; rtype = RTLIL::unescape_id(dpi_decl->children.at(0)->str); - fname = RTLIL::unescape_id(dpi_decl->str); + fname = RTLIL::unescape_id(dpi_decl->children.at(1)->str); - for (int i = 1; i < SIZE(dpi_decl->children); i++) + for (int i = 2; i < SIZE(dpi_decl->children); i++) { - if (i-1 >= SIZE(children)) + if (i-2 >= SIZE(children)) log_error("Insufficient number of arguments in DPI function call at %s:%d.\n", filename.c_str(), linenum); argtypes.push_back(RTLIL::unescape_id(dpi_decl->children.at(i)->str)); - args.push_back(children.at(i-1)->clone()); + args.push_back(children.at(i-2)->clone()); while (args.back()->simplify(true, false, false, stage, -1, false, true)) { } if (args.back()->type != AST_CONSTANT && args.back()->type != AST_REALVALUE) -- cgit v1.2.3 From ad146c25823505e8f9b3cb2b67ba00821a755375 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Aug 2014 17:33:40 +0200 Subject: Fixed small memory leak in ast simplify --- frontends/ast/simplify.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 859058cb9..68c17271c 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1585,8 +1585,8 @@ skip_dynamic_range_lvalue_expansion:; { AstNode *arg = children[arg_count++]->clone(); AstNode *assign = child->is_input ? - new AstNode(AST_ASSIGN_EQ, wire_id, arg) : - new AstNode(AST_ASSIGN_EQ, arg, wire_id); + new AstNode(AST_ASSIGN_EQ, wire_id->clone(), arg) : + new AstNode(AST_ASSIGN_EQ, arg, wire_id->clone()); for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) { if (*it != current_block_child) @@ -1596,7 +1596,7 @@ skip_dynamic_range_lvalue_expansion:; } } - AstNode *cell_arg = new AstNode(AST_ARGUMENT, wire_id->clone()); + AstNode *cell_arg = new AstNode(AST_ARGUMENT, wire_id); cell_arg->str = child->str == str ? outport : child->str; cell->children.push_back(cell_arg); } -- cgit v1.2.3 From 79cbf9067c07ed810b3466174278d77b9a05b46d Mon Sep 17 00:00:00 2001 From: Ruben Undheim Date: Sat, 6 Sep 2014 08:47:06 +0200 Subject: Corrected spelling mistakes found by lintian --- frontends/ast/simplify.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 68c17271c..1998c12e4 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -464,7 +464,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (type == AST_DEFPARAM && !str.empty()) { size_t pos = str.rfind('.'); if (pos == std::string::npos) - log_error("Defparam `%s' does not contain a dot (module/parameter seperator) at %s:%d!\n", + log_error("Defparam `%s' does not contain a dot (module/parameter separator) at %s:%d!\n", RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); std::string modname = str.substr(0, pos), paraname = "\\" + str.substr(pos+1); if (current_scope.count(modname) == 0 || current_scope.at(modname)->type != AST_CELL) -- cgit v1.2.3 From 680eaaac41bc64000faa483955279155b0fc0a6b Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 6 Sep 2014 19:31:04 +0200 Subject: Fixed $clog2 (off by one error) --- frontends/ast/simplify.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 1998c12e4..9e797573c 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1123,7 +1123,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, 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); - result_width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1; + result_width = abs(left_at_zero_ast->integer - right_at_zero_ast->integer) + 1; } did_something = true; newNode = new AstNode(AST_CASE, shift_expr); @@ -1370,7 +1370,7 @@ skip_dynamic_range_lvalue_expansion:; uint32_t result = 0; for (size_t i = 0; i < arg_value.bits.size(); i++) if (arg_value.bits.at(i) == RTLIL::State::S1) - result = i; + result = i + 1; newNode = mkconst_int(result, false); goto apply_newNode; -- cgit v1.2.3 From 48b00dcceab8bb046258cd6f0912636a6e5b232c Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 8 Sep 2014 12:25:23 +0200 Subject: Another $clog2 bugfix --- frontends/ast/simplify.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'frontends/ast/simplify.cc') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 9e797573c..969cc2302 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1365,6 +1365,8 @@ skip_dynamic_range_lvalue_expansion:; log_error("Failed to evaluate system function `%s' with non-constant value at %s:%d.\n", str.c_str(), filename.c_str(), linenum); RTLIL::Const arg_value = buf->bitsAsConst(); + if (arg_value.as_bool()) + arg_value = const_sub(arg_value, 1, false, false, SIZE(arg_value)); delete buf; uint32_t result = 0; -- cgit v1.2.3