mirror of https://github.com/YosysHQ/yosys.git
Implemented read_verilog -defer
This commit is contained in:
parent
b463907890
commit
cd9e8741a7
|
@ -747,14 +747,18 @@ bool AstNode::asBool()
|
|||
}
|
||||
|
||||
// create a new AstModule from an AST_MODULE AST node
|
||||
static AstModule* process_module(AstNode *ast)
|
||||
static AstModule* process_module(AstNode *ast, bool defer)
|
||||
{
|
||||
assert(ast->type == AST_MODULE);
|
||||
log("Generating RTLIL representation for module `%s'.\n", ast->str.c_str());
|
||||
|
||||
if (defer)
|
||||
log("Storing AST representation for module `%s'.\n", ast->str.c_str());
|
||||
else
|
||||
log("Generating RTLIL representation for module `%s'.\n", ast->str.c_str());
|
||||
|
||||
current_module = new AstModule;
|
||||
current_module->ast = NULL;
|
||||
current_module->name = ast->str;
|
||||
current_module->name = defer ? "$abstract" + ast->str : ast->str;
|
||||
current_module->attributes["\\src"] = stringf("%s:%d", ast->filename.c_str(), ast->linenum);
|
||||
|
||||
current_ast_mod = ast;
|
||||
|
@ -766,61 +770,64 @@ static AstModule* process_module(AstNode *ast)
|
|||
log("--- END OF AST DUMP ---\n");
|
||||
}
|
||||
|
||||
while (ast->simplify(!flag_noopt, false, false, 0, -1, false)) { }
|
||||
if (!defer)
|
||||
{
|
||||
while (ast->simplify(!flag_noopt, false, false, 0, -1, false)) { }
|
||||
|
||||
if (flag_dump_ast2) {
|
||||
log("Dumping verilog AST after simplification:\n");
|
||||
ast->dumpAst(NULL, " ");
|
||||
log("--- END OF AST DUMP ---\n");
|
||||
}
|
||||
|
||||
if (flag_dump_vlog) {
|
||||
log("Dumping verilog AST (as requested by dump_vlog option):\n");
|
||||
ast->dumpVlog(NULL, " ");
|
||||
log("--- END OF AST DUMP ---\n");
|
||||
}
|
||||
|
||||
if (flag_lib) {
|
||||
std::vector<AstNode*> new_children;
|
||||
for (auto child : ast->children) {
|
||||
if (child->type == AST_WIRE && (child->is_input || child->is_output))
|
||||
new_children.push_back(child);
|
||||
else
|
||||
delete child;
|
||||
if (flag_dump_ast2) {
|
||||
log("Dumping verilog AST after simplification:\n");
|
||||
ast->dumpAst(NULL, " ");
|
||||
log("--- END OF AST DUMP ---\n");
|
||||
}
|
||||
ast->children.swap(new_children);
|
||||
ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false);
|
||||
}
|
||||
|
||||
ignoreThisSignalsInInitial = RTLIL::SigSpec();
|
||||
if (flag_dump_vlog) {
|
||||
log("Dumping verilog AST (as requested by dump_vlog option):\n");
|
||||
ast->dumpVlog(NULL, " ");
|
||||
log("--- END OF AST DUMP ---\n");
|
||||
}
|
||||
|
||||
for (auto &attr : ast->attributes) {
|
||||
if (attr.second->type != AST_CONSTANT)
|
||||
log_error("Attribute `%s' with non-constant value at %s:%d!\n",
|
||||
attr.first.c_str(), ast->filename.c_str(), ast->linenum);
|
||||
current_module->attributes[attr.first] = attr.second->asAttrConst();
|
||||
}
|
||||
for (size_t i = 0; i < ast->children.size(); i++) {
|
||||
AstNode *node = ast->children[i];
|
||||
if (node->type == AST_WIRE || node->type == AST_MEMORY)
|
||||
node->genRTLIL();
|
||||
}
|
||||
for (size_t i = 0; i < ast->children.size(); i++) {
|
||||
AstNode *node = ast->children[i];
|
||||
if (node->type != AST_WIRE && node->type != AST_MEMORY && node->type != AST_INITIAL)
|
||||
node->genRTLIL();
|
||||
}
|
||||
if (flag_lib) {
|
||||
std::vector<AstNode*> new_children;
|
||||
for (auto child : ast->children) {
|
||||
if (child->type == AST_WIRE && (child->is_input || child->is_output))
|
||||
new_children.push_back(child);
|
||||
else
|
||||
delete child;
|
||||
}
|
||||
ast->children.swap(new_children);
|
||||
ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false);
|
||||
}
|
||||
|
||||
ignoreThisSignalsInInitial.sort_and_unify();
|
||||
ignoreThisSignalsInInitial = RTLIL::SigSpec();
|
||||
|
||||
for (size_t i = 0; i < ast->children.size(); i++) {
|
||||
AstNode *node = ast->children[i];
|
||||
if (node->type == AST_INITIAL)
|
||||
node->genRTLIL();
|
||||
for (auto &attr : ast->attributes) {
|
||||
if (attr.second->type != AST_CONSTANT)
|
||||
log_error("Attribute `%s' with non-constant value at %s:%d!\n",
|
||||
attr.first.c_str(), ast->filename.c_str(), ast->linenum);
|
||||
current_module->attributes[attr.first] = attr.second->asAttrConst();
|
||||
}
|
||||
for (size_t i = 0; i < ast->children.size(); i++) {
|
||||
AstNode *node = ast->children[i];
|
||||
if (node->type == AST_WIRE || node->type == AST_MEMORY)
|
||||
node->genRTLIL();
|
||||
}
|
||||
for (size_t i = 0; i < ast->children.size(); i++) {
|
||||
AstNode *node = ast->children[i];
|
||||
if (node->type != AST_WIRE && node->type != AST_MEMORY && node->type != AST_INITIAL)
|
||||
node->genRTLIL();
|
||||
}
|
||||
|
||||
ignoreThisSignalsInInitial.sort_and_unify();
|
||||
|
||||
for (size_t i = 0; i < ast->children.size(); i++) {
|
||||
AstNode *node = ast->children[i];
|
||||
if (node->type == AST_INITIAL)
|
||||
node->genRTLIL();
|
||||
}
|
||||
|
||||
ignoreThisSignalsInInitial = RTLIL::SigSpec();
|
||||
}
|
||||
|
||||
ignoreThisSignalsInInitial = RTLIL::SigSpec();
|
||||
|
||||
current_module->ast = ast_before_simplify;
|
||||
current_module->nolatches = flag_nolatches;
|
||||
current_module->nomem2reg = flag_nomem2reg;
|
||||
|
@ -832,7 +839,7 @@ static AstModule* process_module(AstNode *ast)
|
|||
}
|
||||
|
||||
// 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 nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef)
|
||||
void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer)
|
||||
{
|
||||
current_ast = ast;
|
||||
flag_dump_ast1 = dump_ast1;
|
||||
|
@ -847,7 +854,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
|
|||
|
||||
assert(current_ast->type == AST_DESIGN);
|
||||
for (auto it = current_ast->children.begin(); it != current_ast->children.end(); it++) {
|
||||
if (design->modules.count((*it)->str) != 0) {
|
||||
if (design->modules.count((*it)->str) != 0 && design->modules.count("$abstract" + (*it)->str) != 0) {
|
||||
if (!ignore_redef)
|
||||
log_error("Re-definition of module `%s' at %s:%d!\n",
|
||||
(*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
|
||||
|
@ -855,7 +862,10 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
|
|||
(*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
|
||||
continue;
|
||||
}
|
||||
design->modules[(*it)->str] = process_module(*it);
|
||||
if (defer)
|
||||
design->modules["$abstract" + (*it)->str] = process_module(*it, true);
|
||||
else
|
||||
design->modules[(*it)->str] = process_module(*it, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -869,7 +879,12 @@ AstModule::~AstModule()
|
|||
// create a new parametric module (when needed) and return the name of the generated module
|
||||
RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters)
|
||||
{
|
||||
log_header("Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", name.c_str());
|
||||
std::string stripped_name = name;
|
||||
|
||||
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());
|
||||
|
||||
current_ast = NULL;
|
||||
flag_dump_ast1 = false;
|
||||
|
@ -885,12 +900,13 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
|
|||
|
||||
std::string para_info;
|
||||
std::vector<unsigned char> hash_data;
|
||||
hash_data.insert(hash_data.end(), name.begin(), name.end());
|
||||
hash_data.insert(hash_data.end(), stripped_name.begin(), stripped_name.end());
|
||||
hash_data.push_back(0);
|
||||
|
||||
AstNode *new_ast = ast->clone();
|
||||
|
||||
int para_counter = 0;
|
||||
int orig_parameters_n = parameters.size();
|
||||
for (auto it = new_ast->children.begin(); it != new_ast->children.end(); it++) {
|
||||
AstNode *child = *it;
|
||||
if (child->type != AST_PARAMETER)
|
||||
|
@ -917,10 +933,15 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
|
|||
}
|
||||
}
|
||||
if (parameters.size() > 0)
|
||||
log_error("Requested parameter `%s' does not exist in module `%s'!\n", parameters.begin()->first.c_str(), name.c_str());
|
||||
log_error("Requested parameter `%s' does not exist in module `%s'!\n", parameters.begin()->first.c_str(), stripped_name.c_str());
|
||||
|
||||
std::string modname;
|
||||
|
||||
if (orig_parameters_n == 0)
|
||||
{
|
||||
modname = stripped_name;
|
||||
}
|
||||
else
|
||||
if (para_info.size() > 60)
|
||||
{
|
||||
unsigned char hash[20];
|
||||
|
@ -933,16 +954,16 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
|
|||
char hexstring[41];
|
||||
sha1::toHexString(hash, hexstring);
|
||||
|
||||
modname = "$paramod$" + std::string(hexstring) + name;
|
||||
modname = "$paramod$" + std::string(hexstring) + stripped_name;
|
||||
}
|
||||
else
|
||||
{
|
||||
modname = "$paramod" + name + para_info;
|
||||
modname = "$paramod" + stripped_name + para_info;
|
||||
}
|
||||
|
||||
if (design->modules.count(modname) == 0) {
|
||||
new_ast->str = modname;
|
||||
design->modules[modname] = process_module(new_ast);
|
||||
design->modules[modname] = process_module(new_ast, false);
|
||||
design->modules[modname]->check();
|
||||
} else {
|
||||
log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
|
||||
|
|
|
@ -232,7 +232,7 @@ 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 = false, bool dump_ast2 = false, bool dump_vlog = false, bool nolatches = false, bool nomem2reg = false, bool mem2reg = false, bool lib = false, bool noopt = false, bool icells = false, bool ignore_redef = false);
|
||||
void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1 = false, bool dump_ast2 = false, bool dump_vlog = false, bool nolatches = false, bool nomem2reg = false, bool mem2reg = false, bool lib = false, bool noopt = false, bool icells = false, bool ignore_redef = false, bool defer = true);
|
||||
|
||||
// parametric modules are supported directly by the AST library
|
||||
// therfore we need our own derivate of RTLIL::Module with overloaded virtual functions
|
||||
|
|
|
@ -106,6 +106,11 @@ struct VerilogFrontend : public Frontend {
|
|||
log(" ignore re-definitions of modules. (the default behavior is to\n");
|
||||
log(" create an error message.)\n");
|
||||
log("\n");
|
||||
log(" -defer\n");
|
||||
log(" only read the abstract syntax tree and defer actual compilation\n");
|
||||
log(" to a later 'hierarchy' command. Useful in cases where the default\n");
|
||||
log(" parameters of modules yield invalid or not synthesizable code.\n");
|
||||
log("\n");
|
||||
log(" -setattr <attribute_name>\n");
|
||||
log(" set the specified attribute (to the value 1) on all loaded modules\n");
|
||||
log("\n");
|
||||
|
@ -135,6 +140,7 @@ struct VerilogFrontend : public Frontend {
|
|||
bool flag_noopt = false;
|
||||
bool flag_icells = false;
|
||||
bool flag_ignore_redef = false;
|
||||
bool flag_defer = false;
|
||||
std::map<std::string, std::string> defines_map;
|
||||
std::list<std::string> include_dirs;
|
||||
std::list<std::string> attributes;
|
||||
|
@ -199,6 +205,10 @@ struct VerilogFrontend : public Frontend {
|
|||
flag_ignore_redef = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-defer") {
|
||||
flag_defer = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-setattr" && argidx+1 < args.size()) {
|
||||
attributes.push_back(RTLIL::escape_id(args[++argidx]));
|
||||
continue;
|
||||
|
@ -264,7 +274,7 @@ struct VerilogFrontend : public Frontend {
|
|||
child->attributes[attr] = AST::AstNode::mkconst_int(1, false);
|
||||
}
|
||||
|
||||
AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef);
|
||||
AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef, flag_defer);
|
||||
|
||||
if (!flag_nopp)
|
||||
fclose(fp);
|
||||
|
|
|
@ -145,6 +145,14 @@ static bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool fla
|
|||
|
||||
if (design->modules.count(cell->type) == 0)
|
||||
{
|
||||
if (design->modules.count("$abstract" + cell->type))
|
||||
{
|
||||
cell->type = design->modules.at("$abstract" + cell->type)->derive(design, cell->parameters);
|
||||
cell->parameters.clear();
|
||||
did_something = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cell->type[0] == '$')
|
||||
continue;
|
||||
|
||||
|
@ -210,7 +218,7 @@ static void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*> &us
|
|||
}
|
||||
}
|
||||
|
||||
static void hierarchy(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
|
||||
static void hierarchy(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib, bool first_pass)
|
||||
{
|
||||
std::set<RTLIL::Module*> used;
|
||||
hierarchy_worker(design, used, top, 0);
|
||||
|
@ -221,6 +229,8 @@ static void hierarchy(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
|
|||
del_modules.push_back(it.second);
|
||||
|
||||
for (auto mod : del_modules) {
|
||||
if (first_pass && mod->name.substr(0, 9) == "$abstract")
|
||||
continue;
|
||||
if (!purge_lib && mod->get_bool_attribute("\\blackbox"))
|
||||
continue;
|
||||
log("Removing unused module `%s'.\n", mod->name.c_str());
|
||||
|
@ -362,10 +372,12 @@ struct HierarchyPass : public Pass {
|
|||
if (args[argidx] == "-top") {
|
||||
if (++argidx >= args.size())
|
||||
log_cmd_error("Option -top requires an additional argument!\n");
|
||||
if (args[argidx][0] != '$' && args[argidx][0] != '\\')
|
||||
top_mod = design->modules.count("\\" + args[argidx]) > 0 ? design->modules["\\" + args[argidx]] : NULL;
|
||||
else
|
||||
top_mod = design->modules.count(args[argidx]) > 0 ? design->modules[args[argidx]] : NULL;
|
||||
top_mod = design->modules.count(RTLIL::escape_id(args[argidx])) ? design->modules.at(RTLIL::escape_id(args[argidx])) : NULL;
|
||||
if (top_mod == NULL && design->modules.count("$abstract" + RTLIL::escape_id(args[argidx]))) {
|
||||
std::map<RTLIL::IdString, RTLIL::Const> empty_parameters;
|
||||
design->modules.at("$abstract" + RTLIL::escape_id(args[argidx]))->derive(design, empty_parameters);
|
||||
top_mod = design->modules.count(RTLIL::escape_id(args[argidx])) ? design->modules.at(RTLIL::escape_id(args[argidx])) : NULL;
|
||||
}
|
||||
if (top_mod == NULL)
|
||||
log_cmd_error("Module `%s' not found!\n", args[argidx].c_str());
|
||||
continue;
|
||||
|
@ -387,7 +399,7 @@ struct HierarchyPass : public Pass {
|
|||
top_mod = mod_it.second;
|
||||
|
||||
if (top_mod != NULL)
|
||||
hierarchy(design, top_mod, purge_lib);
|
||||
hierarchy(design, top_mod, purge_lib, true);
|
||||
|
||||
bool did_something = true;
|
||||
bool did_something_once = false;
|
||||
|
@ -409,7 +421,7 @@ struct HierarchyPass : public Pass {
|
|||
|
||||
if (top_mod != NULL && did_something_once) {
|
||||
log_header("Re-running hierarchy analysis..\n");
|
||||
hierarchy(design, top_mod, purge_lib);
|
||||
hierarchy(design, top_mod, purge_lib, false);
|
||||
}
|
||||
|
||||
if (top_mod != NULL) {
|
||||
|
|
Loading…
Reference in New Issue