diff options
Diffstat (limited to 'frontends/ast')
-rw-r--r-- | frontends/ast/ast.cc | 4 | ||||
-rw-r--r-- | frontends/ast/genrtlil.cc | 46 | ||||
-rw-r--r-- | frontends/ast/simplify.cc | 224 |
3 files changed, 217 insertions, 57 deletions
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index a45859157..3e163bae7 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -699,7 +699,7 @@ AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signe for (size_t i = 0; i < 32; i++) { if (i < node->bits.size()) node->integer |= (node->bits[i] == RTLIL::S1) << i; - else if (is_signed) + else if (is_signed && !node->bits.empty()) node->integer |= (node->bits.back() == RTLIL::S1) << i; } node->range_valid = true; @@ -831,7 +831,7 @@ double AstNode::asReal(bool is_signed) { RTLIL::Const val(bits); - bool is_negative = is_signed && val.bits.back() == RTLIL::State::S1; + bool is_negative = is_signed && !val.bits.empty() && val.bits.back() == RTLIL::State::S1; if (is_negative) val = const_neg(val, val, false, false, val.bits.size()); diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index a2655e9a5..87e8379e9 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -520,6 +520,11 @@ struct AST_INTERNAL::ProcessGenerator log_error("Found wire declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum); break; + case AST_PARAMETER: + case AST_LOCALPARAM: + log_error("Found parameter declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum); + break; + case AST_TCALL: case AST_FOR: break; @@ -547,14 +552,14 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun switch (type) { case AST_CONSTANT: - width_hint = std::max(width_hint, int(bits.size())); + width_hint = max(width_hint, int(bits.size())); if (!is_signed) sign_hint = false; break; case AST_REALVALUE: *found_real = true; - width_hint = std::max(width_hint, 32); + width_hint = max(width_hint, 32); break; case AST_IDENTIFIER: @@ -617,7 +622,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun this_width = range->range_left - range->range_right + 1; sign_hint = false; } - width_hint = std::max(width_hint, this_width); + width_hint = max(width_hint, this_width); if (!id_ast->is_signed) sign_hint = false; break; @@ -627,7 +632,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (children[0]->type != AST_CONSTANT) log_error("Left operand of tobits expression is not constant at %s:%d!\n", filename.c_str(), linenum); children[1]->detectSignWidthWorker(sub_width_hint, sign_hint); - width_hint = std::max(width_hint, children[0]->bitsAsConst().as_int()); + width_hint = max(width_hint, children[0]->bitsAsConst().as_int()); break; case AST_TO_SIGNED: @@ -646,7 +651,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun child->detectSignWidthWorker(sub_width_hint, sub_sign_hint); this_width += sub_width_hint; } - width_hint = std::max(width_hint, this_width); + width_hint = max(width_hint, this_width); sign_hint = false; break; @@ -655,7 +660,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (children[0]->type != AST_CONSTANT) log_error("Left operand of replicate expression is not constant at %s:%d!\n", filename.c_str(), linenum); children[1]->detectSignWidthWorker(sub_width_hint, sub_sign_hint); - width_hint = std::max(width_hint, children[0]->bitsAsConst().as_int() * sub_width_hint); + width_hint = max(width_hint, children[0]->bitsAsConst().as_int() * sub_width_hint); sign_hint = false; break; @@ -678,7 +683,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_REDUCE_XOR: case AST_REDUCE_XNOR: case AST_REDUCE_BOOL: - width_hint = std::max(width_hint, 1); + width_hint = max(width_hint, 1); sign_hint = false; break; @@ -698,7 +703,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_NEX: case AST_GE: case AST_GT: - width_hint = std::max(width_hint, 1); + width_hint = max(width_hint, 1); sign_hint = false; break; @@ -714,7 +719,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_LOGIC_AND: case AST_LOGIC_OR: case AST_LOGIC_NOT: - width_hint = std::max(width_hint, 1); + width_hint = max(width_hint, 1); sign_hint = false; break; @@ -729,7 +734,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (!id2ast->children[0]->range_valid) log_error("Failed to detect with of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); this_width = id2ast->children[0]->range_left - id2ast->children[0]->range_right + 1; - width_hint = std::max(width_hint, this_width); + width_hint = max(width_hint, this_width); break; // everything should have been handled above -> print error if not. @@ -1054,7 +1059,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) detectSignWidth(width_hint, sign_hint); RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint); RTLIL::SigSpec right = children[1]->genRTLIL(width_hint, sign_hint); - int width = std::max(left.size(), right.size()); + int width = max(left.size(), right.size()); if (width_hint > 0) width = width_hint; is_signed = children[0]->is_signed && children[1]->is_signed; @@ -1068,7 +1073,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (0) { case AST_REDUCE_XNOR: type_name = "$reduce_xnor"; } { RTLIL::SigSpec arg = children[0]->genRTLIL(); - RTLIL::SigSpec sig = uniop2rtlil(this, type_name, std::max(width_hint, 1), arg); + RTLIL::SigSpec sig = uniop2rtlil(this, type_name, max(width_hint, 1), arg); return sig; } @@ -1077,7 +1082,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (0) { case AST_REDUCE_BOOL: type_name = "$reduce_bool"; } { RTLIL::SigSpec arg = children[0]->genRTLIL(); - RTLIL::SigSpec sig = arg.size() > 1 ? uniop2rtlil(this, type_name, std::max(width_hint, 1), arg) : arg; + RTLIL::SigSpec sig = arg.size() > 1 ? uniop2rtlil(this, type_name, max(width_hint, 1), arg) : arg; return sig; } @@ -1123,7 +1128,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (0) { case AST_GE: type_name = "$ge"; } if (0) { case AST_GT: type_name = "$gt"; } { - int width = std::max(width_hint, 1); + int width = max(width_hint, 1); width_hint = -1, sign_hint = true; children[0]->detectSignWidthWorker(width_hint, sign_hint); children[1]->detectSignWidthWorker(width_hint, sign_hint); @@ -1145,7 +1150,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) RTLIL::SigSpec left = children[0]->genRTLIL(width_hint, sign_hint); RTLIL::SigSpec right = children[1]->genRTLIL(width_hint, sign_hint); #if 0 - int width = std::max(left.size(), right.size()); + int width = max(left.size(), right.size()); if (width > width_hint && width_hint > 0) width = width_hint; if (width < width_hint) { @@ -1154,10 +1159,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (type == AST_SUB && (!children[0]->is_signed || !children[1]->is_signed)) width = width_hint; if (type == AST_MUL) - width = std::min(left.size() + right.size(), width_hint); + width = min(left.size() + right.size(), width_hint); } #else - int width = std::max(std::max(left.size(), right.size()), width_hint); + int width = max(max(left.size(), right.size()), width_hint); #endif is_signed = children[0]->is_signed && children[1]->is_signed; return binop2rtlil(this, type_name, width, left, right); @@ -1169,14 +1174,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) { RTLIL::SigSpec left = children[0]->genRTLIL(); RTLIL::SigSpec right = children[1]->genRTLIL(); - return binop2rtlil(this, type_name, std::max(width_hint, 1), left, right); + return binop2rtlil(this, type_name, max(width_hint, 1), left, right); } // generate cells for unary operations: $logic_not case AST_LOGIC_NOT: { RTLIL::SigSpec arg = children[0]->genRTLIL(); - return uniop2rtlil(this, "$logic_not", std::max(width_hint, 1), arg); + return uniop2rtlil(this, "$logic_not", max(width_hint, 1), arg); } // generate multiplexer for ternary operator (aka ?:-operator) @@ -1192,7 +1197,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (cond.size() > 1) cond = uniop2rtlil(this, "$reduce_bool", 1, cond, false); - int width = std::max(val1.size(), val2.size()); + int width = max(val1.size(), val2.size()); is_signed = children[1]->is_signed && children[2]->is_signed; widthExtend(this, val1, width, is_signed); widthExtend(this, val2, width, is_signed); @@ -1220,6 +1225,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) id2ast->meminfo(mem_width, mem_size, addr_bits); cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1)); + cell->setPort("\\EN", RTLIL::SigSpec(RTLIL::State::Sx, 1)); cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits)); cell->setPort("\\DATA", RTLIL::SigSpec(wire)); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 5eb173c9a..2264d896a 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -174,13 +174,113 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } // deactivate all calls to non-synthesis system tasks - if ((type == AST_FCALL || type == AST_TCALL) && (str == "$display" || str == "$strobe" || str == "$monitor" || str == "$time" || str == "$stop" || str == "$finish" || + // note that $display and $finish are used for synthesis-time DRC so they're not in this list + if ((type == AST_FCALL || type == AST_TCALL) && (str == "$strobe" || str == "$monitor" || str == "$time" || str == "$stop" || str == "$dumpfile" || str == "$dumpvars" || str == "$dumpon" || str == "$dumpoff" || str == "$dumpall")) { log_warning("Ignoring call to system %s %s at %s:%d.\n", type == AST_FCALL ? "function" : "task", str.c_str(), filename.c_str(), linenum); delete_children(); str = std::string(); } + if ((type == AST_TCALL) && (str == "$display" || str == "$write") && (!current_always || current_always->type != AST_INITIAL)) { + log_warning("System task `%s' outside initial block is unsupported at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + delete_children(); + str = std::string(); + } + + // print messages if this a call to $display() or $write() + // This code implements only a small subset of Verilog-2005 $display() format specifiers, + // but should be good enough for most uses + if ((type == AST_TCALL) && ((str == "$display") || (str == "$write"))) + { + size_t nargs = GetSize(children); + if(nargs < 1) + log_error("System task `%s' got %d arguments, expected >= 1 at %s:%d.\n", + str.c_str(), int(children.size()), filename.c_str(), linenum); + + // First argument is the format string + AstNode *node_string = children[0]->clone(); + while (node_string->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } + if (node_string->type != AST_CONSTANT) + log_error("Failed to evaluate system task `%s' with non-constant 1st argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + std::string sformat = node_string->bitsAsConst().decode_string(); + + // Other arguments are placeholders. Process the string as we go through it + std::string sout; + size_t next_arg = 1; + for(size_t i=0; i<sformat.length(); i++) + { + // format specifier + if(sformat[i] == '%') + { + // If there's no next character, that's a problem + if(i+1 >= sformat.length()) + log_error("System task `%s' called with `%%' at end of string at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + + char cformat = sformat[++i]; + + // %% is special, does not need a matching argument + if(cformat == '%') + { + sout += '%'; + continue; + } + + // If we're out of arguments, that's a problem! + if(next_arg >= nargs) + log_error("System task `%s' called with more format specifiers than arguments at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + + // Simplify the argument + AstNode *node_arg = children[next_arg ++]->clone(); + while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } + if (node_arg->type != AST_CONSTANT) + log_error("Failed to evaluate system task `%s' with non-constant argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + + // Everything from here on depends on the format specifier + switch(cformat) + { + case 's': + case 'S': + sout += node_arg->bitsAsConst().decode_string(); + break; + + case 'd': + case 'D': + { + char tmp[128]; + snprintf(tmp, sizeof(tmp), "%d", node_arg->bitsAsConst().as_int()); + sout += tmp; + } + break; + + case 'x': + case 'X': + { + char tmp[128]; + snprintf(tmp, sizeof(tmp), "%x", node_arg->bitsAsConst().as_int()); + sout += tmp; + } + break; + + default: + log_error("System task `%s' called with invalid format specifier at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + break; + } + } + + // not a format specifier + else + sout += sformat[i]; + } + + // Finally, print the message (only include a \n for $display, not for $write) + log("%s", sout.c_str()); + if(str == "$display") + log("\n"); + delete_children(); + str = std::string(); + } + // 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; @@ -298,7 +398,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, 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); + width_hint = max(width_hint, backup_width_hint); child_0_is_self_determined = true; break; @@ -312,7 +412,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, 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); + width_hint = max(width_hint, children[1]->range_left - children[1]->range_right + 1); } break; @@ -552,6 +652,8 @@ 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); } + if (children[1]->type == AST_PREFIX) + children[1]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param); log_assert(children[1]->type == AST_IDENTIFIER); newNode = children[1]->clone(); const char *second_part = children[1]->str.c_str(); @@ -631,8 +733,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, 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); + multirange_dimensions.push_back(min(range->range_left, range->range_right)); + multirange_dimensions.push_back(max(range->range_left, range->range_right) - min(range->range_left, range->range_right) + 1); total_size *= multirange_dimensions.back(); } delete children[1]; @@ -658,10 +760,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, 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); + 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 = GetSize(id2ast->multirange_dimensions)/1; i < GetSize(children[0]->children); i++) + for (int i = GetSize(id2ast->multirange_dimensions)/2; i < GetSize(children[0]->children); i++) children.push_back(children[0]->children[i]->clone()); delete children[0]; @@ -911,7 +1013,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, std::vector<AstNode*> new_children; for (size_t i = 0; i < children.size(); i++) - if (children[i]->type == AST_WIRE) { + if (children[i]->type == AST_WIRE || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM) { 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]; @@ -1067,7 +1169,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, 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; + int num = max(children.at(0)->range_left, children.at(0)->range_right) - 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; @@ -1274,7 +1376,7 @@ skip_dynamic_range_lvalue_expansion:; // found right-hand side identifier for memory -> replace with memory read port if (stage > 1 && type == AST_IDENTIFIER && id2ast != NULL && id2ast->type == AST_MEMORY && !in_lvalue && - children[0]->type == AST_RANGE && children[0]->children.size() == 1) { + children.size() == 1 && children[0]->type == AST_RANGE && children[0]->children.size() == 1) { newNode = new AstNode(AST_MEMRD, children[0]->children[0]->clone()); newNode->str = str; newNode->id2ast = id2ast; @@ -1569,7 +1671,17 @@ skip_dynamic_range_lvalue_expansion:; 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); } - if (type == AST_TCALL) { + + if (type == AST_TCALL) + { + if (str == "$finish") + { + if (!current_always || current_always->type != AST_INITIAL) + log_error("System task `$finish' outside initial block is unsupported at %s:%d.\n", filename.c_str(), linenum); + + log_error("System task `$finish' executed at %s:%d.\n", filename.c_str(), linenum); + } + if (str == "\\$readmemh" || str == "\\$readmemb") { if (GetSize(children) < 2 || GetSize(children) > 4) @@ -1606,12 +1718,19 @@ skip_dynamic_range_lvalue_expansion:; bool unconditional_init = false; if (current_always->type == AST_INITIAL) { + pool<AstNode*> queue; log_assert(current_always->children[0]->type == AST_BLOCK); - for (auto n : current_always->children[0]->children) - if (n == this) { - unconditional_init = true; - break; + queue.insert(current_always->children[0]); + while (!unconditional_init && !queue.empty()) { + pool<AstNode*> next_queue; + for (auto n : queue) + for (auto c : n->children) { + if (c == this) + unconditional_init = true; + next_queue.insert(c); } + next_queue.swap(queue); + } } newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr, unconditional_init); @@ -1654,6 +1773,8 @@ skip_dynamic_range_lvalue_expansion:; size_t arg_count = 0; std::map<std::string, std::string> replace_rules; + vector<AstNode*> added_mod_children; + dict<std::string, AstNode*> wire_cache; if (current_block == NULL) { @@ -1746,17 +1867,39 @@ skip_dynamic_range_lvalue_expansion:; } for (auto child : decl->children) - if (child->type == AST_WIRE) + if (child->type == AST_WIRE || child->type == AST_PARAMETER || child->type == AST_LOCALPARAM) { - 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 = nullptr; + + if (wire_cache.count(child->str)) + { + wire = wire_cache.at(child->str); + if (wire->children.empty()) { + for (auto c : child->children) + wire->children.push_back(c->clone()); + } else { + if (!child->children.empty()) + log_error("Incompatible re-declaration of wire %s at %s:%d.\n", child->str.c_str(), filename.c_str(), linenum); + } + } + else + { + wire = child->clone(); + wire->str = prefix + wire->str; + wire->port_id = 0; + wire->is_input = false; + wire->is_output = false; + wire_cache[child->str] = wire; + + current_ast_mod->children.push_back(wire); + added_mod_children.push_back(wire); + } + + if (child->type == AST_WIRE) + while (wire->simplify(true, false, false, 1, -1, false, false)) { } replace_rules[child->str] = wire->str; + current_scope[wire->str] = wire; if ((child->is_input || child->is_output) && arg_count < children.size()) { @@ -1776,8 +1919,13 @@ skip_dynamic_range_lvalue_expansion:; } } + for (auto child : added_mod_children) { + child->replace_ids(prefix, replace_rules); + while (child->simplify(true, false, false, 1, -1, false, false)) { } + } + for (auto child : decl->children) - if (child->type != AST_WIRE) + if (child->type != AST_WIRE && child->type != AST_PARAMETER && child->type != AST_LOCALPARAM) { AstNode *stmt = child->clone(); stmt->replace_ids(prefix, replace_rules); @@ -1924,7 +2072,7 @@ skip_dynamic_range_lvalue_expansion:; if (0) { case AST_GE: const_func = RTLIL::const_ge; } if (0) { case AST_GT: const_func = RTLIL::const_gt; } if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) { - int cmp_width = std::max(children[0]->bits.size(), children[1]->bits.size()); + int cmp_width = max(children[0]->bits.size(), children[1]->bits.size()); bool cmp_signed = children[0]->is_signed && children[1]->is_signed; RTLIL::Const y = const_func(children[0]->bitsAsConst(cmp_width, cmp_signed), children[1]->bitsAsConst(cmp_width, cmp_signed), cmp_signed, cmp_signed, 1); @@ -2099,6 +2247,9 @@ static void replace_result_wire_name_in_function(AstNode *node, std::string &fro // replace a readmem[bh] TCALL ast node with a block of memory assignments AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init) { + int mem_width, mem_size, addr_bits; + memory->meminfo(mem_width, mem_size, addr_bits); + AstNode *block = new AstNode(AST_BLOCK); AstNode *meminit = nullptr; @@ -2114,13 +2265,13 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m log_assert(GetSize(memory->children) == 2 && memory->children[1]->type == AST_RANGE && memory->children[1]->range_valid); int range_left = memory->children[1]->range_left, range_right = memory->children[1]->range_right; - int range_min = std::min(range_left, range_right), range_max = std::max(range_left, range_right); + int range_min = min(range_left, range_right), range_max = max(range_left, range_right); if (start_addr < 0) start_addr = range_min; if (finish_addr < 0) - finish_addr = range_max; + finish_addr = range_max + 1; bool in_comment = false; int increment = start_addr <= finish_addr ? +1 : -1; @@ -2160,7 +2311,7 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m continue; } - AstNode *value = VERILOG_FRONTEND::const2ast((is_readmemh ? "'h" : "'b") + token); + AstNode *value = VERILOG_FRONTEND::const2ast(stringf("%d'%c", mem_width, is_readmemh ? 'h' : 'b') + token); if (unconditional_init) { @@ -2196,12 +2347,12 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m block->children.back()->children[0]->id2ast = memory; } - if ((cursor == finish_addr) || (increment > 0 && cursor >= range_max) || (increment < 0 && cursor <= range_min)) + if ((cursor == finish_addr) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min)) break; cursor += increment; } - if ((cursor == finish_addr) || (increment > 0 && cursor >= range_max) || (increment < 0 && cursor <= range_min)) + if ((cursor == finish_addr) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min)) break; } @@ -2598,7 +2749,7 @@ void AstNode::meminfo(int &mem_width, int &mem_size, int &addr_bits) if (mem_size < 0) mem_size *= -1; - mem_size += std::min(children[1]->range_left, children[1]->range_right) + 1; + mem_size += min(children[1]->range_left, children[1]->range_right) + 1; addr_bits = 1; while ((1 << addr_bits) < mem_size) @@ -2634,8 +2785,8 @@ void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &varia 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(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 = min(children.at(0)->range_left, children.at(0)->range_right); + width = min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width); } offset -= variables.at(str).offset; std::vector<RTLIL::State> &var_bits = variables.at(str).val.bits; @@ -2675,7 +2826,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) 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].offset = 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()); @@ -2706,6 +2857,9 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) if (stmt->type == AST_ASSIGN_EQ) { + if (stmt->children.at(0)->type == AST_IDENTIFIER && stmt->children.at(0)->children.size() != 0 && + stmt->children.at(0)->children.at(0)->type == AST_RANGE) + stmt->children.at(0)->children.at(0)->replace_variables(variables, fcall); stmt->children.at(1)->replace_variables(variables, fcall); while (stmt->simplify(true, false, false, 1, -1, false, true)) { } @@ -2731,7 +2885,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) 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 offset = min(range->range_left, range->range_right); 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()); |