diff options
Diffstat (limited to 'frontends/ast')
-rw-r--r-- | frontends/ast/ast.cc | 71 | ||||
-rw-r--r-- | frontends/ast/ast.h | 18 | ||||
-rw-r--r-- | frontends/ast/genrtlil.cc | 105 | ||||
-rw-r--r-- | frontends/ast/simplify.cc | 412 |
4 files changed, 521 insertions, 85 deletions
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 834ee82a..fd272400 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -30,15 +30,6 @@ #include "libs/sha1/sha1.h" #include "ast.h" -#include <sstream> -#include <stdarg.h> - -#if defined(__APPLE__) -# include <cmath> -#else -# include <math.h> -#endif - YOSYS_NAMESPACE_BEGIN using namespace AST; @@ -53,13 +44,15 @@ namespace AST { // instanciate global variables (private API) namespace AST_INTERNAL { - bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire; + bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit; + bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire; AstNode *current_ast, *current_ast_mod; std::map<std::string, AstNode*> current_scope; const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL; RTLIL::SigSpec ignoreThisSignalsInInitial; AstNode *current_always, *current_top_block, *current_block, *current_block_child; AstModule *current_module; + bool current_always_clocked; } // convert node types to string @@ -146,6 +139,8 @@ std::string AST::type2str(AstNodeType type) X(AST_ASSIGN_LE) X(AST_CASE) X(AST_COND) + X(AST_CONDX) + X(AST_CONDZ) X(AST_DEFAULT) X(AST_FOR) X(AST_WHILE) @@ -158,6 +153,7 @@ std::string AST::type2str(AstNodeType type) X(AST_POSEDGE) X(AST_NEGEDGE) X(AST_EDGE) + X(AST_PACKAGE) #undef X default: log_abort(); @@ -180,7 +176,7 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id) // create new node (AstNode constructor) // (the optional child arguments make it easier to create AST trees) -AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2) +AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *child3) { static unsigned int hashidx_count = 123456789; hashidx_count = mkhash_xorshift(hashidx_count); @@ -208,6 +204,8 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2) children.push_back(child1); if (child2) children.push_back(child2); + if (child3) + children.push_back(child3); } // create a (deep recursive) copy of a node @@ -311,6 +309,8 @@ void AstNode::dumpAst(FILE *f, std::string indent) for (size_t i = 0; i < children.size(); i++) children[i]->dumpAst(f, indent + " "); + + fflush(f); } // helper function for AstNode::dumpVlog() @@ -435,16 +435,15 @@ void AstNode::dumpVlog(FILE *f, std::string indent) break; case AST_ALWAYS: - fprintf(f, "%s" "always @(", indent.c_str()); + fprintf(f, "%s" "always @", indent.c_str()); for (auto child : children) { if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE) continue; - if (!first) - fprintf(f, ", "); + fprintf(f, first ? "(" : ", "); child->dumpVlog(f, ""); first = false; } - fprintf(f, ")\n"); + fprintf(f, first ? "*\n" : ")\n"); for (auto child : children) { if (child->type != AST_POSEDGE && child->type != AST_NEGEDGE && child->type != AST_EDGE) child->dumpVlog(f, indent + " "); @@ -501,7 +500,12 @@ void AstNode::dumpVlog(FILE *f, std::string indent) break; case AST_CASE: - fprintf(f, "%s" "case (", indent.c_str()); + if (!children.empty() && children[0]->type == AST_CONDX) + fprintf(f, "%s" "casex (", indent.c_str()); + else if (!children.empty() && children[0]->type == AST_CONDZ) + fprintf(f, "%s" "casez (", indent.c_str()); + else + fprintf(f, "%s" "case (", indent.c_str()); children[0]->dumpVlog(f, ""); fprintf(f, ")\n"); for (size_t i = 1; i < children.size(); i++) { @@ -512,6 +516,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent) break; case AST_COND: + case AST_CONDX: + case AST_CONDZ: for (auto child : children) { if (child->type == AST_BLOCK) { fprintf(f, ":\n"); @@ -528,6 +534,14 @@ void AstNode::dumpVlog(FILE *f, std::string indent) } break; + case AST_ASSIGN: + fprintf(f, "%sassign ", indent.c_str()); + children[0]->dumpVlog(f, ""); + fprintf(f, " = "); + children[1]->dumpVlog(f, ""); + fprintf(f, ";\n"); + break; + case AST_ASSIGN_EQ: case AST_ASSIGN_LE: fprintf(f, "%s", indent.c_str()); @@ -616,6 +630,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent) fprintf(f, "%s" "/** %s **/%s", indent.c_str(), type_name.c_str(), indent.empty() ? "" : "\n"); // dumpAst(f, indent, NULL); } + + fflush(f); } // check if two AST nodes are identical @@ -967,16 +983,25 @@ static AstModule* process_module(AstNode *ast, bool defer) current_module->icells = flag_icells; current_module->autowire = flag_autowire; current_module->fixup_ports(); + + if (flag_dump_rtlil) { + log("Dumping generated RTLIL:\n"); + log_module(current_module); + log("--- END OF RTLIL DUMP ---\n"); + } + return current_module; } // create AstModule instances for all modules in the AST tree and add them to 'design' -void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire) +void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool dump_rtlil, + bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire) { current_ast = ast; flag_dump_ast1 = dump_ast1; flag_dump_ast2 = dump_ast2; flag_dump_vlog = dump_vlog; + flag_dump_rtlil = dump_rtlil; flag_nolatches = nolatches; flag_nomeminit = nomeminit; flag_nomem2reg = nomem2reg; @@ -996,6 +1021,14 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump for (auto n : global_decls) (*it)->children.push_back(n->clone()); + for (auto n : design->verilog_packages){ + for (auto o : n->children) { + AstNode *cloned_node = o->clone(); + cloned_node->str = n->str + std::string("::") + cloned_node->str.substr(1); + (*it)->children.push_back(cloned_node); + } + } + if (flag_icells && (*it)->str.substr(0, 2) == "\\$") (*it)->str = (*it)->str.substr(1); @@ -1013,6 +1046,8 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump design->add(process_module(*it, defer)); } + else if ((*it)->type == AST_PACKAGE) + design->verilog_packages.push_back((*it)->clone()); else global_decls.push_back(*it); } @@ -1033,7 +1068,7 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R if (stripped_name.substr(0, 9) == "$abstract") stripped_name = stripped_name.substr(9); - log_header("Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str()); + log_header(design, "Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str()); current_ast = NULL; flag_dump_ast1 = false; diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index b5349db5..cd6e264e 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -122,6 +122,8 @@ namespace AST AST_ASSIGN_LE, AST_CASE, AST_COND, + AST_CONDX, + AST_CONDZ, AST_DEFAULT, AST_FOR, AST_WHILE, @@ -135,7 +137,9 @@ namespace AST AST_POSEDGE, AST_NEGEDGE, - AST_EDGE + AST_EDGE, + + AST_PACKAGE }; // convert an node type to a string (e.g. for debug output) @@ -182,7 +186,7 @@ namespace AST int linenum; // creating and deleting nodes - AstNode(AstNodeType type = AST_NONE, AstNode *child1 = NULL, AstNode *child2 = NULL); + AstNode(AstNodeType type = AST_NONE, AstNode *child1 = NULL, AstNode *child2 = NULL, AstNode *child3 = NULL); AstNode *clone(); void cloneInto(AstNode *other); void delete_children(); @@ -215,8 +219,9 @@ namespace AST void replace_ids(const std::string &prefix, const std::map<std::string, std::string> &rules); void mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places, dict<AstNode*, uint32_t> &mem2reg_flags, dict<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags); - bool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block); + bool mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode *&async_block); bool mem2reg_check(pool<AstNode*> &mem2reg_set); + void mem2reg_remove(pool<AstNode*> &mem2reg_set, vector<AstNode*> &delnodes); void meminfo(int &mem_width, int &mem_size, int &addr_bits); // additional functionality for evaluating constant functions @@ -266,7 +271,8 @@ namespace AST }; // process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code - void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire); + void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool dump_rtlil, bool nolatches, bool nomeminit, + bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire); // parametric modules are supported directly by the AST library // therefore we need our own derivate of RTLIL::Module with overloaded virtual functions @@ -296,13 +302,15 @@ namespace AST namespace AST_INTERNAL { // internal state variables - extern bool flag_dump_ast1, flag_dump_ast2, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire; + extern bool flag_dump_ast1, flag_dump_ast2, flag_dump_rtlil, flag_nolatches, flag_nomeminit; + extern bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire; extern AST::AstNode *current_ast, *current_ast_mod; extern std::map<std::string, AST::AstNode*> current_scope; extern const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr; extern RTLIL::SigSpec ignoreThisSignalsInInitial; extern AST::AstNode *current_always, *current_top_block, *current_block, *current_block_child; extern AST::AstModule *current_module; + extern bool current_always_clocked; struct ProcessGenerator; } diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 9fc59037..3c57162a 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -241,6 +241,8 @@ struct AST_INTERNAL::ProcessGenerator RTLIL::SyncRule *syncrule = new RTLIL::SyncRule; syncrule->type = child->type == AST_POSEDGE ? RTLIL::STp : RTLIL::STn; syncrule->signal = child->children[0]->genRTLIL(); + if (GetSize(syncrule->signal) != 1) + log_error("Found posedge/negedge event on a signal that is not 1 bit wide at %s:%d!\n", always->filename.c_str(), always->linenum); addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to, true); proc->syncs.push_back(syncrule); } @@ -338,12 +340,14 @@ struct AST_INTERNAL::ProcessGenerator case AST_CASE: for (auto child : ast->children) if (child != ast->children[0]) { - log_assert(child->type == AST_COND); + log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ); collect_lvalues(reg, child, type_eq, type_le, false); } break; case AST_COND: + case AST_CONDX: + case AST_CONDZ: case AST_ALWAYS: case AST_INITIAL: for (auto child : ast->children) @@ -427,6 +431,17 @@ struct AST_INTERNAL::ProcessGenerator { RTLIL::SigSpec unmapped_lvalue = ast->children[0]->genRTLIL(), lvalue = unmapped_lvalue; RTLIL::SigSpec rvalue = ast->children[1]->genWidthRTLIL(lvalue.size(), &subst_rvalue_map.stdmap()); + + pool<SigBit> lvalue_sigbits; + for (int i = 0; i < GetSize(lvalue); i++) { + if (lvalue_sigbits.count(lvalue[i]) > 0) { + unmapped_lvalue.remove(i); + lvalue.remove(i); + rvalue.remove(i--); + } else + lvalue_sigbits.insert(lvalue[i]); + } + lvalue.replace(subst_lvalue_map.stdmap()); if (ast->type == AST_ASSIGN_EQ) { @@ -443,6 +458,7 @@ struct AST_INTERNAL::ProcessGenerator case AST_CASE: { RTLIL::SwitchRule *sw = new RTLIL::SwitchRule; + sw->attributes["\\src"] = stringf("%s:%d", ast->filename.c_str(), ast->linenum); sw->signal = ast->children[0]->genWidthRTLIL(-1, &subst_rvalue_map.stdmap()); current_case->switches.push_back(sw); @@ -467,7 +483,7 @@ struct AST_INTERNAL::ProcessGenerator { if (child == ast->children[0]) continue; - log_assert(child->type == AST_COND); + log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ); subst_lvalue_map.save(); subst_rvalue_map.save(); @@ -525,6 +541,7 @@ struct AST_INTERNAL::ProcessGenerator log_error("Found parameter declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum); break; + case AST_NONE: case AST_TCALL: case AST_FOR: break; @@ -589,7 +606,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun // log("---\n"); // id_ast->dumpAst(NULL, "decl> "); // dumpAst(NULL, "ref> "); - log_error("Failed to detect with of signal access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); + log_error("Failed to detect width of signal access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); } } else { this_width = id_ast->range_left - id_ast->range_right + 1; @@ -600,7 +617,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun this_width = 32; } else if (id_ast->type == AST_MEMORY) { if (!id_ast->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); + log_error("Failed to detect width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1; } else log_error("Failed to detect width for identifier %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum); @@ -732,11 +749,34 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (!id2ast->is_signed) sign_hint = false; 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); + log_error("Failed to detect width 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 = max(width_hint, this_width); break; + case AST_FCALL: + if (str == "\\$anyconst") { + if (GetSize(children) == 1) { + while (children[0]->simplify(true, false, false, 1, -1, false, true) == true) { } + if (children[0]->type != AST_CONSTANT) + log_error("System function %s called with non-const argument at %s:%d!\n", + RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); + width_hint = max(width_hint, int(children[0]->asInt(true))); + } + break; + } + if (str == "\\$past") { + if (GetSize(children) > 0) { + sub_width_hint = 0; + sub_sign_hint = true; + children.at(0)->detectSignWidthWorker(sub_width_hint, sub_sign_hint); + width_hint = max(width_hint, sub_width_hint); + sign_hint = false; + } + break; + } + /* fall through */ + // everything should have been handled above -> print error if not. default: for (auto f : log_files) @@ -782,6 +822,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // simply ignore this nodes. // they are either leftovers from simplify() or are referenced by other nodes // and are only accessed here thru this references + case AST_NONE: case AST_TASK: case AST_FUNCTION: case AST_DPI_FUNCTION: @@ -793,6 +834,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) case AST_GENBLOCK: case AST_GENIF: case AST_GENCASE: + case AST_PACKAGE: break; // remember the parameter, needed for example in techmap @@ -1224,13 +1266,15 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) int mem_width, mem_size, addr_bits; id2ast->meminfo(mem_width, mem_size, addr_bits); + RTLIL::SigSpec addr_sig = children[0]->genRTLIL(); + 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("\\ADDR", addr_sig); cell->setPort("\\DATA", RTLIL::SigSpec(wire)); cell->parameters["\\MEMID"] = RTLIL::Const(str); - cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits); + cell->parameters["\\ABITS"] = RTLIL::Const(GetSize(addr_sig)); cell->parameters["\\WIDTH"] = RTLIL::Const(wire->width); cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0); @@ -1261,11 +1305,13 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) cell->parameters["\\WORDS"] = RTLIL::Const(num_words); } - cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits)); + SigSpec addr_sig = children[0]->genRTLIL(); + + cell->setPort("\\ADDR", addr_sig); cell->setPort("\\DATA", children[1]->genWidthRTLIL(current_module->memories[str]->width * num_words)); cell->parameters["\\MEMID"] = RTLIL::Const(str); - cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits); + cell->parameters["\\ABITS"] = RTLIL::Const(GetSize(addr_sig)); cell->parameters["\\WIDTH"] = RTLIL::Const(current_module->memories[str]->width); if (type == AST_MEMWR) { @@ -1283,6 +1329,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) case AST_ASSERT: case AST_ASSUME: { + const char *celltype = "$assert"; + if (type == AST_ASSUME) celltype = "$assume"; + log_assert(children.size() == 2); RTLIL::SigSpec check = children[0]->genRTLIL(); @@ -1294,9 +1343,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) en = current_module->ReduceBool(NEW_ID, en); std::stringstream sstr; - sstr << (type == AST_ASSERT ? "$assert$" : "$assume$") << filename << ":" << linenum << "$" << (autoidx++); + sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++); - RTLIL::Cell *cell = current_module->addCell(sstr.str(), type == AST_ASSERT ? "$assert" : "$assume"); + RTLIL::Cell *cell = current_module->addCell(sstr.str(), celltype); cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); for (auto &attr : attributes) { @@ -1408,6 +1457,40 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) delete always; } break; + case AST_FCALL: { + if (str == "\\$anyconst") + { + string myid = stringf("%s$%d", str.c_str() + 1, autoidx++); + int width = width_hint; + + if (GetSize(children) > 1) + log_error("System function %s got %d arguments, expected 1 or 0 at %s:%d.\n", + RTLIL::unescape_id(str).c_str(), GetSize(children), filename.c_str(), linenum); + + if (GetSize(children) == 1) { + if (children[0]->type != AST_CONSTANT) + log_error("System function %s called with non-const argument at %s:%d!\n", + RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); + width = children[0]->asInt(true); + } + + if (width <= 0) + log_error("Failed to detect width of %s at %s:%d!\n", + RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); + + Cell *cell = current_module->addCell(myid, str.substr(1)); + cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); + cell->parameters["\\WIDTH"] = width; + + Wire *wire = current_module->addWire(myid + "_wire", width); + wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); + cell->setPort("\\Y", wire); + + is_signed = sign_hint; + return SigSpec(wire); + } + } /* fall through */ + // everything should have been handled above -> print error if not. default: for (auto f : log_files) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 2621be49..57aa648c 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -63,7 +63,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, #if 0 log("-------------\n"); - log("AST simplify[%d] depth %d at %s:%d,\n", stage, recursion_counter, filename.c_str(), linenum); + log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, filename.c_str(), linenum, type2str(type).c_str(), this); 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, "> "); @@ -148,14 +148,14 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } } - while (mem2reg_as_needed_pass2(mem2reg_set, this, NULL)) { } + AstNode *async_block = NULL; + while (mem2reg_as_needed_pass2(mem2reg_set, this, NULL, async_block)) { } - for (size_t i = 0; i < children.size(); i++) { - if (mem2reg_set.count(children[i]) > 0) { - delete children[i]; - children.erase(children.begin() + (i--)); - } - } + vector<AstNode*> delnodes; + mem2reg_remove(mem2reg_set, delnodes); + + for (auto node : delnodes) + delete node; } while (simplify(const_fold, at_zero, in_lvalue, 2, width_hint, sign_hint, in_param)) { } @@ -174,8 +174,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } // deactivate all calls to non-synthesis system tasks - // 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" || + // note that $display, $finish, and $stop 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 == "$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(); @@ -193,13 +193,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, // but should be good enough for most uses if ((type == AST_TCALL) && ((str == "$display") || (str == "$write"))) { - size_t nargs = GetSize(children); - if(nargs < 1) + int 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(); + AstNode *node_string = children[0]; 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); @@ -207,37 +207,57 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, // 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++) + int next_arg = 1; + for (size_t i = 0; i < sformat.length(); i++) { // format specifier - if(sformat[i] == '%') + if (sformat[i] == '%') { // If there's no next character, that's a problem - if(i+1 >= sformat.length()) + 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 == '%') + 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); + AstNode *node_arg = nullptr; // Everything from here on depends on the format specifier - switch(cformat) + switch (cformat) + { + case 's': + case 'S': + case 'd': + case 'D': + case 'x': + case 'X': + if (next_arg >= GetSize(children)) + log_error("Missing argument for %%%c format specifier in system task `%s' at %s:%d.\n", + cformat, str.c_str(), filename.c_str(), linenum); + + node_arg = children[next_arg++]; + 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); + break; + + case 'm': + case 'M': + break; + + default: + log_error("System task `%s' called with invalid/unsupported format specifier at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + break; + } + + switch (cformat) { case 's': case 'S': @@ -262,9 +282,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } break; - default: - log_error("System task `%s' called with invalid format specifier at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + case 'm': + case 'M': + sout += log_id(current_module->name); break; + + default: + log_abort(); } } @@ -275,7 +299,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, // Finally, print the message (only include a \n for $display, not for $write) log("%s", sout.c_str()); - if(str == "$display") + if (str == "$display") log("\n"); delete_children(); str = std::string(); @@ -373,9 +397,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, auto backup_current_block_child = current_block_child; auto backup_current_top_block = current_top_block; auto backup_current_always = current_always; + auto backup_current_always_clocked = current_always_clocked; if (type == AST_ALWAYS || type == AST_INITIAL) + { current_always = this; + current_always_clocked = false; + + if (type == AST_ALWAYS) + for (auto child : children) + if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE) + current_always_clocked = true; + } int backup_width_hint = width_hint; bool backup_sign_hint = sign_hint; @@ -489,6 +522,11 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, children_are_self_determined = true; break; + case AST_FCALL: + case AST_TCALL: + children_are_self_determined = true; + break; + default: width_hint = -1; sign_hint = false; @@ -504,6 +542,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, detectSignWidth(width_hint, sign_hint); } + if (type == AST_FCALL && str == "\\$past") + detectSignWidth(width_hint, sign_hint); + if (type == AST_TERNARY) { int width_hint_left, width_hint_right; bool sign_hint_left, sign_hint_right; @@ -516,6 +557,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } } + if (type == AST_CONDX && children.size() > 0 && children.at(0)->type == AST_CONSTANT) { + for (auto &bit : children.at(0)->bits) + if (bit == State::Sz || bit == State::Sx) + bit = State::Sa; + } + + if (type == AST_CONDZ && children.size() > 0 && children.at(0)->type == AST_CONSTANT) { + for (auto &bit : children.at(0)->bits) + if (bit == State::Sz) + bit = State::Sa; + } + if (const_fold && type == AST_CASE) { while (children[0]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { } @@ -524,7 +577,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, new_children.push_back(children[0]); for (int i = 1; i < GetSize(children); i++) { AstNode *child = children[i]; - log_assert(child->type == AST_COND); + log_assert(child->type == AST_COND || child->type == AST_CONDX || child->type == AST_CONDZ); for (auto v : child->children) { if (v->type == AST_DEFAULT) goto keep_const_cond; @@ -616,6 +669,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, current_block_child = backup_current_block_child; current_top_block = backup_current_top_block; current_always = backup_current_always; + current_always_clocked = backup_current_always_clocked; for (auto it = backup_scope.begin(); it != backup_scope.end(); it++) { if (it->second == NULL) @@ -794,7 +848,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, 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); + children[0] = mkconst_bits(sig.as_const().bits, is_signed); delete old_child_0; } children[0]->is_signed = is_signed; @@ -847,11 +901,14 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int mem_width, mem_size, addr_bits; id2ast->meminfo(mem_width, mem_size, addr_bits); + int data_range_left = id2ast->children[0]->range_left; + int data_range_right = id2ast->children[0]->range_right; + std::stringstream sstr; - sstr << "$mem2bits$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++); + sstr << "$mem2bits$" << 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))); + AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); wire->str = wire_id; if (current_block) wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false); @@ -1101,7 +1158,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, AstNode *selected_case = NULL; for (size_t i = 1; i < children.size(); i++) { - log_assert(children.at(i)->type == AST_COND); + log_assert(children.at(i)->type == AST_COND || children.at(i)->type == AST_CONDX || children.at(i)->type == AST_CONDZ); AstNode *this_genblock = NULL; for (auto child : children.at(i)->children) { @@ -1316,7 +1373,7 @@ skip_dynamic_range_lvalue_expansion:; if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME) && current_block != NULL) { std::stringstream sstr; - sstr << "$assert$" << filename << ":" << linenum << "$" << (autoidx++); + sstr << "$formal$" << filename << ":" << linenum << "$" << (autoidx++); std::string id_check = sstr.str() + "_CHECK", id_en = sstr.str() + "_EN"; AstNode *wire_check = new AstNode(AST_WIRE); @@ -1328,8 +1385,10 @@ skip_dynamic_range_lvalue_expansion:; AstNode *wire_en = new AstNode(AST_WIRE); wire_en->str = id_en; current_ast_mod->children.push_back(wire_en); - 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; + if (current_always_clocked) { + 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, false)) { } @@ -1350,7 +1409,12 @@ skip_dynamic_range_lvalue_expansion:; assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_REDUCE_BOOL, children[0]->clone())); assign_check->children[0]->str = id_check; - assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1)); + if (current_always == nullptr || current_always->type != AST_INITIAL) { + assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1)); + } else { + assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_FCALL)); + assign_en->children[1]->str = "\\$initstate"; + } assign_en->children[0]->str = id_en; newNode = new AstNode(AST_BLOCK); @@ -1383,6 +1447,50 @@ skip_dynamic_range_lvalue_expansion:; goto apply_newNode; } + // assignment with nontrivial member in left-hand concat expression -> split assignment + if ((type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE) && children[0]->type == AST_CONCAT && width_hint > 0) + { + bool found_nontrivial_member = false; + + for (auto child : children[0]->children) { + if (child->type == AST_IDENTIFIER && child->id2ast != NULL && child->id2ast->type == AST_MEMORY) + found_nontrivial_member = true; + } + + if (found_nontrivial_member) + { + newNode = new AstNode(AST_BLOCK); + + AstNode *wire_tmp = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(width_hint-1, true), mkconst_int(0, true))); + wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", filename.c_str(), linenum, autoidx++); + current_ast_mod->children.push_back(wire_tmp); + current_scope[wire_tmp->str] = wire_tmp; + wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false); + while (wire_tmp->simplify(true, false, false, 1, -1, false, false)) { } + + AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER); + wire_tmp_id->str = wire_tmp->str; + + newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, wire_tmp_id, children[1]->clone())); + + int cursor = 0; + for (auto child : children[0]->children) + { + int child_width_hint = -1; + bool child_sign_hint = true; + child->detectSignWidth(child_width_hint, child_sign_hint); + + AstNode *rhs = wire_tmp_id->clone(); + rhs->children.push_back(new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+child_width_hint-1, true), AstNode::mkconst_int(cursor, true))); + newNode->children.push_back(new AstNode(type, child->clone(), rhs)); + + cursor += child_width_hint; + } + + goto apply_newNode; + } + } + // 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]->id2ast && children[0]->id2ast->type == AST_MEMORY && children[0]->id2ast->children.size() >= 2 && @@ -1404,6 +1512,15 @@ skip_dynamic_range_lvalue_expansion:; int mem_width, mem_size, addr_bits; children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits); + int data_range_left = children[0]->id2ast->children[0]->range_left; + int data_range_right = children[0]->id2ast->children[0]->range_right; + int mem_data_range_offset = std::min(data_range_left, data_range_right); + + int addr_width_hint = -1; + bool addr_sign_hint = true; + children[0]->children[0]->children[0]->detectSignWidthWorker(addr_width_hint, addr_sign_hint); + addr_bits = std::max(addr_bits, addr_width_hint); + AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); wire_addr->str = id_addr; current_ast_mod->children.push_back(wire_addr); @@ -1461,6 +1578,7 @@ skip_dynamic_range_lvalue_expansion:; { int offset = children[0]->children[1]->range_right; int width = children[0]->children[1]->range_left - offset + 1; + offset -= mem_data_range_offset; std::vector<RTLIL::State> padding_x(offset, RTLIL::State::Sx); @@ -1482,6 +1600,9 @@ skip_dynamic_range_lvalue_expansion:; 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(); + if (mem_data_range_offset) + offset_ast = new AstNode(AST_SUB, offset_ast, mkconst_int(mem_data_range_offset, true)); + 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) @@ -1545,6 +1666,153 @@ skip_dynamic_range_lvalue_expansion:; { if (type == AST_FCALL) { + if (str == "\\$initstate") + { + int myidx = autoidx++; + + AstNode *wire = new AstNode(AST_WIRE); + wire->str = stringf("$initstate$%d_wire", myidx); + current_ast_mod->children.push_back(wire); + while (wire->simplify(true, false, false, 1, -1, false, false)) { } + + AstNode *cell = new AstNode(AST_CELL, new AstNode(AST_CELLTYPE), new AstNode(AST_ARGUMENT, new AstNode(AST_IDENTIFIER))); + cell->str = stringf("$initstate$%d", myidx); + cell->children[0]->str = "$initstate"; + cell->children[1]->str = "\\Y"; + cell->children[1]->children[0]->str = wire->str; + cell->children[1]->children[0]->id2ast = wire; + current_ast_mod->children.push_back(cell); + while (cell->simplify(true, false, false, 1, -1, false, false)) { } + + newNode = new AstNode(AST_IDENTIFIER); + newNode->str = wire->str; + newNode->id2ast = wire; + goto apply_newNode; + } + + if (str == "\\$past") + { + if (width_hint <= 0) + goto replace_fcall_later; + + int num_steps = 1; + + if (GetSize(children) != 1 && GetSize(children) != 2) + log_error("System function %s got %d arguments, expected 1 or 2 at %s:%d.\n", + RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); + + if (!current_always_clocked) + log_error("System function %s is only allowed in clocked blocks at %s:%d.\n", + RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); + + if (GetSize(children) == 2) + { + AstNode *buf = children[1]->clone(); + 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); + + num_steps = buf->asInt(true); + delete buf; + } + + AstNode *block = nullptr; + + for (auto child : current_always->children) + if (child->type == AST_BLOCK) + block = child; + + log_assert(block != nullptr); + + int myidx = autoidx++; + AstNode *outreg = nullptr; + + for (int i = 0; i < num_steps; i++) + { + AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE, + mkconst_int(width_hint-1, true), mkconst_int(0, true))); + + reg->str = stringf("$past$%s:%d$%d$%d", filename.c_str(), linenum, myidx, i); + reg->is_reg = true; + + current_ast_mod->children.push_back(reg); + + while (reg->simplify(true, false, false, 1, -1, false, false)) { } + + AstNode *regid = new AstNode(AST_IDENTIFIER); + regid->str = reg->str; + regid->id2ast = reg; + + AstNode *rhs = nullptr; + + if (outreg == nullptr) { + rhs = children.at(0)->clone(); + } else { + rhs = new AstNode(AST_IDENTIFIER); + rhs->str = outreg->str; + rhs->id2ast = outreg; + } + + block->children.push_back(new AstNode(AST_ASSIGN_LE, regid, rhs)); + outreg = reg; + } + + newNode = new AstNode(AST_IDENTIFIER); + newNode->str = outreg->str; + newNode->id2ast = outreg; + goto apply_newNode; + } + + if (str == "\\$stable" || str == "\\$rose" || str == "\\$fell") + { + if (GetSize(children) != 1) + log_error("System function %s got %d arguments, expected 1 at %s:%d.\n", + RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); + + if (!current_always_clocked) + log_error("System function %s is only allowed in clocked blocks at %s:%d.\n", + RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); + + AstNode *present = children.at(0)->clone(); + AstNode *past = clone(); + past->str = "\\$past"; + + if (str == "\\$stable") + newNode = new AstNode(AST_EQ, past, present); + + else if (str == "\\$rose") + newNode = new AstNode(AST_LOGIC_AND, new AstNode(AST_LOGIC_NOT, past), present); + + else if (str == "\\$fell") + newNode = new AstNode(AST_LOGIC_AND, past, new AstNode(AST_LOGIC_NOT, present)); + + else + log_abort(); + + goto apply_newNode; + } + + if (str == "\\$rose" || str == "\\$fell") + { + if (GetSize(children) != 1) + log_error("System function %s got %d arguments, expected 1 at %s:%d.\n", + RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); + + if (!current_always_clocked) + log_error("System function %s is only allowed in clocked blocks at %s:%d.\n", + RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); + + newNode = new AstNode(AST_EQ, children.at(0)->clone(), clone()); + newNode->children.at(1)->str = "\\$past"; + goto apply_newNode; + } + + // $anyconst is mapped in AstNode::genRTLIL() + if (str == "\\$anyconst") { + recursion_counter--; + return false; + } + if (str == "\\$clog2") { if (children.size() != 1) @@ -1674,12 +1942,12 @@ skip_dynamic_range_lvalue_expansion:; if (type == AST_TCALL) { - if (str == "$finish") + if (str == "$finish" || str == "$stop") { 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 `%s' outside initial block is unsupported at %s:%d.\n", str.c_str(), filename.c_str(), linenum); - log_error("System task `$finish' executed at %s:%d.\n", filename.c_str(), linenum); + log_error("System task `%s' executed at %s:%d.\n", str.c_str(), filename.c_str(), linenum); } if (str == "\\$readmemh" || str == "\\$readmemb") @@ -1889,6 +2157,8 @@ skip_dynamic_range_lvalue_expansion:; wire->port_id = 0; wire->is_input = false; wire->is_output = false; + if (!child->is_output) + wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false); wire_cache[child->str] = wire; current_ast_mod->children.push_back(wire); @@ -1949,6 +2219,8 @@ skip_dynamic_range_lvalue_expansion:; did_something = true; } +replace_fcall_later:; + // perform const folding when activated if (const_fold) { @@ -2347,12 +2619,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)) - break; cursor += increment; + if ((cursor == finish_addr+increment) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min)) + break; } - if ((cursor == finish_addr) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min)) + if ((cursor == finish_addr+increment) || (increment > 0 && cursor > range_max) || (increment < 0 && cursor < range_min)) break; } @@ -2568,16 +2840,54 @@ bool AstNode::mem2reg_check(pool<AstNode*> &mem2reg_set) return true; } +void AstNode::mem2reg_remove(pool<AstNode*> &mem2reg_set, vector<AstNode*> &delnodes) +{ + log_assert(mem2reg_set.count(this) == 0); + + if (mem2reg_set.count(id2ast)) + id2ast = nullptr; + + for (size_t i = 0; i < children.size(); i++) { + if (mem2reg_set.count(children[i]) > 0) { + delnodes.push_back(children[i]); + children.erase(children.begin() + (i--)); + } else { + children[i]->mem2reg_remove(mem2reg_set, delnodes); + } + } +} + // actually replace memories with registers -bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block) +bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block, AstNode *&async_block) { bool did_something = false; if (type == AST_BLOCK) block = this; - if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && block != NULL && - children[0]->mem2reg_check(mem2reg_set) && children[0]->children[0]->children[0]->type != AST_CONSTANT) + if (type == AST_FUNCTION || type == AST_TASK) + return false; + + if (type == AST_ASSIGN && block == NULL && children[0]->mem2reg_check(mem2reg_set)) + { + if (async_block == NULL) { + async_block = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK)); + mod->children.push_back(async_block); + } + + AstNode *newNode = clone(); + newNode->type = AST_ASSIGN_EQ; + async_block->children[0]->children.push_back(newNode); + + newNode = new AstNode(AST_NONE); + newNode->cloneInto(this); + delete newNode; + + did_something = true; + } + + if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && children[0]->mem2reg_check(mem2reg_set) && + children[0]->children[0]->children[0]->type != AST_CONSTANT) { std::stringstream sstr; sstr << "$mem2reg_wr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++); @@ -2653,7 +2963,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, else { std::stringstream sstr; - sstr << "$mem2reg_rd$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++); + sstr << "$mem2reg_rd$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA"; int mem_width, mem_size, addr_bits; @@ -2733,7 +3043,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, auto children_list = children; for (size_t i = 0; i < children_list.size(); i++) - if (children_list[i]->mem2reg_as_needed_pass2(mem2reg_set, mod, block)) + if (children_list[i]->mem2reg_as_needed_pass2(mem2reg_set, mod, block, async_block)) did_something = true; return did_something; @@ -2958,7 +3268,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) for (size_t i = 1; i < stmt->children.size(); i++) { bool found_match = false; - log_assert(stmt->children.at(i)->type == AST_COND); + log_assert(stmt->children.at(i)->type == AST_COND || stmt->children.at(i)->type == AST_CONDX || stmt->children.at(i)->type == AST_CONDZ); if (stmt->children.at(i)->children.front()->type == AST_DEFAULT) { sel_case = stmt->children.at(i)->children.back(); |