summaryrefslogtreecommitdiff
path: root/frontends/ast
diff options
context:
space:
mode:
Diffstat (limited to 'frontends/ast')
-rw-r--r--frontends/ast/ast.cc71
-rw-r--r--frontends/ast/ast.h18
-rw-r--r--frontends/ast/genrtlil.cc105
-rw-r--r--frontends/ast/simplify.cc412
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();