diff options
author | Udi Finkelstein <github@udifink.com> | 2018-09-18 01:27:01 +0300 |
---|---|---|
committer | Udi Finkelstein <github@udifink.com> | 2018-09-18 01:27:01 +0300 |
commit | c693f595c53e2e40840ff40b5b5ba06767582d23 (patch) | |
tree | de5e3f353f3222abca7186996e88cd9d635a964b /frontends | |
parent | f6fe73b31f6e6d8966ad4ddae860b4d79133cce2 (diff) | |
parent | 592a82c0ad8beb6de023aa2a131aab6472f949e8 (diff) | |
download | yosys-c693f595c53e2e40840ff40b5b5ba06767582d23.tar.gz yosys-c693f595c53e2e40840ff40b5b5ba06767582d23.tar.bz2 yosys-c693f595c53e2e40840ff40b5b5ba06767582d23.zip |
Merge branch 'master' into pr_reg_wire_error
Diffstat (limited to 'frontends')
-rw-r--r-- | frontends/ast/ast.cc | 44 | ||||
-rw-r--r-- | frontends/ast/ast.h | 14 | ||||
-rw-r--r-- | frontends/ast/genrtlil.cc | 189 | ||||
-rw-r--r-- | frontends/ast/simplify.cc | 244 | ||||
-rw-r--r-- | frontends/blif/blifparse.cc | 44 | ||||
-rw-r--r-- | frontends/ilang/.gitignore | 2 | ||||
-rw-r--r-- | frontends/ilang/Makefile.inc | 7 | ||||
-rw-r--r-- | frontends/ilang/ilang_frontend.cc | 4 | ||||
-rw-r--r-- | frontends/ilang/ilang_lexer.l | 2 | ||||
-rw-r--r-- | frontends/json/jsonparse.cc | 4 | ||||
-rw-r--r-- | frontends/liberty/liberty.cc | 40 | ||||
-rw-r--r-- | frontends/verific/verific.cc | 587 | ||||
-rw-r--r-- | frontends/verific/verific.h | 14 | ||||
-rw-r--r-- | frontends/verific/verificsva.cc | 365 | ||||
-rw-r--r-- | frontends/verilog/.gitignore | 2 | ||||
-rw-r--r-- | frontends/verilog/Makefile.inc | 7 | ||||
-rw-r--r-- | frontends/verilog/const2ast.cc | 8 | ||||
-rw-r--r-- | frontends/verilog/preproc.cc | 7 | ||||
-rw-r--r-- | frontends/verilog/verilog_frontend.cc | 51 | ||||
-rw-r--r-- | frontends/verilog/verilog_lexer.l | 15 | ||||
-rw-r--r-- | frontends/verilog/verilog_parser.y | 277 |
21 files changed, 1448 insertions, 479 deletions
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index b8f25e53e..e79be953a 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -44,7 +44,7 @@ namespace AST { // instanciate global variables (private API) namespace AST_INTERNAL { - bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit; + bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, 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; @@ -171,8 +171,8 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id) AstNode *attr = attributes.at(id); if (attr->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - id.c_str(), attr->filename.c_str(), attr->linenum); + log_file_error(attr->filename, attr->linenum, "Attribute `%s' with non-constant value!\n", + id.c_str()); return attr->integer != 0; } @@ -267,10 +267,12 @@ void AstNode::dumpAst(FILE *f, std::string indent) const std::string type_name = type2str(type); fprintf(f, "%s%s <%s:%d>", indent.c_str(), type_name.c_str(), filename.c_str(), linenum); - if (id2ast) - fprintf(f, " [%p -> %p]", this, id2ast); - else - fprintf(f, " [%p]", this); + if (!flag_no_dump_ptr) { + if (id2ast) + fprintf(f, " [%p -> %p]", this, id2ast); + else + fprintf(f, " [%p]", this); + } if (!str.empty()) fprintf(f, " str='%s'", str.c_str()); @@ -961,8 +963,8 @@ static AstModule* process_module(AstNode *ast, bool defer) 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); + log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", + attr.first.c_str()); current_module->attributes[attr.first] = attr.second->asAttrConst(); } for (size_t i = 0; i < ast->children.size(); i++) { @@ -1008,12 +1010,13 @@ static AstModule* process_module(AstNode *ast, bool defer) } // 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 dump_rtlil, - 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 no_dump_ptr, bool dump_vlog, bool dump_rtlil, + bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire) { current_ast = ast; flag_dump_ast1 = dump_ast1; flag_dump_ast2 = dump_ast2; + flag_no_dump_ptr = no_dump_ptr; flag_dump_vlog = dump_vlog; flag_dump_rtlil = dump_rtlil; flag_nolatches = nolatches; @@ -1048,12 +1051,20 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump (*it)->str = "$abstract" + (*it)->str; if (design->has((*it)->str)) { - if (!ignore_redef) - log_error("Re-definition of module `%s' at %s:%d!\n", + RTLIL::Module *existing_mod = design->module((*it)->str); + if (!nooverwrite && !overwrite && !existing_mod->get_bool_attribute("\\blackbox")) { + log_file_error((*it)->filename, (*it)->linenum, "Re-definition of module `%s'!\n", + (*it)->str.c_str()); + } else if (nooverwrite) { + log("Ignoring re-definition of module `%s' at %s:%d.\n", (*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum); - log("Ignoring re-definition of module `%s' at %s:%d!\n", - (*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum); - continue; + continue; + } else { + log("Replacing existing%s module `%s' at %s:%d.\n", + existing_mod->get_bool_attribute("\\blackbox") ? " blackbox" : "", + (*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum); + design->remove(existing_mod); + } } design->add(process_module(*it, defer)); @@ -1195,4 +1206,3 @@ void AST::use_internal_line_num() } YOSYS_NAMESPACE_END - diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 8a640b1cc..7e97bdb3b 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -1,4 +1,4 @@ -/* +/* -*- c++ -*- * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> @@ -274,17 +274,17 @@ 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 dump_rtlil, 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 no_dump_ptr, bool dump_vlog, bool dump_rtlil, bool nolatches, bool nomeminit, + bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, 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 struct AstModule : RTLIL::Module { AstNode *ast; bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire; - virtual ~AstModule(); - virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail); - virtual RTLIL::Module *clone() const; + ~AstModule() YS_OVERRIDE; + RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) YS_OVERRIDE; + RTLIL::Module *clone() const YS_OVERRIDE; }; // this must be set by the language frontend before parsing the sources @@ -305,7 +305,7 @@ namespace AST namespace AST_INTERNAL { // internal state variables - extern bool flag_dump_ast1, flag_dump_ast2, flag_dump_rtlil, flag_nolatches, flag_nomeminit; + extern bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, 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; diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 57ba9668d..0f7e910f3 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -55,8 +55,8 @@ static RTLIL::SigSpec uniop2rtlil(AstNode *that, std::string type, int result_wi if (gen_attributes) for (auto &attr : that->attributes) { if (attr.second->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - attr.first.c_str(), that->filename.c_str(), that->linenum); + log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", + attr.first.c_str()); cell->attributes[attr.first] = attr.second->asAttrConst(); } @@ -89,8 +89,8 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s if (that != NULL) for (auto &attr : that->attributes) { if (attr.second->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - attr.first.c_str(), that->filename.c_str(), that->linenum); + log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", + attr.first.c_str()); cell->attributes[attr.first] = attr.second->asAttrConst(); } @@ -117,8 +117,8 @@ static RTLIL::SigSpec binop2rtlil(AstNode *that, std::string type, int result_wi for (auto &attr : that->attributes) { if (attr.second->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - attr.first.c_str(), that->filename.c_str(), that->linenum); + log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", + attr.first.c_str()); cell->attributes[attr.first] = attr.second->asAttrConst(); } @@ -152,8 +152,8 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const for (auto &attr : that->attributes) { if (attr.second->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - attr.first.c_str(), that->filename.c_str(), that->linenum); + log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", + attr.first.c_str()); cell->attributes[attr.first] = attr.second->asAttrConst(); } @@ -207,8 +207,8 @@ struct AST_INTERNAL::ProcessGenerator proc->name = stringf("$proc$%s:%d$%d", always->filename.c_str(), always->linenum, autoidx++); for (auto &attr : always->attributes) { if (attr.second->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - attr.first.c_str(), always->filename.c_str(), always->linenum); + log_file_error(always->filename, always->linenum, "Attribute `%s' with non-constant value!\n", + attr.first.c_str()); proc->attributes[attr.first] = attr.second->asAttrConst(); } current_module->processes[proc->name] = proc; @@ -223,16 +223,22 @@ struct AST_INTERNAL::ProcessGenerator bool found_global_syncs = false; bool found_anyedge_syncs = false; for (auto child : always->children) + { + if ((child->type == AST_POSEDGE || child->type == AST_NEGEDGE) && GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER && + child->children.at(0)->id2ast && child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute("\\gclk")) { + found_global_syncs = true; + } if (child->type == AST_EDGE) { if (GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER && child->children.at(0)->str == "\\$global_clock") found_global_syncs = true; else found_anyedge_syncs = true; } + } if (found_anyedge_syncs) { if (found_global_syncs) - log_error("Found non-synthesizable event list at %s:%d!\n", always->filename.c_str(), always->linenum); + log_file_error(always->filename, always->linenum, "Found non-synthesizable event list!\n"); log("Note: Assuming pure combinatorial block at %s:%d in\n", always->filename.c_str(), always->linenum); log("compliance with IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002. Recommending\n"); log("use of @* instead of @(...) for better match of synthesis and simulation.\n"); @@ -242,14 +248,17 @@ struct AST_INTERNAL::ProcessGenerator bool found_clocked_sync = false; for (auto child : always->children) if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE) { + if (GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER && child->children.at(0)->id2ast && + child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute("\\gclk")) + continue; found_clocked_sync = true; if (found_global_syncs || found_anyedge_syncs) - log_error("Found non-synthesizable event list at %s:%d!\n", always->filename.c_str(), always->linenum); + log_file_error(always->filename, always->linenum, "Found non-synthesizable event list!\n"); 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); + log_file_error(always->filename, always->linenum, "Found posedge/negedge event on a signal that is not 1 bit wide!\n"); addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to, true); proc->syncs.push_back(syncrule); } @@ -471,8 +480,8 @@ struct AST_INTERNAL::ProcessGenerator 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); + log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", + attr.first.c_str()); sw->attributes[attr.first] = attr.second->asAttrConst(); } @@ -540,12 +549,12 @@ struct AST_INTERNAL::ProcessGenerator break; case AST_WIRE: - log_error("Found wire declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum); + log_file_error(ast->filename, ast->linenum, "Found wire declaration in block without label!\n"); break; case AST_PARAMETER: case AST_LOCALPARAM: - log_error("Found parameter declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum); + log_file_error(ast->filename, ast->linenum, "Found parameter declaration in block without label!\n"); break; case AST_NONE: @@ -593,7 +602,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (id_ast == NULL && current_scope.count(str)) id_ast = current_scope.at(str); if (!id_ast) - log_error("Failed to resolve identifier %s for width detection at %s:%d!\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to resolve identifier %s for width detection!\n", str.c_str()); if (id_ast->type == AST_PARAMETER || id_ast->type == AST_LOCALPARAM) { if (id_ast->children.size() > 1 && id_ast->children[1]->range_valid) { this_width = id_ast->children[1]->range_left - id_ast->children[1]->range_right + 1; @@ -603,7 +612,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (id_ast->children[0]->type == AST_CONSTANT) this_width = id_ast->children[0]->bits.size(); else - log_error("Failed to detect width for parameter %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to detect width for parameter %s!\n", str.c_str()); if (children.size() != 0) range = children[0]; } else if (id_ast->type == AST_WIRE || id_ast->type == AST_AUTOWIRE) { @@ -615,7 +624,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 width of signal access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to detect width of signal access `%s'!\n", str.c_str()); } } else { this_width = id_ast->range_left - id_ast->range_right + 1; @@ -626,10 +635,10 @@ 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 width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str()); 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); + log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str()); if (range) { if (range->children.size() == 1) this_width = 1; @@ -639,8 +648,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) - log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", + str.c_str()); this_width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1; delete left_at_zero_ast; delete right_at_zero_ast; @@ -656,7 +665,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_TO_BITS: while (children[0]->simplify(true, false, false, 1, -1, false, false) == true) { } if (children[0]->type != AST_CONSTANT) - log_error("Left operand of tobits expression is not constant at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Left operand of tobits expression is not constant!\n"); children[1]->detectSignWidthWorker(sub_width_hint, sign_hint); width_hint = max(width_hint, children[0]->bitsAsConst().as_int()); break; @@ -684,7 +693,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_REPLICATE: while (children[0]->simplify(true, false, false, 1, -1, false, true) == true) { } if (children[0]->type != AST_CONSTANT) - log_error("Left operand of replicate expression is not constant at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Left operand of replicate expression is not constant!\n"); children[1]->detectSignWidthWorker(sub_width_hint, sub_sign_hint); width_hint = max(width_hint, children[0]->bitsAsConst().as_int() * sub_width_hint); sign_hint = false; @@ -758,7 +767,7 @@ 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 width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str()); this_width = id2ast->children[0]->range_left - id2ast->children[0]->range_right + 1; width_hint = max(width_hint, this_width); break; @@ -768,8 +777,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun 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); + log_file_error(filename, linenum, "System function %s called with non-const argument!\n", + RTLIL::unescape_id(str).c_str()); width_hint = max(width_hint, int(children[0]->asInt(true))); } break; @@ -790,8 +799,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun default: for (auto f : log_files) current_ast->dumpAst(f, "verilog-ast> "); - log_error("Don't know how to detect sign and width for %s node at %s:%d!\n", - type2str(type).c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Don't know how to detect sign and width for %s node!\n", + type2str(type).c_str()); } if (*found_real) @@ -854,11 +863,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // create an RTLIL::Wire for an AST_WIRE node case AST_WIRE: { if (current_module->wires_.count(str) != 0) - log_error("Re-definition of signal `%s' at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Re-definition of signal `%s'!\n", + str.c_str()); if (!range_valid) - log_error("Signal `%s' with non-constant width at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Signal `%s' with non-constant width!\n", + str.c_str()); log_assert(range_left >= range_right || (range_left == -1 && range_right == 0)); @@ -872,8 +881,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) for (auto &attr : attributes) { if (attr.second->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - attr.first.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", + attr.first.c_str()); wire->attributes[attr.first] = attr.second->asAttrConst(); } } @@ -882,16 +891,16 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // create an RTLIL::Memory for an AST_MEMORY node case AST_MEMORY: { if (current_module->memories.count(str) != 0) - log_error("Re-definition of memory `%s' at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Re-definition of memory `%s'!\n", + str.c_str()); log_assert(children.size() >= 2); log_assert(children[0]->type == AST_RANGE); log_assert(children[1]->type == AST_RANGE); if (!children[0]->range_valid || !children[1]->range_valid) - log_error("Memory `%s' with non-constant width or size at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Memory `%s' with non-constant width or size!\n", + str.c_str()); RTLIL::Memory *memory = new RTLIL::Memory; memory->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); @@ -908,8 +917,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) for (auto &attr : attributes) { if (attr.second->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - attr.first.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", + attr.first.c_str()); memory->attributes[attr.first] = attr.second->asAttrConst(); } } @@ -928,8 +937,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) case AST_REALVALUE: { RTLIL::SigSpec sig = realAsConst(width_hint); - log_warning("converting real value %e to binary %s at %s:%d.\n", - realvalue, log_signal(sig), filename.c_str(), linenum); + log_file_warning(filename, linenum, "converting real value %e to binary %s.\n", + realvalue, log_signal(sig)); return sig; } @@ -949,25 +958,25 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); wire->name = str; if (flag_autowire) - log_warning("Identifier `%s' is implicitly declared at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_warning(filename, linenum, "Identifier `%s' is implicitly declared.\n", str.c_str()); else - log_error("Identifier `%s' is implicitly declared at %s:%d and `default_nettype is set to none.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str()); } else if (id2ast->type == AST_PARAMETER || id2ast->type == AST_LOCALPARAM) { if (id2ast->children[0]->type != AST_CONSTANT) - log_error("Parameter %s does not evaluate to constant value at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Parameter %s does not evaluate to constant value!\n", + str.c_str()); chunk = RTLIL::Const(id2ast->children[0]->bits); goto use_const_chunk; } else if (!id2ast || (id2ast->type != AST_WIRE && id2ast->type != AST_AUTOWIRE && id2ast->type != AST_MEMORY) || current_module->wires_.count(str) == 0) - log_error("Identifier `%s' doesn't map to any signal at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Identifier `%s' doesn't map to any signal!\n", + str.c_str()); if (id2ast->type == AST_MEMORY) - log_error("Identifier `%s' does map to an unexpanded memory at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Identifier `%s' does map to an unexpanded memory!\n", + str.c_str()); wire = current_module->wires_[str]; chunk.wire = wire; @@ -985,8 +994,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) - log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", + str.c_str()); int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1; AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : children[0]->children[0]->clone()); @@ -1014,11 +1023,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) chunk.offset = (id2ast->range_left - id2ast->range_right + 1) - (chunk.offset + chunk.width); if (chunk.offset >= source_width || chunk.offset + chunk.width < 0) { if (chunk.width == 1) - log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting result bit to undef.\n", - str.c_str(), filename.c_str(), linenum); + log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting result bit to undef.\n", + str.c_str()); else - log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting all %d result bits to undef.\n", - str.c_str(), filename.c_str(), linenum, chunk.width); + log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting all %d result bits to undef.\n", + str.c_str(), chunk.width); chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width); } else { if (chunk.width + chunk.offset > source_width) { @@ -1031,11 +1040,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) chunk.offset += add_undef_bits_lsb; } if (add_undef_bits_lsb) - log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting %d LSB bits to undef.\n", - str.c_str(), filename.c_str(), linenum, add_undef_bits_lsb); + log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting %d LSB bits to undef.\n", + str.c_str(), add_undef_bits_lsb); if (add_undef_bits_msb) - log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting %d MSB bits to undef.\n", - str.c_str(), filename.c_str(), linenum, add_undef_bits_msb); + log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting %d MSB bits to undef.\n", + str.c_str(), add_undef_bits_msb); } } } @@ -1074,7 +1083,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) RTLIL::SigSpec left = children[0]->genRTLIL(); RTLIL::SigSpec right = children[1]->genRTLIL(); if (!left.is_fully_const()) - log_error("Left operand of replicate expression is not constant at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Left operand of replicate expression is not constant!\n"); int count = left.as_int(); RTLIL::SigSpec sig; for (int i = 0; i < count; i++) @@ -1291,6 +1300,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0); cell->parameters["\\TRANSPARENT"] = RTLIL::Const(0); + if (!sign_hint) + is_signed = false; + return RTLIL::SigSpec(wire); } @@ -1310,7 +1322,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) int num_words = 1; if (type == AST_MEMINIT) { if (children[2]->type != AST_CONSTANT) - log_error("Memory init with non-constant word count at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Memory init with non-constant word count!\n"); num_words = int(children[2]->asInt(false)); cell->parameters["\\WORDS"] = RTLIL::Const(num_words); } @@ -1367,8 +1379,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) for (auto &attr : attributes) { if (attr.second->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - attr.first.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", + attr.first.c_str()); cell->attributes[attr.first] = attr.second->asAttrConst(); } @@ -1389,10 +1401,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) new_left.append(left[i]); new_right.append(right[i]); } - log_warning("Ignoring assignment to constant bits at %s:%d:\n" - " old assignment: %s = %s\n new assignment: %s = %s.\n", - filename.c_str(), linenum, log_signal(left), log_signal(right), - log_signal(new_left), log_signal(new_right)); + log_file_warning(filename, linenum, "Ignoring assignment to constant bits:\n" + " old assignment: %s = %s\n new assignment: %s = %s.\n", + log_signal(left), log_signal(right), + log_signal(new_left), log_signal(new_right)); left = new_left; right = new_right; } @@ -1406,8 +1418,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) int port_counter = 0, para_counter = 0; if (current_module->count_id(str) != 0) - log_error("Re-definition of cell `%s' at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Re-definition of cell `%s'!\n", str.c_str()); RTLIL::Cell *cell = current_module->addCell(str, ""); cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); @@ -1423,16 +1434,15 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (child->type == AST_PARASET) { IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str; if (child->children[0]->type == AST_REALVALUE) { - log_warning("Replacing floating point parameter %s.%s = %f with string at %s:%d.\n", - log_id(cell), log_id(paraname), child->children[0]->realvalue, - filename.c_str(), linenum); + log_file_warning(filename, linenum, "Replacing floating point parameter %s.%s = %f with string.\n", + log_id(cell), log_id(paraname), child->children[0]->realvalue); auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue)); strnode->cloneInto(child->children[0]); delete strnode; } if (child->children[0]->type != AST_CONSTANT) - log_error("Parameter %s.%s with non-constant value at %s:%d!\n", - log_id(cell), log_id(paraname), filename.c_str(), linenum); + log_file_error(filename, linenum, "Parameter %s.%s with non-constant value!\n", + log_id(cell), log_id(paraname)); cell->parameters[paraname] = child->children[0]->asParaConst(); continue; } @@ -1453,8 +1463,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) } for (auto &attr : attributes) { if (attr.second->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - attr.first.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", + attr.first.c_str()); cell->attributes[attr.first] = attr.second->asAttrConst(); } } @@ -1481,19 +1491,19 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) 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); + log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 0.\n", + RTLIL::unescape_id(str).c_str(), GetSize(children)); 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); + log_file_error(filename, linenum, "System function %s called with non-const argument!\n", + RTLIL::unescape_id(str).c_str()); 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); + log_file_error(filename, linenum, "Failed to detect width of %s!\n", + RTLIL::unescape_id(str).c_str()); Cell *cell = current_module->addCell(myid, str.substr(1)); cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); @@ -1502,7 +1512,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (attributes.count("\\reg")) { auto &attr = attributes.at("\\reg"); if (attr->type != AST_CONSTANT) - log_error("Attribute `reg' with non-constant value at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Attribute `reg' with non-constant value!\n"); cell->attributes["\\reg"] = attr->asAttrConst(); } @@ -1520,8 +1530,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) for (auto f : log_files) current_ast->dumpAst(f, "verilog-ast> "); type_name = type2str(type); - log_error("Don't know how to generate RTLIL code for %s node at %s:%d!\n", - type_name.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Don't know how to generate RTLIL code for %s node!\n", + type_name.c_str()); } return RTLIL::SigSpec(); @@ -1551,4 +1561,3 @@ RTLIL::SigSpec AstNode::genWidthRTLIL(int width, const dict<RTLIL::SigBit, RTLIL } YOSYS_NAMESPACE_END - diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index ae46e4bc9..e741bd92a 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -177,13 +177,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, // 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); + log_file_warning(filename, linenum, "Ignoring call to system %s %s.\n", type == AST_FCALL ? "function" : "task", str.c_str()); delete_children(); str = std::string(); } if ((type == AST_TCALL) && (str == "$display" || str == "$write") && (!current_always || current_always->type != AST_INITIAL)) { - log_warning("System task `%s' outside initial block is unsupported at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_warning(filename, linenum, "System task `%s' outside initial block is unsupported.\n", str.c_str()); delete_children(); str = std::string(); } @@ -195,14 +195,14 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, { 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); + log_file_error(filename, linenum, "System task `%s' got %d arguments, expected >= 1.\n", + str.c_str(), int(children.size())); // First argument is the format string 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); + log_file_error(filename, linenum, "Failed to evaluate system task `%s' with non-constant 1st argument.\n", str.c_str()); std::string sformat = node_string->bitsAsConst().decode_string(); // Other arguments are placeholders. Process the string as we go through it @@ -215,7 +215,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, { // If there's no next character, that's a problem if (i+1 >= sformat.length()) - log_error("System task `%s' called with `%%' at end of string at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "System task `%s' called with `%%' at end of string.\n", str.c_str()); char cformat = sformat[++i]; @@ -239,13 +239,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, 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); + log_file_error(filename, linenum, "Missing argument for %%%c format specifier in system task `%s'.\n", + cformat, str.c_str()); 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); + log_file_error(filename, linenum, "Failed to evaluate system task `%s' with non-constant argument.\n", str.c_str()); break; case 'm': @@ -253,7 +253,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, break; default: - log_error("System task `%s' called with invalid/unsupported format specifier at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "System task `%s' called with invalid/unsupported format specifier.\n", str.c_str()); break; } @@ -378,7 +378,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, continue; wires_are_incompatible: if (stage > 1) - log_error("Incompatible re-declaration of wire %s at %s:%d.\n", node->str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Incompatible re-declaration of wire %s.\n", node->str.c_str()); continue; } this_wire_scope[node->str] = node; @@ -406,7 +406,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (type == AST_ALWAYS || type == AST_INITIAL) { if (current_always != nullptr) - log_error("Invalid nesting of always blocks and/or initializations at %s:%d.\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Invalid nesting of always blocks and/or initializations.\n"); current_always = this; current_always_clocked = false; @@ -465,7 +465,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false, true) == true) did_something = true; if (!children[1]->range_valid) - log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Non-constant width range on parameter decl.\n"); width_hint = max(width_hint, children[1]->range_left - children[1]->range_right + 1); } break; @@ -709,7 +709,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (type == AST_DEFPARAM && !children.empty()) { if (children[0]->type != AST_IDENTIFIER) - log_error("Module name in defparam at %s:%d contains non-constant expressions!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Module name in defparam contains non-constant expressions!\n"); string modname, paramname = children[0]->str; @@ -726,13 +726,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } if (pos == std::string::npos) - log_error("Can't find object for defparam `%s` at %s:%d!\n", RTLIL::unescape_id(paramname).c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Can't find object for defparam `%s`!\n", RTLIL::unescape_id(paramname).c_str()); paramname = "\\" + paramname.substr(pos+1); if (current_scope.at(modname)->type != AST_CELL) - log_error("Defparam argument `%s . %s` does not match a cell at %s:%d!\n", - RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paramname).c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Defparam argument `%s . %s` does not match a cell!\n", + RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paramname).c_str()); AstNode *paraset = new AstNode(AST_PARASET, children[1]->clone(), GetSize(children) > 2 ? children[2]->clone() : NULL); paraset->str = paramname; @@ -746,7 +746,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (type == AST_PREFIX) { if (children[0]->type != AST_CONSTANT) { // dumpAst(NULL, "> "); - log_error("Index in generate block prefix syntax at %s:%d is not constant!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Index in generate block prefix syntax is not constant!\n"); } if (children[1]->type == AST_PREFIX) children[1]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param); @@ -762,9 +762,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, // evaluate TO_BITS nodes if (type == AST_TO_BITS) { if (children[0]->type != AST_CONSTANT) - log_error("Left operand of to_bits expression is not constant at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Left operand of to_bits expression is not constant!\n"); if (children[1]->type != AST_CONSTANT) - log_error("Right operand of to_bits expression is not constant at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Right operand of to_bits expression is not constant!\n"); RTLIL::Const new_value = children[1]->bitsAsConst(children[0]->bitsAsConst().as_int(), children[1]->is_signed); newNode = mkconst_bits(new_value.bits, children[1]->is_signed); goto apply_newNode; @@ -828,7 +828,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, multirange_dimensions.clear(); for (auto range : children[1]->children) { if (!range->range_valid) - log_error("Non-constant range on memory decl at %s:%d.\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Non-constant range on memory decl.\n"); multirange_dimensions.push_back(min(range->range_left, range->range_right)); multirange_dimensions.push_back(max(range->range_left, range->range_right) - min(range->range_left, range->range_right) + 1); total_size *= multirange_dimensions.back(); @@ -846,7 +846,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, for (int i = 0; 2*i < GetSize(id2ast->multirange_dimensions); i++) { if (GetSize(children[0]->children) < i) - log_error("Insufficient number of array indices for %s at %s:%d.\n", log_id(str), filename.c_str(), linenum); + log_file_error(filename, linenum, "Insufficient number of array indices for %s.\n", log_id(str)); AstNode *new_index_expr = children[0]->children[i]->children.at(0)->clone(); @@ -875,12 +875,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (type == AST_PARAMETER || type == AST_LOCALPARAM) { if (children.size() > 1 && children[1]->type == AST_RANGE) { if (!children[1]->range_valid) - log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Non-constant width range on parameter decl.\n"); int width = std::abs(children[1]->range_left - children[1]->range_right) + 1; if (children[0]->type == AST_REALVALUE) { RTLIL::Const constvalue = children[0]->realAsConst(width); - log_warning("converting real value %e to binary %s at %s:%d.\n", - children[0]->realvalue, log_signal(constvalue), filename.c_str(), linenum); + log_file_warning(filename, linenum, "converting real value %e to binary %s.\n", + children[0]->realvalue, log_signal(constvalue)); delete children[0]; children[0] = mkconst_bits(constvalue.bits, sign_hint); did_something = true; @@ -938,7 +938,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (type == AST_IDENTIFIER && children.size() == 2 && children[0]->type == AST_RANGE && children[1]->type == AST_RANGE && !in_lvalue) { if (id2ast == NULL || id2ast->type != AST_MEMORY || children[0]->children.size() != 1) - log_error("Invalid bit-select on memory access at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Invalid bit-select on memory access!\n"); int mem_width, mem_size, addr_bits; id2ast->meminfo(mem_width, mem_size, addr_bits); @@ -988,10 +988,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } if (type == AST_WHILE) - log_error("While loops are only allowed in constant functions at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "While loops are only allowed in constant functions!\n"); if (type == AST_REPEAT) - log_error("Repeat loops are only allowed in constant functions at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Repeat loops are only allowed in constant functions!\n"); // unroll for loops and generate-for blocks if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0) @@ -1006,31 +1006,31 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, body_ast = body_ast->children.at(0); if (init_ast->type != AST_ASSIGN_EQ) - log_error("Unsupported 1st expression of generate for-loop at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Unsupported 1st expression of generate for-loop!\n"); if (next_ast->type != AST_ASSIGN_EQ) - log_error("Unsupported 3rd expression of generate for-loop at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Unsupported 3rd expression of generate for-loop!\n"); if (type == AST_GENFOR) { if (init_ast->children[0]->id2ast == NULL || init_ast->children[0]->id2ast->type != AST_GENVAR) - log_error("Left hand side of 1st expression of generate for-loop at %s:%d is not a gen var!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Left hand side of 1st expression of generate for-loop is not a gen var!\n"); if (next_ast->children[0]->id2ast == NULL || next_ast->children[0]->id2ast->type != AST_GENVAR) - log_error("Left hand side of 3rd expression of generate for-loop at %s:%d is not a gen var!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Left hand side of 3rd expression of generate for-loop is not a gen var!\n"); } else { if (init_ast->children[0]->id2ast == NULL || init_ast->children[0]->id2ast->type != AST_WIRE) - log_error("Left hand side of 1st expression of generate for-loop at %s:%d is not a register!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Left hand side of 1st expression of generate for-loop is not a register!\n"); if (next_ast->children[0]->id2ast == NULL || next_ast->children[0]->id2ast->type != AST_WIRE) - log_error("Left hand side of 3rd expression of generate for-loop at %s:%d is not a register!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Left hand side of 3rd expression of generate for-loop is not a register!\n"); } if (init_ast->children[0]->id2ast != next_ast->children[0]->id2ast) - log_error("Incompatible left-hand sides in 1st and 3rd expression of generate for-loop at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Incompatible left-hand sides in 1st and 3rd expression of generate for-loop!\n"); // eval 1st expression AstNode *varbuf = init_ast->children[1]->clone(); while (varbuf->simplify(true, false, false, stage, 32, true, false)) { } if (varbuf->type != AST_CONSTANT) - log_error("Right hand side of 1st expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Right hand side of 1st expression of generate for-loop is not constant!\n"); varbuf = new AstNode(AST_LOCALPARAM, varbuf); varbuf->str = init_ast->children[0]->str; @@ -1052,7 +1052,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } if (buf->type != AST_CONSTANT) - log_error("2nd expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "2nd expression of generate for-loop is not constant!\n"); if (buf->integer == 0) { delete buf; @@ -1093,7 +1093,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, while (buf->simplify(true, false, false, stage, 32, true, false)) { } if (buf->type != AST_CONSTANT) - log_error("Right hand side of 3rd expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Right hand side of 3rd expression of generate for-loop is not constant!\n"); delete varbuf->children[0]; varbuf->children[0] = buf; @@ -1110,8 +1110,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, { for (size_t i = 0; i < children.size(); i++) if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM) - log_error("Local declaration in unnamed block at %s:%d is an unsupported SystemVerilog feature!\n", - children[i]->filename.c_str(), children[i]->linenum); + log_file_error(children[i]->filename, children[i]->linenum, "Local declaration in unnamed block is an unsupported SystemVerilog feature!\n"); } // transform block with name @@ -1159,7 +1158,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (buf->type != AST_CONSTANT) { // for (auto f : log_files) // dumpAst(f, "verilog-ast> "); - log_error("Condition for generate if at %s:%d is not constant!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Condition for generate if is not constant!\n"); } if (buf->asBool() != 0) { delete buf; @@ -1200,7 +1199,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (buf->type != AST_CONSTANT) { // for (auto f : log_files) // dumpAst(f, "verilog-ast> "); - log_error("Condition for generate case at %s:%d is not constant!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Condition for generate case is not constant!\n"); } bool ref_signed = buf->is_signed; @@ -1234,7 +1233,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (buf->type != AST_CONSTANT) { // for (auto f : log_files) // dumpAst(f, "verilog-ast> "); - log_error("Expression in generate case at %s:%d is not constant!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Expression in generate case is not constant!\n"); } bool is_selected = RTLIL::const_eq(ref_value, buf->bitsAsConst(), ref_signed && buf->is_signed, ref_signed && buf->is_signed, 1).as_bool(); @@ -1275,7 +1274,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (type == AST_CELLARRAY) { if (!children.at(0)->range_valid) - log_error("Non-constant array range on cell array at %s:%d.\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Non-constant array range on cell array.\n"); newNode = new AstNode(AST_GENBLOCK); int num = max(children.at(0)->range_left, children.at(0)->range_right) - min(children.at(0)->range_left, children.at(0)->range_right) + 1; @@ -1286,7 +1285,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, newNode->children.push_back(new_cell); new_cell->str += stringf("[%d]", idx); if (new_cell->type == AST_PRIMITIVE) { - log_error("Cell arrays of primitives are currently not supported at %s:%d.\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Cell arrays of primitives are currently not supported.\n"); } else { log_assert(new_cell->children.at(0)->type == AST_CELLTYPE); new_cell->children.at(0)->str = stringf("$array:%d:%d:%s", i, num, new_cell->children.at(0)->str.c_str()); @@ -1300,8 +1299,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (type == AST_PRIMITIVE) { if (children.size() < 2) - log_error("Insufficient number of arguments for primitive `%s' at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Insufficient number of arguments for primitive `%s'!\n", + str.c_str()); std::vector<AstNode*> children_list; for (auto child : children) { @@ -1316,8 +1315,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (str == "bufif0" || str == "bufif1" || str == "notif0" || str == "notif1") { if (children_list.size() != 3) - log_error("Invalid number of arguments for primitive `%s' at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Invalid number of arguments for primitive `%s'!\n", + str.c_str()); std::vector<RTLIL::State> z_const(1, RTLIL::State::Sz); @@ -1404,8 +1403,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, while (left_at_zero_ast->simplify(true, true, false, stage, -1, false, false)) { } while (right_at_zero_ast->simplify(true, true, false, stage, -1, false, false)) { } if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) - log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", + str.c_str()); result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; } did_something = true; @@ -1679,7 +1678,7 @@ skip_dynamic_range_lvalue_expansion:; while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) - log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1; assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), @@ -1775,19 +1774,19 @@ skip_dynamic_range_lvalue_expansion:; 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); + log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 2.\n", + RTLIL::unescape_id(str).c_str(), int(children.size())); 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); + log_file_error(filename, linenum, "System function %s is only allowed in clocked blocks.\n", + RTLIL::unescape_id(str).c_str()); 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); + log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant value.\n", str.c_str()); num_steps = buf->asInt(true); delete buf; @@ -1844,12 +1843,12 @@ skip_dynamic_range_lvalue_expansion:; 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); + log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n", + RTLIL::unescape_id(str).c_str(), int(children.size())); 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); + log_file_error(filename, linenum, "System function %s is only allowed in clocked blocks.\n", + RTLIL::unescape_id(str).c_str()); AstNode *present = children.at(0)->clone(); AstNode *past = clone(); @@ -1879,13 +1878,13 @@ skip_dynamic_range_lvalue_expansion:; if (str == "\\$clog2") { if (children.size() != 1) - log_error("System function %s got %d arguments, expected 1 at %s:%d.\n", - RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); + log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n", + RTLIL::unescape_id(str).c_str(), int(children.size())); AstNode *buf = children[0]->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); + log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant value.\n", str.c_str()); RTLIL::Const arg_value = buf->bitsAsConst(); if (arg_value.as_bool()) @@ -1904,12 +1903,12 @@ skip_dynamic_range_lvalue_expansion:; if (str == "\\$size" || str == "\\$bits") { if (str == "\\$bits" && children.size() != 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); + log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n", + RTLIL::unescape_id(str).c_str(), int(children.size())); if (str == "\\$size" && children.size() != 1 && children.size() != 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); + log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 2.\n", + RTLIL::unescape_id(str).c_str(), int(children.size())); int dim = 1; if (str == "\\$size" && children.size() == 2) { @@ -1932,7 +1931,7 @@ skip_dynamic_range_lvalue_expansion:; if (id_ast == NULL && current_scope.count(buf->str)) id_ast = current_scope.at(buf->str); if (!id_ast) - log_error("Failed to resolve identifier %s for width detection at %s:%d!\n", buf->str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to resolve identifier %s for width detection!\n", buf->str.c_str()); if (id_ast->type == AST_MEMORY) { // We got here only if the argument is a memory // Otherwise $size() and $bits() return the expression width @@ -1940,15 +1939,15 @@ skip_dynamic_range_lvalue_expansion:; if (str == "\\$bits") { if (mem_range->type == AST_RANGE) { if (!mem_range->range_valid) - log_error("Failed to detect width of memory access `%s' at %s:%d!\n", buf->str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", buf->str.c_str()); mem_depth = mem_range->range_left - mem_range->range_right + 1; } else - log_error("Unknown memory depth AST type in `%s' at %s:%d!\n", buf->str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Unknown memory depth AST type in `%s'!\n", buf->str.c_str()); } else { // $size() if (mem_range->type == AST_RANGE) { if (!mem_range->range_valid) - log_error("Failed to detect width of memory access `%s' at %s:%d!\n", buf->str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", buf->str.c_str()); int dims; if (id_ast->multirange_dimensions.empty()) dims = 1; @@ -1959,9 +1958,9 @@ skip_dynamic_range_lvalue_expansion:; else if (dim <= dims) { width_hint = id_ast->multirange_dimensions[2*dim-1]; } else if ((dim > dims+1) || (dim < 0)) - log_error("Dimension %d out of range in `%s', as it only has dimensions 1..%d at %s:%d!\n", dim, buf->str.c_str(), dims+1, filename.c_str(), linenum); + log_file_error(filename, linenum, "Dimension %d out of range in `%s', as it only has dimensions 1..%d!\n", dim, buf->str.c_str(), dims+1); } else - log_error("Unknown memory depth AST type in `%s' at %s:%d!\n", buf->str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Unknown memory depth AST type in `%s'!\n", buf->str.c_str()); } } } @@ -1982,19 +1981,19 @@ skip_dynamic_range_lvalue_expansion:; if (func_with_two_arguments) { if (children.size() != 2) - log_error("System function %s got %d arguments, expected 2 at %s:%d.\n", - RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); + log_file_error(filename, linenum, "System function %s got %d arguments, expected 2.\n", + RTLIL::unescape_id(str).c_str(), int(children.size())); } else { if (children.size() != 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); + log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n", + RTLIL::unescape_id(str).c_str(), int(children.size())); } if (children.size() >= 1) { while (children[0]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } if (!children[0]->isConst()) - log_error("Failed to evaluate system function `%s' with non-constant argument at %s:%d.\n", - RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant argument.\n", + RTLIL::unescape_id(str).c_str()); int child_width_hint = width_hint; bool child_sign_hint = sign_hint; children[0]->detectSignWidth(child_width_hint, child_sign_hint); @@ -2004,8 +2003,8 @@ skip_dynamic_range_lvalue_expansion:; if (children.size() >= 2) { while (children[1]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } if (!children[1]->isConst()) - log_error("Failed to evaluate system function `%s' with non-constant argument at %s:%d.\n", - RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant argument.\n", + RTLIL::unescape_id(str).c_str()); int child_width_hint = width_hint; bool child_sign_hint = sign_hint; children[1]->detectSignWidth(child_width_hint, child_sign_hint); @@ -2057,14 +2056,14 @@ skip_dynamic_range_lvalue_expansion:; for (int i = 2; i < GetSize(dpi_decl->children); i++) { if (i-2 >= GetSize(children)) - log_error("Insufficient number of arguments in DPI function call at %s:%d.\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Insufficient number of arguments in DPI function call.\n"); argtypes.push_back(RTLIL::unescape_id(dpi_decl->children.at(i)->str)); args.push_back(children.at(i-2)->clone()); while (args.back()->simplify(true, false, false, stage, -1, false, true)) { } if (args.back()->type != AST_CONSTANT && args.back()->type != AST_REALVALUE) - log_error("Failed to evaluate DPI function with non-constant argument at %s:%d.\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to evaluate DPI function with non-constant argument.\n"); } newNode = dpi_call(rtype, fname, argtypes, args); @@ -2076,7 +2075,7 @@ skip_dynamic_range_lvalue_expansion:; } if (current_scope.count(str) == 0 || current_scope[str]->type != AST_FUNCTION) - log_error("Can't resolve function name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Can't resolve function name `%s'.\n", str.c_str()); } if (type == AST_TCALL) @@ -2084,26 +2083,26 @@ skip_dynamic_range_lvalue_expansion:; if (str == "$finish" || str == "$stop") { if (!current_always || current_always->type != AST_INITIAL) - log_error("System task `%s' outside initial block is unsupported at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "System task `%s' outside initial block is unsupported.\n", str.c_str()); - log_error("System task `%s' executed at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "System task `%s' executed.\n", str.c_str()); } if (str == "\\$readmemh" || str == "\\$readmemb") { if (GetSize(children) < 2 || GetSize(children) > 4) - log_error("System function %s got %d arguments, expected 2-4 at %s:%d.\n", - RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); + log_file_error(filename, linenum, "System function %s got %d arguments, expected 2-4.\n", + RTLIL::unescape_id(str).c_str(), int(children.size())); AstNode *node_filename = children[0]->clone(); while (node_filename->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } if (node_filename->type != AST_CONSTANT) - log_error("Failed to evaluate system function `%s' with non-constant 1st argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 1st argument.\n", str.c_str()); AstNode *node_memory = children[1]->clone(); while (node_memory->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } if (node_memory->type != AST_IDENTIFIER || node_memory->id2ast == nullptr || node_memory->id2ast->type != AST_MEMORY) - log_error("Failed to evaluate system function `%s' with non-memory 2nd argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-memory 2nd argument.\n", str.c_str()); int start_addr = -1, finish_addr = -1; @@ -2111,7 +2110,7 @@ skip_dynamic_range_lvalue_expansion:; AstNode *node_addr = children[2]->clone(); while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } if (node_addr->type != AST_CONSTANT) - log_error("Failed to evaluate system function `%s' with non-constant 3rd argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 3rd argument.\n", str.c_str()); start_addr = int(node_addr->asInt(false)); } @@ -2119,7 +2118,7 @@ skip_dynamic_range_lvalue_expansion:; AstNode *node_addr = children[3]->clone(); while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } if (node_addr->type != AST_CONSTANT) - log_error("Failed to evaluate system function `%s' with non-constant 4th argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 4th argument.\n", str.c_str()); finish_addr = int(node_addr->asInt(false)); } @@ -2145,7 +2144,7 @@ skip_dynamic_range_lvalue_expansion:; } if (current_scope.count(str) == 0 || current_scope[str]->type != AST_TASK) - log_error("Can't resolve task name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Can't resolve task name `%s'.\n", str.c_str()); } AstNode *decl = current_scope[str]; @@ -2173,9 +2172,9 @@ skip_dynamic_range_lvalue_expansion:; } if (in_param) - log_error("Non-constant function call in constant expression at %s:%d.\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Non-constant function call in constant expression.\n"); if (require_const_eval) - log_error("Function %s can only be called with constant arguments at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Function %s can only be called with constant arguments.\n", str.c_str()); } size_t arg_count = 0; @@ -2295,7 +2294,7 @@ skip_dynamic_range_lvalue_expansion:; goto tcall_incompatible_wires; } else { tcall_incompatible_wires: - log_error("Incompatible re-declaration of wire %s at %s:%d.\n", child->str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Incompatible re-declaration of wire %s.\n", child->str.c_str()); } } } @@ -2684,7 +2683,7 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m yosys_input_files.insert(mem_filename); if (f.fail()) - log_error("Can not open file `%s` for %s at %s:%d.\n", mem_filename.c_str(), str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Can not open file `%s` for %s.\n", mem_filename.c_str(), str.c_str()); log_assert(GetSize(memory->children) == 2 && memory->children[1]->type == AST_RANGE && memory->children[1]->range_valid); int range_left = memory->children[1]->range_left, range_right = memory->children[1]->range_right; @@ -2730,7 +2729,7 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m char *endptr; cursor = strtol(nptr, &endptr, 16); if (!*nptr || *endptr) - log_error("Can not parse address `%s` for %s at %s:%d.\n", nptr, str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Can not parse address `%s` for %s.\n", nptr, str.c_str()); continue; } @@ -2987,7 +2986,7 @@ bool AstNode::mem2reg_check(pool<AstNode*> &mem2reg_set) return false; if (children.empty() || children[0]->type != AST_RANGE || GetSize(children[0]->children) != 1) - log_error("Invalid array access at %s:%d.\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Invalid array access.\n"); return true; } @@ -3256,13 +3255,13 @@ void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &varia int offset = variables.at(str).offset, width = variables.at(str).val.bits.size(); if (!children.empty()) { if (children.size() != 1 || children.at(0)->type != AST_RANGE) - log_error("Memory access in constant function is not supported in %s:%d (called from %s:%d).\n", - filename.c_str(), linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(filename, linenum, "Memory access in constant function is not supported\n%s:%d: ...called from here.\n", + fcall->filename.c_str(), fcall->linenum); children.at(0)->replace_variables(variables, fcall); while (simplify(true, false, false, 1, -1, false, true)) { } if (!children.at(0)->range_valid) - log_error("Non-constant range in %s:%d (called from %s:%d).\n", - filename.c_str(), linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(filename, linenum, "Non-constant range\n%s:%d: ... called from here.\n", + fcall->filename.c_str(), fcall->linenum); offset = min(children.at(0)->range_left, children.at(0)->range_right); width = min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width); } @@ -3301,8 +3300,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) { while (child->simplify(true, false, false, 1, -1, false, true)) { } if (!child->range_valid) - log_error("Can't determine size of variable %s in %s:%d (called from %s:%d).\n", - child->str.c_str(), child->filename.c_str(), child->linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(child->filename, child->linenum, "Can't determine size of variable %s\n%s:%d: ... called from here.\n", + child->str.c_str(), fcall->filename.c_str(), fcall->linenum); variables[child->str].val = RTLIL::Const(RTLIL::State::Sx, abs(child->range_left - child->range_right)+1); variables[child->str].offset = min(child->range_left, child->range_right); variables[child->str].is_signed = child->is_signed; @@ -3345,24 +3344,24 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) continue; if (stmt->children.at(1)->type != AST_CONSTANT) - log_error("Non-constant expression in constant function at %s:%d (called from %s:%d). X\n", - stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here. X\n", + fcall->filename.c_str(), fcall->linenum); if (stmt->children.at(0)->type != AST_IDENTIFIER) - log_error("Unsupported composite left hand side in constant function at %s:%d (called from %s:%d).\n", - stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(stmt->filename, stmt->linenum, "Unsupported composite left hand side in constant function\n%s:%d: ... called from here.\n", + fcall->filename.c_str(), fcall->linenum); if (!variables.count(stmt->children.at(0)->str)) - log_error("Assignment to non-local variable in constant function at %s:%d (called from %s:%d).\n", - stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(stmt->filename, stmt->linenum, "Assignment to non-local variable in constant function\n%s:%d: ... called from here.\n", + fcall->filename.c_str(), fcall->linenum); if (stmt->children.at(0)->children.empty()) { variables[stmt->children.at(0)->str].val = stmt->children.at(1)->bitsAsConst(variables[stmt->children.at(0)->str].val.bits.size()); } else { AstNode *range = stmt->children.at(0)->children.at(0); if (!range->range_valid) - log_error("Non-constant range in %s:%d (called from %s:%d).\n", - range->filename.c_str(), range->linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(range->filename, range->linenum, "Non-constant range\n%s:%d: ... called from here.\n", + fcall->filename.c_str(), fcall->linenum); int offset = min(range->range_left, range->range_right); int width = std::abs(range->range_left - range->range_right) + 1; varinfo_t &v = variables[stmt->children.at(0)->str]; @@ -3393,8 +3392,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) while (cond->simplify(true, false, false, 1, -1, false, true)) { } if (cond->type != AST_CONSTANT) - log_error("Non-constant expression in constant function at %s:%d (called from %s:%d).\n", - stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here.\n", + fcall->filename.c_str(), fcall->linenum); if (cond->asBool()) { block->children.insert(block->children.begin(), stmt->children.at(1)->clone()); @@ -3414,8 +3413,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) while (num->simplify(true, false, false, 1, -1, false, true)) { } if (num->type != AST_CONSTANT) - log_error("Non-constant expression in constant function at %s:%d (called from %s:%d).\n", - stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here.\n", + fcall->filename.c_str(), fcall->linenum); block->children.erase(block->children.begin()); for (int i = 0; i < num->bitsAsConst().as_int(); i++) @@ -3452,8 +3451,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) while (cond->simplify(true, false, false, 1, -1, false, true)) { } if (cond->type != AST_CONSTANT) - log_error("Non-constant expression in constant function at %s:%d (called from %s:%d).\n", - stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here.\n", + fcall->filename.c_str(), fcall->linenum); found_match = cond->asBool(); delete cond; @@ -3482,8 +3481,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) continue; } - log_error("Unsupported language construct in constant function at %s:%d (called from %s:%d).\n", - stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(stmt->filename, stmt->linenum, "Unsupported language construct in constant function\n%s:%d: ... called from here.\n", + fcall->filename.c_str(), fcall->linenum); log_abort(); } @@ -3500,4 +3499,3 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) } YOSYS_NAMESPACE_END - diff --git a/frontends/blif/blifparse.cc b/frontends/blif/blifparse.cc index e6bb99954..034b3e70c 100644 --- a/frontends/blif/blifparse.cc +++ b/frontends/blif/blifparse.cc @@ -83,7 +83,9 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo RTLIL::Module *module = nullptr; RTLIL::Const *lutptr = NULL; RTLIL::Cell *sopcell = NULL; + RTLIL::Cell *lastcell = nullptr; RTLIL::State lut_default_state = RTLIL::State::Sx; + std::string err_reason; int blif_maxnum = 0, sopmode = -1; auto blif_wire = [&](const std::string &wire_name) -> Wire* @@ -159,6 +161,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo if (module != nullptr) goto error; module = new RTLIL::Module; + lastcell = nullptr; module->name = RTLIL::escape_id(strtok(NULL, " \t\r\n")); obj_attributes = &module->attributes; obj_parameters = nullptr; @@ -232,6 +235,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo } module = nullptr; + lastcell = nullptr; obj_attributes = nullptr; obj_parameters = nullptr; continue; @@ -264,6 +268,22 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo continue; } + if (!strcmp(cmd, ".cname")) + { + char *p = strtok(NULL, " \t\r\n"); + if (p == NULL) + goto error; + + if(lastcell == nullptr || module == nullptr) + { + err_reason = stringf("No primative object to attach .cname %s.", p); + goto error_with_reason; + } + + module->rename(lastcell, p); + continue; + } + if (!strcmp(cmd, ".attr") || !strcmp(cmd, ".param")) { char *n = strtok(NULL, " \t\r\n"); char *v = strtok(NULL, "\r\n"); @@ -281,12 +301,16 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo const_v.bits[i] = v[n-i-1] != '0' ? State::S1 : State::S0; } if (!strcmp(cmd, ".attr")) { - if (obj_attributes == nullptr) - goto error; + if (obj_attributes == nullptr) { + err_reason = stringf("No object to attach .attr too."); + goto error_with_reason; + } (*obj_attributes)[id_n] = const_v; } else { - if (obj_parameters == nullptr) - goto error; + if (obj_parameters == nullptr) { + err_reason = stringf("No object to attach .param too."); + goto error_with_reason; + } (*obj_parameters)[id_n] = const_v; } continue; @@ -331,6 +355,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo } } + lastcell = cell; obj_attributes = &cell->attributes; obj_parameters = &cell->parameters; continue; @@ -383,6 +408,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo cell->setPort(it.first, sig); } + lastcell = cell; obj_attributes = &cell->attributes; obj_parameters = &cell->parameters; continue; @@ -391,7 +417,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo obj_attributes = nullptr; obj_parameters = nullptr; - if (!strcmp(cmd, ".barbuf")) + if (!strcmp(cmd, ".barbuf") || !strcmp(cmd, ".conn")) { char *p = strtok(NULL, " \t\r\n"); if (p == NULL) @@ -459,6 +485,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo sopcell->setPort("\\A", input_sig); sopcell->setPort("\\Y", output_sig); sopmode = -1; + lastcell = sopcell; } else { @@ -469,6 +496,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo cell->setPort("\\Y", output_sig); lutptr = &cell->parameters.at("\\LUT"); lut_default_state = RTLIL::State::Sx; + lastcell = cell; } continue; } @@ -546,11 +574,13 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo error: log_error("Syntax error in line %d!\n", line_count); +error_with_reason: + log_error("Syntax error in line %d: %s\n", line_count, err_reason.c_str()); } struct BlifFrontend : public Frontend { BlifFrontend() : Frontend("blif", "read BLIF file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -566,7 +596,7 @@ struct BlifFrontend : public Frontend { log(" multi-bit port 'name'.\n"); log("\n"); } - virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool sop_mode = false; bool wideports = false; diff --git a/frontends/ilang/.gitignore b/frontends/ilang/.gitignore index 43106a814..f586b33c7 100644 --- a/frontends/ilang/.gitignore +++ b/frontends/ilang/.gitignore @@ -1,4 +1,4 @@ ilang_lexer.cc ilang_parser.output ilang_parser.tab.cc -ilang_parser.tab.h +ilang_parser.tab.hh diff --git a/frontends/ilang/Makefile.inc b/frontends/ilang/Makefile.inc index e2a476c93..6f1f0e8fc 100644 --- a/frontends/ilang/Makefile.inc +++ b/frontends/ilang/Makefile.inc @@ -1,15 +1,14 @@ GENFILES += frontends/ilang/ilang_parser.tab.cc -GENFILES += frontends/ilang/ilang_parser.tab.h +GENFILES += frontends/ilang/ilang_parser.tab.hh GENFILES += frontends/ilang/ilang_parser.output GENFILES += frontends/ilang/ilang_lexer.cc frontends/ilang/ilang_parser.tab.cc: frontends/ilang/ilang_parser.y $(Q) mkdir -p $(dir $@) - $(P) $(BISON) -d -r all -b frontends/ilang/ilang_parser $< - $(Q) mv frontends/ilang/ilang_parser.tab.c frontends/ilang/ilang_parser.tab.cc + $(P) $(BISON) -o $@ -d -r all -b frontends/ilang/ilang_parser $< -frontends/ilang/ilang_parser.tab.h: frontends/ilang/ilang_parser.tab.cc +frontends/ilang/ilang_parser.tab.hh: frontends/ilang/ilang_parser.tab.cc frontends/ilang/ilang_lexer.cc: frontends/ilang/ilang_lexer.l $(Q) mkdir -p $(dir $@) diff --git a/frontends/ilang/ilang_frontend.cc b/frontends/ilang/ilang_frontend.cc index ed6789987..d8783ac1d 100644 --- a/frontends/ilang/ilang_frontend.cc +++ b/frontends/ilang/ilang_frontend.cc @@ -35,7 +35,7 @@ YOSYS_NAMESPACE_BEGIN struct IlangFrontend : public Frontend { IlangFrontend() : Frontend("ilang", "read modules from ilang file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -45,7 +45,7 @@ struct IlangFrontend : public Frontend { log("representation of a design in yosys's internal format.)\n"); log("\n"); } - virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing ILANG frontend.\n"); extra_args(f, filename, args, 1); diff --git a/frontends/ilang/ilang_lexer.l b/frontends/ilang/ilang_lexer.l index 842388548..d8e01ae4d 100644 --- a/frontends/ilang/ilang_lexer.l +++ b/frontends/ilang/ilang_lexer.l @@ -30,7 +30,7 @@ #endif #include "frontends/ilang/ilang_frontend.h" -#include "ilang_parser.tab.h" +#include "ilang_parser.tab.hh" USING_YOSYS_NAMESPACE diff --git a/frontends/json/jsonparse.cc b/frontends/json/jsonparse.cc index 629578c61..82361ea9b 100644 --- a/frontends/json/jsonparse.cc +++ b/frontends/json/jsonparse.cc @@ -494,7 +494,7 @@ void json_import(Design *design, string &modname, JsonNode *node) struct JsonFrontend : public Frontend { JsonFrontend() : Frontend("json", "read JSON file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -504,7 +504,7 @@ struct JsonFrontend : public Frontend { log("for a description of the file format.\n"); log("\n"); } - virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing JSON frontend.\n"); diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc index af80c2921..0a5bd84de 100644 --- a/frontends/liberty/liberty.cc +++ b/frontends/liberty/liberty.cc @@ -148,7 +148,7 @@ static bool parse_func_reduce(RTLIL::Module *module, std::vector<token_t> &stack } if (0 <= top && stack[top].type == 2) { - if (next_token.type == '*' || next_token.type == '&' || next_token.type == 0 || next_token.type == '(') + if (next_token.type == '*' || next_token.type == '&' || next_token.type == 0 || next_token.type == '(' || next_token.type == '!') return false; stack[top].type = 3; return true; @@ -188,7 +188,7 @@ static RTLIL::SigSpec parse_func_expr(RTLIL::Module *module, const char *expr) } token_t next_token(0); - if (*expr == '(' || *expr == ')' || *expr == '\'' || *expr == '!' || *expr == '^' || *expr == '*' || *expr == '+' || *expr == '|') + if (*expr == '(' || *expr == ')' || *expr == '\'' || *expr == '!' || *expr == '^' || *expr == '*' || *expr == '+' || *expr == '|' || *expr == '&') next_token = token_t(*(expr++)); else next_token = token_t(0, parse_func_identifier(module, expr)); @@ -452,7 +452,7 @@ void parse_type_map(std::map<std::string, std::tuple<int, int, bool>> &type_map, struct LibertyFrontend : public Frontend { LibertyFrontend() : Frontend("liberty", "read cells from liberty file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -463,9 +463,13 @@ struct LibertyFrontend : public Frontend { log(" -lib\n"); log(" only create empty blackbox modules\n"); log("\n"); - log(" -ignore_redef\n"); + log(" -nooverwrite\n"); log(" ignore re-definitions of modules. (the default behavior is to\n"); - log(" create an error message.)\n"); + log(" create an error message if the existing module is not a blackbox\n"); + log(" module, and overwrite the existing module if it is a blackbox module.)\n"); + log("\n"); + log(" -overwrite\n"); + log(" overwrite existing modules with the same name\n"); log("\n"); log(" -ignore_miss_func\n"); log(" ignore cells with missing function specification of outputs\n"); @@ -481,10 +485,11 @@ struct LibertyFrontend : public Frontend { log(" set the specified attribute (to the value 1) on all loaded modules\n"); log("\n"); } - virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool flag_lib = false; - bool flag_ignore_redef = false; + bool flag_nooverwrite = false; + bool flag_overwrite = false; bool flag_ignore_miss_func = false; bool flag_ignore_miss_dir = false; bool flag_ignore_miss_data_latch = false; @@ -499,8 +504,14 @@ struct LibertyFrontend : public Frontend { flag_lib = true; continue; } - if (arg == "-ignore_redef") { - flag_ignore_redef = true; + if (arg == "-ignore_redef" || arg == "-nooverwrite") { + flag_nooverwrite = true; + flag_overwrite = false; + continue; + } + if (arg == "-overwrite") { + flag_nooverwrite = false; + flag_overwrite = true; continue; } if (arg == "-ignore_miss_func") { @@ -537,9 +548,16 @@ struct LibertyFrontend : public Frontend { std::string cell_name = RTLIL::escape_id(cell->args.at(0)); if (design->has(cell_name)) { - if (flag_ignore_redef) + Module *existing_mod = design->module(cell_name); + if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) { + log_error("Re-definition of of cell/module %s!\n", log_id(cell_name)); + } else if (flag_nooverwrite) { + log("Ignoring re-definition of module %s.\n", log_id(cell_name)); continue; - log_error("Duplicate definition of cell/module %s.\n", RTLIL::unescape_id(cell_name).c_str()); + } else { + log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute("\\blackbox") ? " blackbox" : "", log_id(cell_name)); + design->remove(existing_mod); + } } // log("Processing cell type %s.\n", RTLIL::unescape_id(cell_name).c_str()); diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 7b5dac309..c5fa58313 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -62,7 +62,11 @@ using namespace Verific; YOSYS_NAMESPACE_BEGIN int verific_verbose; +bool verific_import_pending; string verific_error_msg; +int verific_sva_fsm_limit; + +vector<string> verific_incdirs, verific_libdirs; void msg_func(msg_type_t msg_type, const char *message_id, linefile_type linefile, const char *msg, va_list args) { @@ -99,9 +103,9 @@ string get_full_netlist_name(Netlist *nl) // ================================================================== -VerificImporter::VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific) : +VerificImporter::VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific, bool mode_autocover) : mode_gates(mode_gates), mode_keep(mode_keep), mode_nosva(mode_nosva), - mode_names(mode_names), mode_verific(mode_verific) + mode_names(mode_names), mode_verific(mode_verific), mode_autocover(mode_autocover) { } @@ -123,8 +127,11 @@ void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &att attributes["\\src"] = stringf("%s:%d", LineFile::GetFileName(obj->Linefile()), LineFile::GetLineNo(obj->Linefile())); // FIXME: Parse numeric attributes - FOREACH_ATTRIBUTE(obj, mi, attr) + FOREACH_ATTRIBUTE(obj, mi, attr) { + if (attr->Key()[0] == ' ' || attr->Value() == nullptr) + continue; attributes[RTLIL::escape_id(attr->Key())] = RTLIL::Const(std::string(attr->Value())); + } } RTLIL::SigSpec VerificImporter::operatorInput(Instance *inst) @@ -186,12 +193,12 @@ RTLIL::SigSpec VerificImporter::operatorInport(Instance *inst, const char *portn } } -RTLIL::SigSpec VerificImporter::operatorOutput(Instance *inst) +RTLIL::SigSpec VerificImporter::operatorOutput(Instance *inst, const pool<Net*, hash_ptr_ops> *any_all_nets) { RTLIL::SigSpec sig; RTLIL::Wire *dummy_wire = NULL; for (int i = int(inst->OutputSize())-1; i >= 0; i--) - if (inst->GetOutputBit(i)) { + if (inst->GetOutputBit(i) && (!any_all_nets || !any_all_nets->count(inst->GetOutputBit(i)))) { sig.append(net_map_at(inst->GetOutputBit(i))); dummy_wire = NULL; } else { @@ -241,7 +248,9 @@ bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdStr } if (inst->Type() == PRIM_BUF) { - module->addBufGate(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + auto outnet = inst->GetOutput(); + if (!any_all_nets.count(outnet)) + module->addBufGate(inst_name, net_map_at(inst->GetInput()), net_map_at(outnet)); return true; } @@ -391,6 +400,7 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr #define IN1 operatorInput1(inst) #define IN2 operatorInput2(inst) #define OUT operatorOutput(inst) + #define FILTERED_OUT operatorOutput(inst, &any_all_nets) #define SIGNED inst->View()->IsSigned() if (inst->Type() == OPER_ADDER) { @@ -522,7 +532,7 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr } if (inst->Type() == OPER_WIDE_BUF) { - module->addPos(inst_name, IN, OUT, SIGNED); + module->addPos(inst_name, IN, FILTERED_OUT, SIGNED); return true; } @@ -786,8 +796,9 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se module->fixup_ports(); dict<Net*, char, hash_ptr_ops> init_nets; - pool<Net*, hash_ptr_ops> anyconst_nets; - pool<Net*, hash_ptr_ops> anyseq_nets; + pool<Net*, hash_ptr_ops> anyconst_nets, anyseq_nets; + pool<Net*, hash_ptr_ops> allconst_nets, allseq_nets; + any_all_nets.clear(); FOREACH_NET_OF_NETLIST(nl, mi, net) { @@ -862,11 +873,36 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se const char *rand_const_attr = net->GetAttValue(" rand_const"); const char *rand_attr = net->GetAttValue(" rand"); - if (rand_const_attr != nullptr && !strcmp(rand_const_attr, "1")) - anyconst_nets.insert(net); + const char *anyconst_attr = net->GetAttValue("anyconst"); + const char *anyseq_attr = net->GetAttValue("anyseq"); + + const char *allconst_attr = net->GetAttValue("allconst"); + const char *allseq_attr = net->GetAttValue("allseq"); - else if (rand_attr != nullptr && !strcmp(rand_attr, "1")) + if (rand_const_attr != nullptr && (!strcmp(rand_const_attr, "1") || !strcmp(rand_const_attr, "'1'"))) { + anyconst_nets.insert(net); + any_all_nets.insert(net); + } + else if (rand_attr != nullptr && (!strcmp(rand_attr, "1") || !strcmp(rand_attr, "'1'"))) { + anyseq_nets.insert(net); + any_all_nets.insert(net); + } + else if (anyconst_attr != nullptr && (!strcmp(anyconst_attr, "1") || !strcmp(anyconst_attr, "'1'"))) { + anyconst_nets.insert(net); + any_all_nets.insert(net); + } + else if (anyseq_attr != nullptr && (!strcmp(anyseq_attr, "1") || !strcmp(anyseq_attr, "'1'"))) { anyseq_nets.insert(net); + any_all_nets.insert(net); + } + else if (allconst_attr != nullptr && (!strcmp(allconst_attr, "1") || !strcmp(allconst_attr, "'1'"))) { + allconst_nets.insert(net); + any_all_nets.insert(net); + } + else if (allseq_attr != nullptr && (!strcmp(allseq_attr, "1") || !strcmp(allseq_attr, "'1'"))) { + allseq_nets.insert(net); + any_all_nets.insert(net); + } if (net_map.count(net)) { if (verific_verbose) @@ -951,6 +987,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se SigSpec anyconst_sig; SigSpec anyseq_sig; + SigSpec allconst_sig; + SigSpec allseq_sig; for (int i = netbus->RightIndex();; i += netbus->IsUp() ? -1 : +1) { net = netbus->ElementAtIndex(i); @@ -962,6 +1000,14 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se anyseq_sig.append(net_map_at(net)); anyseq_nets.erase(net); } + if (net != nullptr && allconst_nets.count(net)) { + allconst_sig.append(net_map_at(net)); + allconst_nets.erase(net); + } + if (net != nullptr && allseq_nets.count(net)) { + allseq_sig.append(net_map_at(net)); + allseq_nets.erase(net); + } if (i == netbus->LeftIndex()) break; } @@ -971,6 +1017,12 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se if (GetSize(anyseq_sig)) module->connect(anyseq_sig, module->Anyseq(NEW_ID, GetSize(anyseq_sig))); + + if (GetSize(allconst_sig)) + module->connect(allconst_sig, module->Allconst(NEW_ID, GetSize(allconst_sig))); + + if (GetSize(allseq_sig)) + module->connect(allseq_sig, module->Allseq(NEW_ID, GetSize(allseq_sig))); } for (auto it : init_nets) @@ -1027,7 +1079,9 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se } if (inst->Type() == PRIM_BUF) { - module->addBufGate(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + auto outnet = inst->GetOutput(); + if (!any_all_nets.count(outnet)) + module->addBufGate(inst_name, net_map_at(inst->GetInput()), net_map_at(outnet)); continue; } @@ -1044,23 +1098,30 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se if (inst->Type() == OPER_READ_PORT) { RTLIL::Memory *memory = module->memories.at(RTLIL::escape_id(inst->GetInput()->Name())); - if (memory->width != int(inst->OutputSize())) - log_error("Import of asymetric memories from Verific is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name()); + int numchunks = int(inst->OutputSize()) / memory->width; + int chunksbits = ceil_log2(numchunks); - RTLIL::SigSpec addr = operatorInput1(inst); - RTLIL::SigSpec data = operatorOutput(inst); + if ((numchunks * memory->width) != int(inst->OutputSize()) || (numchunks & (numchunks - 1)) != 0) + log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name()); - RTLIL::Cell *cell = module->addCell(inst_name, "$memrd"); - cell->parameters["\\MEMID"] = memory->name.str(); - cell->parameters["\\CLK_ENABLE"] = false; - cell->parameters["\\CLK_POLARITY"] = true; - cell->parameters["\\TRANSPARENT"] = false; - cell->parameters["\\ABITS"] = GetSize(addr); - cell->parameters["\\WIDTH"] = GetSize(data); - cell->setPort("\\CLK", RTLIL::State::Sx); - cell->setPort("\\EN", RTLIL::State::Sx); - cell->setPort("\\ADDR", addr); - cell->setPort("\\DATA", data); + for (int i = 0; i < numchunks; i++) + { + RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)}; + RTLIL::SigSpec data = operatorOutput(inst).extract(i * memory->width, memory->width); + + RTLIL::Cell *cell = module->addCell(numchunks == 1 ? inst_name : + RTLIL::IdString(stringf("%s_%d", inst_name.c_str(), i)), "$memrd"); + cell->parameters["\\MEMID"] = memory->name.str(); + cell->parameters["\\CLK_ENABLE"] = false; + cell->parameters["\\CLK_POLARITY"] = true; + cell->parameters["\\TRANSPARENT"] = false; + cell->parameters["\\ABITS"] = GetSize(addr); + cell->parameters["\\WIDTH"] = GetSize(data); + cell->setPort("\\CLK", RTLIL::State::Sx); + cell->setPort("\\EN", RTLIL::State::Sx); + cell->setPort("\\ADDR", addr); + cell->setPort("\\DATA", data); + } continue; } @@ -1068,7 +1129,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se { RTLIL::Memory *memory = module->memories.at(RTLIL::escape_id(inst->GetOutput()->Name())); if (memory->width != int(inst->Input2Size())) - log_error("Import of asymetric memories from Verific is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name()); + log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name()); RTLIL::SigSpec addr = operatorInput1(inst); RTLIL::SigSpec data = operatorInput2(inst); @@ -1214,11 +1275,27 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se continue; } - if (inst->IsPrimitive()) + if (inst->Type() == PRIM_HDL_ASSERTION) { - if (inst->Type() == PRIM_HDL_ASSERTION) - continue; + SigBit cond = net_map_at(inst->GetInput()); + + if (verific_verbose) + log(" assert condition %s.\n", log_signal(cond)); + + const char *assume_attr = nullptr; // inst->GetAttValue("assume"); + + Cell *cell = nullptr; + if (assume_attr != nullptr && !strcmp(assume_attr, "1")) + cell = module->addAssume(NEW_ID, cond, State::S1); + else + cell = module->addAssert(NEW_ID, cond, State::S1); + + import_attributes(cell->attributes, inst); + continue; + } + if (inst->IsPrimitive()) + { if (!mode_keep) log_error("Unsupported Verific primitive %s of type %s\n", inst->Name(), inst->View()->Owner()->Name()); @@ -1272,8 +1349,11 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se if (!mode_nosva) { - for (auto inst : sva_asserts) + for (auto inst : sva_asserts) { + if (mode_autocover) + verific_import_sva_cover(this, inst); verific_import_sva_assert(this, inst); + } for (auto inst : sva_assumes) verific_import_sva_assume(this, inst); @@ -1290,7 +1370,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se // ================================================================== -VerificClocking::VerificClocking(VerificImporter *importer, Net *net) +VerificClocking::VerificClocking(VerificImporter *importer, Net *net, bool sva_at_only) { module = importer->module; @@ -1313,8 +1393,14 @@ VerificClocking::VerificClocking(VerificImporter *importer, Net *net) body_net = body_inst->GetInput2(); } } + else + { + if (sva_at_only) + return; + } - if (inst != nullptr && inst->Type() == PRIM_SVA_POSEDGE) + // Use while() instead of if() to work around VIPER #13453 + while (inst != nullptr && inst->Type() == PRIM_SVA_POSEDGE) { net = inst->GetInput(); inst = net->Driver();; @@ -1388,6 +1474,10 @@ VerificClocking::VerificClocking(VerificImporter *importer, Net *net) clock_net = net; clock_sig = importer->net_map_at(clock_net); + + const char *gclk_attr = clock_net->GetAttValue("gclk"); + if (gclk_attr != nullptr && (!strcmp(gclk_attr, "1") || !strcmp(gclk_attr, "'1'"))) + gclk = true; } Cell *VerificClocking::addDff(IdString name, SigSpec sig_d, SigSpec sig_q, Const init_value) @@ -1410,15 +1500,20 @@ Cell *VerificClocking::addDff(IdString name, SigSpec sig_d, SigSpec sig_q, Const sig_d = module->Mux(NEW_ID, sig_q, sig_d, enable_sig); if (disable_sig != State::S0) { + log_assert(gclk == false); log_assert(GetSize(sig_q) == GetSize(init_value)); return module->addAdff(name, clock_sig, disable_sig, sig_d, sig_q, init_value, posedge); } + if (gclk) + return module->addFf(name, sig_d, sig_q); + return module->addDff(name, clock_sig, sig_d, sig_q, posedge); } Cell *VerificClocking::addAdff(IdString name, RTLIL::SigSpec sig_arst, SigSpec sig_d, SigSpec sig_q, Const arst_value) { + log_assert(gclk == false); log_assert(disable_sig == State::S0); if (enable_sig != State::S1) @@ -1429,6 +1524,7 @@ Cell *VerificClocking::addAdff(IdString name, RTLIL::SigSpec sig_arst, SigSpec s Cell *VerificClocking::addDffsr(IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, SigSpec sig_d, SigSpec sig_q) { + log_assert(gclk == false); log_assert(disable_sig == State::S0); if (enable_sig != State::S1) @@ -1521,14 +1617,78 @@ struct VerificExtNets } }; +void verific_import(Design *design, std::string top) +{ + verific_sva_fsm_limit = 16; + + std::set<Netlist*> nl_todo, nl_done; + + { + VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1); + VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1); + + Array veri_libs, vhdl_libs; + if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib); + if (veri_lib) veri_libs.InsertLast(veri_lib); + + Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs); + Netlist *nl; + int i; + + FOREACH_ARRAY_ITEM(netlists, i, nl) { + if (top.empty() || nl->Owner()->Name() == top) + nl_todo.insert(nl); + } + + delete netlists; + } + + if (!verific_error_msg.empty()) + log_error("%s\n", verific_error_msg.c_str()); + + VerificExtNets worker; + for (auto nl : nl_todo) + worker.run(nl); + + while (!nl_todo.empty()) { + Netlist *nl = *nl_todo.begin(); + if (nl_done.count(nl) == 0) { + VerificImporter importer(false, false, false, false, false, false); + importer.import_netlist(design, nl, nl_todo); + } + nl_todo.erase(nl); + nl_done.insert(nl); + } + + veri_file::Reset(); + vhdl_file::Reset(); + Libset::Reset(); + verific_incdirs.clear(); + verific_libdirs.clear(); + verific_import_pending = false; + + if (!verific_error_msg.empty()) + log_error("%s\n", verific_error_msg.c_str()); +} + YOSYS_NAMESPACE_END #endif /* YOSYS_ENABLE_VERIFIC */ PRIVATE_NAMESPACE_BEGIN +bool check_noverific_env() +{ + const char *e = getenv("YOSYS_NOVERIFIC"); + if (e == nullptr) + return false; + if (atoi(e) == 0) + return false; + return true; +} + struct VerificPass : public Pass { VerificPass() : Pass("verific", "load Verilog and VHDL designs using Verific") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -1536,12 +1696,31 @@ struct VerificPass : public Pass { log("\n"); log("Load the specified Verilog/SystemVerilog files into Verific.\n"); log("\n"); + log("All files specified in one call to this command are one compilation unit.\n"); + log("Files passed to different calls to this command are treated as belonging to\n"); + log("different compilation units.\n"); + log("\n"); + log("Additional -D<macro>[=<value>] options may be added after the option indicating\n"); + log("the language version (and before file names) to set additional verilog defines.\n"); + log("The macros SYNTHESIS and VERIFIC are defined implicitly.\n"); + log("\n"); + log("\n"); + log(" verific -formal <verilog-file>..\n"); + log("\n"); + log("Like -sv, but define FORMAL instead of SYNTHESIS.\n"); + log("\n"); log("\n"); log(" verific {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl} <vhdl-file>..\n"); log("\n"); log("Load the specified VHDL files into Verific.\n"); log("\n"); log("\n"); + log(" verific -work <libname> {-sv|-vhdl|...} <hdl-file>\n"); + log("\n"); + log("Load the specified Verilog/SystemVerilog/VHDL file into the specified library.\n"); + log("(default library when -work is not present: \"work\")\n"); + log("\n"); + log("\n"); log(" verific -vlog-incdir <directory>..\n"); log("\n"); log("Add Verilog include directories.\n"); @@ -1555,7 +1734,21 @@ struct VerificPass : public Pass { log("\n"); log(" verific -vlog-define <macro>[=<value>]..\n"); log("\n"); - log("Add Verilog defines. (The macros SYNTHESIS and VERIFIC are defined implicitly.)\n"); + log("Add Verilog defines.\n"); + log("\n"); + log("\n"); + log(" verific -vlog-undef <macro>..\n"); + log("\n"); + log("Remove Verilog defines previously set with -vlog-define.\n"); + log("\n"); + log("\n"); + log(" verific -set-error <msg_id>..\n"); + log(" verific -set-warning <msg_id>..\n"); + log(" verific -set-info <msg_id>..\n"); + log(" verific -set-ignore <msg_id>..\n"); + log("\n"); + log("Set message severity. <msg_id> is the string in square brackets when a message\n"); + log("is printed, such as VERI-1209.\n"); log("\n"); log("\n"); log(" verific -import [options] <top-module>..\n"); @@ -1578,6 +1771,9 @@ struct VerificPass : public Pass { log(" -extnets\n"); log(" Resolve references to external nets by adding module ports as needed.\n"); log("\n"); + log(" -autocover\n"); + log(" Generate automatic cover statements for all asserts\n"); + log("\n"); log(" -v, -vv\n"); log(" Verbose log messages. (-vv is even more verbose than -v.)\n"); log("\n"); @@ -1596,6 +1792,9 @@ struct VerificPass : public Pass { log(" -nosva\n"); log(" Ignore SVA properties, do not infer checker logic.\n"); log("\n"); + log(" -L <int>\n"); + log(" Maximum number of ctrl bits for SVA checker FSMs (default=16).\n"); + log("\n"); log(" -n\n"); log(" Keep all Verific names on instances and nets. By default only\n"); log(" user-declared names are preserved.\n"); @@ -1607,19 +1806,37 @@ struct VerificPass : public Pass { log("\n"); } #ifdef YOSYS_ENABLE_VERIFIC - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { + static bool set_verific_global_flags = true; + + if (check_noverific_env()) + log_cmd_error("This version of Yosys is built without Verific support.\n"); + log_header(design, "Executing VERIFIC (loading SystemVerilog and VHDL designs using Verific).\n"); - Message::SetConsoleOutput(0); - Message::RegisterCallBackMsg(msg_func); - RuntimeFlags::SetVar("db_preserve_user_nets", 1); - RuntimeFlags::SetVar("db_allow_external_nets", 1); - RuntimeFlags::SetVar("vhdl_ignore_assertion_statements", 0); - veri_file::DefineCmdLineMacro("VERIFIC"); - veri_file::DefineCmdLineMacro("SYNTHESIS"); + if (set_verific_global_flags) + { + Message::SetConsoleOutput(0); + Message::RegisterCallBackMsg(msg_func); + RuntimeFlags::SetVar("db_preserve_user_nets", 1); + RuntimeFlags::SetVar("db_allow_external_nets", 1); + RuntimeFlags::SetVar("vhdl_ignore_assertion_statements", 0); + RuntimeFlags::SetVar("veri_extract_dualport_rams", 0); + RuntimeFlags::SetVar("veri_extract_multiport_rams", 1); + RuntimeFlags::SetVar("db_infer_wide_operators", 1); + + // Workaround for VIPER #13851 + RuntimeFlags::SetVar("veri_create_name_for_unnamed_gen_block", 1); + + // WARNING: instantiating unknown module 'XYZ' (VERI-1063) + Message::SetMessageType("VERI-1063", VERIFIC_ERROR); + + set_verific_global_flags = false; + } verific_verbose = 0; + verific_sva_fsm_limit = 16; const char *release_str = Message::ReleaseString(); time_t release_time = Message::ReleaseDate(); @@ -1634,16 +1851,39 @@ struct VerificPass : public Pass { log("Built with Verific %s, released at %s.\n", release_str, release_tmstr); int argidx = 1; + std::string work = "work"; + + if (GetSize(args) > argidx && (args[argidx] == "-set-error" || args[argidx] == "-set-warning" || + args[argidx] == "-set-info" || args[argidx] == "-set-ignore")) + { + msg_type_t new_type; + + if (args[argidx] == "-set-error") + new_type = VERIFIC_ERROR; + else if (args[argidx] == "-set-warning") + new_type = VERIFIC_WARNING; + else if (args[argidx] == "-set-info") + new_type = VERIFIC_INFO; + else if (args[argidx] == "-set-ignore") + new_type = VERIFIC_IGNORE; + else + log_abort(); + + for (argidx++; argidx < GetSize(args); argidx++) + Message::SetMessageType(args[argidx].c_str(), new_type); + + goto check_error; + } if (GetSize(args) > argidx && args[argidx] == "-vlog-incdir") { for (argidx++; argidx < GetSize(args); argidx++) - veri_file::AddIncludeDir(args[argidx].c_str()); + verific_incdirs.push_back(args[argidx]); goto check_error; } if (GetSize(args) > argidx && args[argidx] == "-vlog-libdir") { for (argidx++; argidx < GetSize(args); argidx++) - veri_file::AddYDir(args[argidx].c_str()); + verific_libdirs.push_back(args[argidx]); goto check_error; } @@ -1662,70 +1902,110 @@ struct VerificPass : public Pass { goto check_error; } - if (GetSize(args) > argidx && args[argidx] == "-vlog95") { - for (argidx++; argidx < GetSize(args); argidx++) - if (!veri_file::Analyze(args[argidx].c_str(), veri_file::VERILOG_95)) - log_cmd_error("Reading `%s' in VERILOG_95 mode failed.\n", args[argidx].c_str()); + if (GetSize(args) > argidx && args[argidx] == "-vlog-undef") { + for (argidx++; argidx < GetSize(args); argidx++) { + string name = args[argidx]; + veri_file::UndefineMacro(name.c_str()); + } goto check_error; } - if (GetSize(args) > argidx && args[argidx] == "-vlog2k") { - for (argidx++; argidx < GetSize(args); argidx++) - if (!veri_file::Analyze(args[argidx].c_str(), veri_file::VERILOG_2K)) - log_cmd_error("Reading `%s' in VERILOG_2K mode failed.\n", args[argidx].c_str()); - goto check_error; + for (; argidx < GetSize(args); argidx++) + { + if (args[argidx] == "-work" && argidx+1 < GetSize(args)) { + work = args[++argidx]; + continue; + } + break; } - if (GetSize(args) > argidx && args[argidx] == "-sv2005") { - for (argidx++; argidx < GetSize(args); argidx++) - if (!veri_file::Analyze(args[argidx].c_str(), veri_file::SYSTEM_VERILOG_2005)) - log_cmd_error("Reading `%s' in SYSTEM_VERILOG_2005 mode failed.\n", args[argidx].c_str()); - goto check_error; - } + if (GetSize(args) > argidx && (args[argidx] == "-vlog95" || args[argidx] == "-vlog2k" || args[argidx] == "-sv2005" || + args[argidx] == "-sv2009" || args[argidx] == "-sv2012" || args[argidx] == "-sv" || args[argidx] == "-formal")) + { + Array file_names; + unsigned verilog_mode; + + if (args[argidx] == "-vlog95") + verilog_mode = veri_file::VERILOG_95; + else if (args[argidx] == "-vlog2k") + verilog_mode = veri_file::VERILOG_2K; + else if (args[argidx] == "-sv2005") + verilog_mode = veri_file::SYSTEM_VERILOG_2005; + else if (args[argidx] == "-sv2009") + verilog_mode = veri_file::SYSTEM_VERILOG_2009; + else if (args[argidx] == "-sv2012" || args[argidx] == "-sv" || args[argidx] == "-formal") + verilog_mode = veri_file::SYSTEM_VERILOG; + else + log_abort(); - if (GetSize(args) > argidx && args[argidx] == "-sv2009") { - for (argidx++; argidx < GetSize(args); argidx++) - if (!veri_file::Analyze(args[argidx].c_str(), veri_file::SYSTEM_VERILOG_2009)) - log_cmd_error("Reading `%s' in SYSTEM_VERILOG_2009 mode failed.\n", args[argidx].c_str()); - goto check_error; - } + veri_file::DefineMacro("VERIFIC"); + veri_file::DefineMacro(args[argidx] == "-formal" ? "FORMAL" : "SYNTHESIS"); - if (GetSize(args) > argidx && (args[argidx] == "-sv2012" || args[argidx] == "-sv")) { - for (argidx++; argidx < GetSize(args); argidx++) - if (!veri_file::Analyze(args[argidx].c_str(), veri_file::SYSTEM_VERILOG)) - log_cmd_error("Reading `%s' in SYSTEM_VERILOG mode failed.\n", args[argidx].c_str()); + for (argidx++; argidx < GetSize(args) && GetSize(args[argidx]) >= 2 && args[argidx].substr(0, 2) == "-D"; argidx++) { + std::string name = args[argidx].substr(2); + if (args[argidx] == "-D") { + if (++argidx >= GetSize(args)) + break; + name = args[argidx]; + } + size_t equal = name.find('='); + if (equal != std::string::npos) { + string value = name.substr(equal+1); + name = name.substr(0, equal); + veri_file::DefineMacro(name.c_str(), value.c_str()); + } else { + veri_file::DefineMacro(name.c_str()); + } + } + + for (auto &dir : verific_incdirs) + veri_file::AddIncludeDir(dir.c_str()); + for (auto &dir : verific_libdirs) + veri_file::AddYDir(dir.c_str()); + + while (argidx < GetSize(args)) + file_names.Insert(args[argidx++].c_str()); + + if (!veri_file::AnalyzeMultipleFiles(&file_names, verilog_mode, work.c_str(), veri_file::MFCU)) + log_cmd_error("Reading Verilog/SystemVerilog sources failed.\n"); + + verific_import_pending = true; goto check_error; } if (GetSize(args) > argidx && args[argidx] == "-vhdl87") { vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1987").c_str()); for (argidx++; argidx < GetSize(args); argidx++) - if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_87)) + if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_87)) log_cmd_error("Reading `%s' in VHDL_87 mode failed.\n", args[argidx].c_str()); + verific_import_pending = true; goto check_error; } if (GetSize(args) > argidx && args[argidx] == "-vhdl93") { vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str()); for (argidx++; argidx < GetSize(args); argidx++) - if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_93)) + if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_93)) log_cmd_error("Reading `%s' in VHDL_93 mode failed.\n", args[argidx].c_str()); + verific_import_pending = true; goto check_error; } if (GetSize(args) > argidx && args[argidx] == "-vhdl2k") { vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str()); for (argidx++; argidx < GetSize(args); argidx++) - if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_2K)) + if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_2K)) log_cmd_error("Reading `%s' in VHDL_2K mode failed.\n", args[argidx].c_str()); + verific_import_pending = true; goto check_error; } if (GetSize(args) > argidx && (args[argidx] == "-vhdl2008" || args[argidx] == "-vhdl")) { vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_2008").c_str()); for (argidx++; argidx < GetSize(args); argidx++) - if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_2008)) + if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_2008)) log_cmd_error("Reading `%s' in VHDL_2008 mode failed.\n", args[argidx].c_str()); + verific_import_pending = true; goto check_error; } @@ -1734,6 +2014,7 @@ struct VerificPass : public Pass { std::set<Netlist*> nl_todo, nl_done; bool mode_all = false, mode_gates = false, mode_keep = false; bool mode_nosva = false, mode_names = false, mode_verific = false; + bool mode_autocover = false; bool flatten = false, extnets = false; string dumpfile; @@ -1762,10 +2043,18 @@ struct VerificPass : public Pass { mode_nosva = true; continue; } + if (args[argidx] == "-L" && argidx+1 < GetSize(args)) { + verific_sva_fsm_limit = atoi(args[++argidx].c_str()); + continue; + } if (args[argidx] == "-n") { mode_names = true; continue; } + if (args[argidx] == "-autocover") { + mode_autocover = true; + continue; + } if (args[argidx] == "-V") { mode_verific = true; continue; @@ -1828,8 +2117,8 @@ struct VerificPass : public Pass { #else log("Running hier_tree::ElaborateAll().\n"); - VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1); - VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1); + VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1); + VeriLibrary *veri_lib = veri_file::GetLibrary(work.c_str(), 1); Array veri_libs, vhdl_libs; if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib); @@ -1876,7 +2165,7 @@ struct VerificPass : public Pass { continue; } - VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1); + VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1); VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(name); if (vhdl_unit) { log("Adding VHDL unit '%s' to elaboration queue.\n", name); @@ -1898,6 +2187,9 @@ struct VerificPass : public Pass { #endif } + if (!verific_error_msg.empty()) + goto check_error; + if (flatten) { for (auto nl : nl_todo) nl->Flatten(); @@ -1918,7 +2210,7 @@ struct VerificPass : public Pass { Netlist *nl = *nl_todo.begin(); if (nl_done.count(nl) == 0) { VerificImporter importer(mode_gates, mode_keep, mode_nosva, - mode_names, mode_verific); + mode_names, mode_verific, mode_autocover); importer.import_netlist(design, nl, nl_todo); } nl_todo.erase(nl); @@ -1928,6 +2220,9 @@ struct VerificPass : public Pass { veri_file::Reset(); vhdl_file::Reset(); Libset::Reset(); + verific_incdirs.clear(); + verific_libdirs.clear(); + verific_import_pending = false; goto check_error; } @@ -1939,11 +2234,139 @@ struct VerificPass : public Pass { } #else /* YOSYS_ENABLE_VERIFIC */ - virtual void execute(std::vector<std::string>, RTLIL::Design *) { + void execute(std::vector<std::string>, RTLIL::Design *) YS_OVERRIDE { log_cmd_error("This version of Yosys is built without Verific support.\n"); } #endif } VerificPass; -PRIVATE_NAMESPACE_END +struct ReadPass : public Pass { + ReadPass() : Pass("read", "load HDL designs") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" read {-vlog95|-vlog2k|-sv2005|-sv2009|-sv2012|-sv|-formal} <verilog-file>..\n"); + log("\n"); + log("Load the specified Verilog/SystemVerilog files. (Full SystemVerilog support\n"); + log("is only available via Verific.)\n"); + log("\n"); + log("Additional -D<macro>[=<value>] options may be added after the option indicating\n"); + log("the language version (and before file names) to set additional verilog defines.\n"); + log("\n"); + log("\n"); + log(" read {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl} <vhdl-file>..\n"); + log("\n"); + log("Load the specified VHDL files. (Requires Verific.)\n"); + log("\n"); + log("\n"); + log(" read -define <macro>[=<value>]..\n"); + log("\n"); + log("Set global Verilog/SystemVerilog defines.\n"); + log("\n"); + log("\n"); + log(" read -undef <macro>..\n"); + log("\n"); + log("Unset global Verilog/SystemVerilog defines.\n"); + log("\n"); + log("\n"); + log(" read -incdir <directory>\n"); + log("\n"); + log("Add directory to global Verilog/SystemVerilog include directories.\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + if (args.size() < 2) + log_cmd_error("Missing mode parameter.\n"); + + if (args.size() < 3) + log_cmd_error("Missing file name parameter.\n"); + +#ifdef YOSYS_ENABLE_VERIFIC + bool use_verific = !check_noverific_env(); +#else + bool use_verific = false; +#endif + if (args[1] == "-vlog95" || args[1] == "-vlog2k") { + if (use_verific) { + args[0] = "verific"; + } else { + args[0] = "read_verilog"; + args.erase(args.begin()+1, args.begin()+2); + } + Pass::call(design, args); + return; + } + + if (args[1] == "-sv2005" || args[1] == "-sv2009" || args[1] == "-sv2012" || args[1] == "-sv" || args[1] == "-formal") { + if (use_verific) { + args[0] = "verific"; + } else { + args[0] = "read_verilog"; + if (args[1] == "-formal") + args.insert(args.begin()+1, std::string()); + args[1] = "-sv"; + } + Pass::call(design, args); + return; + } + + if (args[1] == "-vhdl87" || args[1] == "-vhdl93" || args[1] == "-vhdl2k" || args[1] == "-vhdl2008" || args[1] == "-vhdl") { + if (use_verific) { + args[0] = "verific"; + Pass::call(design, args); + } else { + log_cmd_error("This version of Yosys is built without Verific support.\n"); + } + return; + } + + if (args[1] == "-define") { + if (use_verific) { + args[0] = "verific"; + args[1] = "-vlog-define"; + Pass::call(design, args); + } + args[0] = "verilog_defines"; + args.erase(args.begin()+1, args.begin()+2); + for (int i = 1; i < GetSize(args); i++) + args[i] = "-D" + args[i]; + Pass::call(design, args); + return; + } + + if (args[1] == "-undef") { + if (use_verific) { + args[0] = "verific"; + args[1] = "-vlog-undef"; + Pass::call(design, args); + } + args[0] = "verilog_defines"; + args.erase(args.begin()+1, args.begin()+2); + for (int i = 1; i < GetSize(args); i++) + args[i] = "-U" + args[i]; + Pass::call(design, args); + return; + } + + if (args[1] == "-incdir") { + if (use_verific) { + args[0] = "verific"; + args[1] = "-vlog-incdir"; + Pass::call(design, args); + } + args[0] = "verilog_defaults"; + args[1] = "-add"; + for (int i = 2; i < GetSize(args); i++) + args[i] = "-I" + args[i]; + Pass::call(design, args); + return; + } + + log_cmd_error("Missing or unsupported mode parameter.\n"); + } +} ReadPass; + +PRIVATE_NAMESPACE_END diff --git a/frontends/verific/verific.h b/frontends/verific/verific.h index 877d79057..334a436af 100644 --- a/frontends/verific/verific.h +++ b/frontends/verific/verific.h @@ -25,6 +25,9 @@ YOSYS_NAMESPACE_BEGIN extern int verific_verbose; +extern bool verific_import_pending; +extern void verific_import(Design *design, std::string top = std::string()); + extern pool<int> verific_sva_prims; struct VerificImporter; @@ -40,9 +43,10 @@ struct VerificClocking { SigBit enable_sig = State::S1; SigBit disable_sig = State::S0; bool posedge = true; + bool gclk = false; VerificClocking() { } - VerificClocking(VerificImporter *importer, Verific::Net *net); + VerificClocking(VerificImporter *importer, Verific::Net *net, bool sva_at_only = false); RTLIL::Cell *addDff(IdString name, SigSpec sig_d, SigSpec sig_q, Const init_value = Const()); RTLIL::Cell *addAdff(IdString name, RTLIL::SigSpec sig_arst, SigSpec sig_d, SigSpec sig_q, Const arst_value); RTLIL::Cell *addDffsr(IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, SigSpec sig_d, SigSpec sig_q); @@ -65,10 +69,12 @@ struct VerificImporter std::map<Verific::Net*, RTLIL::SigBit> net_map; std::map<Verific::Net*, Verific::Net*> sva_posedge_map; + pool<Verific::Net*, hash_ptr_ops> any_all_nets; bool mode_gates, mode_keep, mode_nosva, mode_names, mode_verific; + bool mode_autocover; - VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific); + VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific, bool mode_autocover); RTLIL::SigBit net_map_at(Verific::Net *net); @@ -78,7 +84,7 @@ struct VerificImporter RTLIL::SigSpec operatorInput1(Verific::Instance *inst); RTLIL::SigSpec operatorInput2(Verific::Instance *inst); RTLIL::SigSpec operatorInport(Verific::Instance *inst, const char *portname); - RTLIL::SigSpec operatorOutput(Verific::Instance *inst); + RTLIL::SigSpec operatorOutput(Verific::Instance *inst, const pool<Verific::Net*, hash_ptr_ops> *any_all_nets = nullptr); bool import_netlist_instance_gates(Verific::Instance *inst, RTLIL::IdString inst_name); bool import_netlist_instance_cells(Verific::Instance *inst, RTLIL::IdString inst_name); @@ -95,6 +101,8 @@ void verific_import_sva_cover(VerificImporter *importer, Verific::Instance *inst void verific_import_sva_trigger(VerificImporter *importer, Verific::Instance *inst); bool verific_is_sva_net(VerificImporter *importer, Verific::Net *net); +extern int verific_sva_fsm_limit; + YOSYS_NAMESPACE_END #endif diff --git a/frontends/verific/verificsva.cc b/frontends/verific/verificsva.cc index 5abe0eb35..cdc9ece8c 100644 --- a/frontends/verific/verificsva.cc +++ b/frontends/verific/verificsva.cc @@ -21,14 +21,52 @@ // Currently supported SVA sequence and property syntax: // http://symbiyosys.readthedocs.io/en/latest/verific.html // -// Todos: -// property and property -// sequence |-> always sequence -// sequence |-> eventually sequence -// sequence implies sequence -// sequence iff sequence -// accept_on (expr) prop -// reject_on (expr) prop +// Next gen property syntax: +// basic_property +// [antecedent_condition] property +// [antecedent_condition] always.. property +// [antecedent_condition] eventually.. basic_property +// [antecedent_condition] property until.. expression +// [antecedent_condition] basic_property until.. basic_property (assert/assume only) +// +// antecedent_condition: +// sequence |-> +// sequence |=> +// +// basic_property: +// sequence +// not basic_property +// sequence #-# basic_property +// sequence #=# basic_property +// basic_property or basic_property (cover only) +// basic_property and basic_property (assert/assume only) +// basic_property implies basic_property +// basic_property iff basic_property +// +// sequence: +// expression +// sequence ##N sequence +// sequence ##[*] sequence +// sequence ##[+] sequence +// sequence ##[N:M] sequence +// sequence ##[N:$] sequence +// expression [*] +// expression [+] +// expression [*N] +// expression [*N:M] +// expression [*N:$] +// sequence or sequence +// sequence and sequence +// expression throughout sequence +// sequence intersect sequence +// sequence within sequence +// first_match( sequence ) +// expression [=N] +// expression [=N:M] +// expression [=N:$] +// expression [->N] +// expression [->N:M] +// expression [->N:$] #include "kernel/yosys.h" @@ -428,13 +466,14 @@ struct SvaFsm dnode.ctrl.sort_and_unify(); - if (GetSize(dnode.ctrl) > 16) { + if (GetSize(dnode.ctrl) > verific_sva_fsm_limit) { if (verific_verbose >= 2) { log(" detected state explosion in DFSM generation:\n"); dump(); log(" ctrl signal: %s\n", log_signal(dnode.ctrl)); } - log_error("SVA DFSM state ctrl signal has %d (>16) bits. Stopping to prevent exponential design size explosion.\n", GetSize(dnode.ctrl)); + log_error("SVA DFSM state ctrl signal has %d (>%d) bits. Stopping to prevent exponential design size explosion.\n", + GetSize(dnode.ctrl), verific_sva_fsm_limit); } for (int i = 0; i < (1 << GetSize(dnode.ctrl)); i++) @@ -942,7 +981,6 @@ struct VerificSvaImporter bool mode_assume = false; bool mode_cover = false; bool mode_trigger = false; - bool eventually = false; Instance *net_to_ast_driver(Net *n) { @@ -1100,6 +1138,97 @@ struct VerificSvaImporter log_abort(); } + bool check_zero_consecutive_repeat(Net *net) + { + Instance *inst = net_to_ast_driver(net); + + if (inst == nullptr) + return false; + + if (inst->Type() != PRIM_SVA_CONSECUTIVE_REPEAT) + return false; + + const char *sva_low_s = inst->GetAttValue("sva:low"); + int sva_low = atoi(sva_low_s); + + return sva_low == 0; + } + + int parse_consecutive_repeat(SvaFsm &fsm, int start_node, Net *net, bool add_pre_delay, bool add_post_delay) + { + Instance *inst = net_to_ast_driver(net); + + log_assert(inst->Type() == PRIM_SVA_CONSECUTIVE_REPEAT); + + const char *sva_low_s = inst->GetAttValue("sva:low"); + const char *sva_high_s = inst->GetAttValue("sva:high"); + + int sva_low = atoi(sva_low_s); + int sva_high = atoi(sva_high_s); + bool sva_inf = !strcmp(sva_high_s, "$"); + + Net *body_net = inst->GetInput(); + + if (add_pre_delay || add_post_delay) + log_assert(sva_low == 0); + + if (sva_low == 0) { + if (!add_pre_delay && !add_post_delay) + parser_error("Possibly zero-length consecutive repeat must follow or precede a delay of at least one cycle", inst); + sva_low++; + } + + int node = fsm.createNode(start_node); + start_node = node; + + if (add_pre_delay) { + node = fsm.createNode(start_node); + fsm.createEdge(start_node, node); + } + + int prev_node = node; + node = parse_sequence(fsm, node, body_net); + + for (int i = 1; i < sva_low; i++) + { + int next_node = fsm.createNode(); + fsm.createEdge(node, next_node); + + prev_node = node; + node = parse_sequence(fsm, next_node, body_net); + } + + if (sva_inf) + { + log_assert(prev_node >= 0); + fsm.createEdge(node, prev_node); + } + else + { + for (int i = sva_low; i < sva_high; i++) + { + int next_node = fsm.createNode(); + fsm.createEdge(node, next_node); + + prev_node = node; + node = parse_sequence(fsm, next_node, body_net); + + fsm.createLink(prev_node, node); + } + } + + if (add_post_delay) { + int next_node = fsm.createNode(); + fsm.createEdge(node, next_node); + node = next_node; + } + + if (add_pre_delay || add_post_delay) + fsm.createLink(start_node, node); + + return node; + } + int parse_sequence(SvaFsm &fsm, int start_node, Net *net) { if (check_expression(net)) { @@ -1144,7 +1273,20 @@ struct VerificSvaImporter int sva_high = atoi(sva_high_s); bool sva_inf = !strcmp(sva_high_s, "$"); - int node = parse_sequence(fsm, start_node, inst->GetInput1()); + int node = -1; + bool past_add_delay = false; + + if (check_zero_consecutive_repeat(inst->GetInput1()) && sva_low > 0) { + node = parse_consecutive_repeat(fsm, start_node, inst->GetInput1(), false, true); + sva_low--, sva_high--; + } else { + node = parse_sequence(fsm, start_node, inst->GetInput1()); + } + + if (check_zero_consecutive_repeat(inst->GetInput2()) && sva_low > 0) { + past_add_delay = true; + sva_low--, sva_high--; + } for (int i = 0; i < sva_low; i++) { int next_node = fsm.createNode(); @@ -1167,62 +1309,17 @@ struct VerificSvaImporter } } - node = parse_sequence(fsm, node, inst->GetInput2()); + if (past_add_delay) + node = parse_consecutive_repeat(fsm, node, inst->GetInput2(), true, false); + else + node = parse_sequence(fsm, node, inst->GetInput2()); return node; } if (inst->Type() == PRIM_SVA_CONSECUTIVE_REPEAT) { - const char *sva_low_s = inst->GetAttValue("sva:low"); - const char *sva_high_s = inst->GetAttValue("sva:high"); - - int sva_low = atoi(sva_low_s); - int sva_high = atoi(sva_high_s); - bool sva_inf = !strcmp(sva_high_s, "$"); - - Net *body_net = inst->GetInput(); - int node = fsm.createNode(start_node); - - for (int i = 0; i < sva_low; i++) - { - int next_node = fsm.createNode(); - - if (i == 0) - fsm.createLink(node, next_node); - else - fsm.createEdge(node, next_node); - - node = parse_sequence(fsm, next_node, body_net); - } - - if (sva_inf) - { - int next_node = fsm.createNode(); - fsm.createEdge(node, next_node); - - next_node = parse_sequence(fsm, next_node, body_net); - fsm.createLink(next_node, node); - } - else - { - for (int i = sva_low; i < sva_high; i++) - { - int next_node = fsm.createNode(); - - if (i == 0) - fsm.createLink(node, next_node); - else - fsm.createEdge(node, next_node); - - next_node = parse_sequence(fsm, next_node, body_net); - - fsm.createLink(node, next_node); - node = next_node; - } - } - - return node; + return parse_consecutive_repeat(fsm, start_node, net, false, false); } if (inst->Type() == PRIM_SVA_NON_CONSECUTIVE_REPEAT || inst->Type() == PRIM_SVA_GOTO_REPEAT) @@ -1390,6 +1487,72 @@ struct VerificSvaImporter fsm.getFirstAcceptReject(accept_p, reject_p); } + bool eventually_property(Net *&net, SigBit &trig) + { + Instance *inst = net_to_ast_driver(net); + + if (inst == nullptr) + return false; + + if (clocking.cond_net != nullptr) + trig = importer->net_map_at(clocking.cond_net); + else + trig = State::S1; + + if (inst->Type() == PRIM_SVA_S_EVENTUALLY || inst->Type() == PRIM_SVA_EVENTUALLY) + { + if (mode_cover || mode_trigger) + parser_error(inst); + + net = inst->GetInput(); + clocking.cond_net = nullptr; + + return true; + } + + if (inst->Type() == PRIM_SVA_OVERLAPPED_IMPLICATION || + inst->Type() == PRIM_SVA_NON_OVERLAPPED_IMPLICATION) + { + Net *antecedent_net = inst->GetInput1(); + Net *consequent_net = inst->GetInput2(); + + Instance *consequent_inst = net_to_ast_driver(consequent_net); + + if (consequent_inst == nullptr) + return false; + + if (consequent_inst->Type() != PRIM_SVA_S_EVENTUALLY && consequent_inst->Type() != PRIM_SVA_EVENTUALLY) + return false; + + if (mode_cover || mode_trigger) + parser_error(consequent_inst); + + int node; + + SvaFsm antecedent_fsm(clocking, trig); + node = parse_sequence(antecedent_fsm, antecedent_fsm.createStartNode(), antecedent_net); + if (inst->Type() == PRIM_SVA_NON_OVERLAPPED_IMPLICATION) { + int next_node = antecedent_fsm.createNode(); + antecedent_fsm.createEdge(node, next_node); + node = next_node; + } + antecedent_fsm.createLink(node, antecedent_fsm.acceptNode); + + trig = antecedent_fsm.getAccept(); + net = consequent_inst->GetInput(); + clocking.cond_net = nullptr; + + if (verific_verbose) { + log(" Eventually Antecedent FSM:\n"); + antecedent_fsm.dump(); + } + + return true; + } + + return false; + } + void parse_property(Net *net, SigBit *accept_p, SigBit *reject_p) { Instance *inst = net_to_ast_driver(net); @@ -1505,20 +1668,65 @@ struct VerificSvaImporter RTLIL::IdString root_name = module->uniquify(importer->mode_names || root->IsUserDeclared() ? RTLIL::escape_id(root->Name()) : NEW_ID); - clocking = VerificClocking(importer, root->GetInput()); + // parse SVA sequence into trigger signal + + clocking = VerificClocking(importer, root->GetInput(), true); + SigBit accept_bit = State::S0, reject_bit = State::S0; if (clocking.body_net == nullptr) - parser_error(stringf("Failed to parse SVA clocking"), root); + { + if (clocking.clock_net != nullptr || clocking.enable_net != nullptr || clocking.disable_net != nullptr || clocking.cond_net != nullptr) + parser_error(stringf("Failed to parse SVA clocking"), root); - // parse SVA sequence into trigger signal + if (mode_assert || mode_assume) { + reject_bit = module->Not(NEW_ID, parse_expression(root->GetInput())); + } else { + accept_bit = parse_expression(root->GetInput()); + } + } + else + { + Net *net = clocking.body_net; + SigBit trig; - Net *net = clocking.body_net; - SigBit accept_bit = State::S0, reject_bit = State::S0; + if (eventually_property(net, trig)) + { + SigBit sig_a, sig_en = trig; + parse_property(net, &sig_a, nullptr); - if (mode_assert || mode_assume) { - parse_property(net, nullptr, &reject_bit); - } else { - parse_property(net, &accept_bit, nullptr); + // add final FF stage + + SigBit sig_a_q, sig_en_q; + + if (clocking.body_net == nullptr) { + sig_a_q = sig_a; + sig_en_q = sig_en; + } else { + sig_a_q = module->addWire(NEW_ID); + sig_en_q = module->addWire(NEW_ID); + clocking.addDff(NEW_ID, sig_a, sig_a_q, State::S0); + clocking.addDff(NEW_ID, sig_en, sig_en_q, State::S0); + } + + // generate fair/live cell + + RTLIL::Cell *c = nullptr; + + if (mode_assert) c = module->addLive(root_name, sig_a_q, sig_en_q); + if (mode_assume) c = module->addFair(root_name, sig_a_q, sig_en_q); + + importer->import_attributes(c->attributes, root); + + return; + } + else + { + if (mode_assert || mode_assume) { + parse_property(net, nullptr, &reject_bit); + } else { + parse_property(net, &accept_bit, nullptr); + } + } } if (mode_trigger) @@ -1532,10 +1740,17 @@ struct VerificSvaImporter // add final FF stage - SigBit sig_a_q = module->addWire(NEW_ID); - SigBit sig_en_q = module->addWire(NEW_ID); - clocking.addDff(NEW_ID, sig_a, sig_a_q, State::S0); - clocking.addDff(NEW_ID, sig_en, sig_en_q, State::S0); + SigBit sig_a_q, sig_en_q; + + if (clocking.body_net == nullptr) { + sig_a_q = sig_a; + sig_en_q = sig_en; + } else { + sig_a_q = module->addWire(NEW_ID); + sig_en_q = module->addWire(NEW_ID); + clocking.addDff(NEW_ID, sig_a, sig_a_q, State::S0); + clocking.addDff(NEW_ID, sig_en, sig_en_q, State::S0); + } // generate assert/assume/cover cell diff --git a/frontends/verilog/.gitignore b/frontends/verilog/.gitignore index 1d4ae9e5c..aadbcdcdd 100644 --- a/frontends/verilog/.gitignore +++ b/frontends/verilog/.gitignore @@ -1,4 +1,4 @@ verilog_lexer.cc verilog_parser.output verilog_parser.tab.cc -verilog_parser.tab.h +verilog_parser.tab.hh diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index a06c1d5ab..dbaace585 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -1,15 +1,14 @@ GENFILES += frontends/verilog/verilog_parser.tab.cc -GENFILES += frontends/verilog/verilog_parser.tab.h +GENFILES += frontends/verilog/verilog_parser.tab.hh GENFILES += frontends/verilog/verilog_parser.output GENFILES += frontends/verilog/verilog_lexer.cc frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y $(Q) mkdir -p $(dir $@) - $(P) $(BISON) -d -r all -b frontends/verilog/verilog_parser $< - $(Q) mv frontends/verilog/verilog_parser.tab.c frontends/verilog/verilog_parser.tab.cc + $(P) $(BISON) -o $@ -d -r all -b frontends/verilog/verilog_parser $< -frontends/verilog/verilog_parser.tab.h: frontends/verilog/verilog_parser.tab.cc +frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l $(Q) mkdir -p $(dir $@) diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc index 4a58357bf..7848c626d 100644 --- a/frontends/verilog/const2ast.cc +++ b/frontends/verilog/const2ast.cc @@ -49,8 +49,7 @@ static int my_decimal_div_by_two(std::vector<uint8_t> &digits) int carry = 0; for (size_t i = 0; i < digits.size(); i++) { if (digits[i] >= 10) - log_error("Invalid use of [a-fxz?] in decimal constant at %s:%d.\n", - current_filename.c_str(), get_line_num()); + log_file_error(current_filename, get_line_num(), "Invalid use of [a-fxz?] in decimal constant.\n"); digits[i] += carry * 10; carry = digits[i] % 2; digits[i] /= 2; @@ -105,8 +104,8 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le int bits_per_digit = my_ilog2(base-1); for (auto it = digits.rbegin(), e = digits.rend(); it != e; it++) { if (*it > (base-1) && *it < 0xf0) - log_error("Digit larger than %d used in in base-%d constant at %s:%d.\n", - base-1, base, current_filename.c_str(), get_line_num()); + log_file_error(current_filename, get_line_num(), "Digit larger than %d used in in base-%d constant.\n", + base-1, base); for (int i = 0; i < bits_per_digit; i++) { int bitmask = 1 << i; if (*it == 0xf0) @@ -238,4 +237,3 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn } YOSYS_NAMESPACE_END - diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index c43ff4e3a..dea22ee8a 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -183,8 +183,9 @@ static std::string next_token(bool pass_newline = false) const char *ok = "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ$0123456789"; if (ch == '`' || strchr(ok, ch) != NULL) { + char first = ch; ch = next_char(); - if (ch == '"') { + if (first == '`' && (ch == '"' || ch == '`')) { token += ch; } else do { if (strchr(ok, ch) == NULL) { @@ -244,6 +245,7 @@ static bool try_expand_macro(std::set<std::string> &defines_with_args, args.push_back(std::string()); while (1) { + skip_spaces(); tok = next_token(true); if (tok == ")" || tok == "}" || tok == "]") level--; @@ -264,6 +266,9 @@ static bool try_expand_macro(std::set<std::string> &defines_with_args, } insert_input(defines_map[name]); return true; + } else if (tok == "``") { + // Swallow `` in macro expansion + return true; } else return false; } diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index e5917b97e..8dcc7c5aa 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -42,14 +42,14 @@ static std::list<std::vector<std::string>> verilog_defaults_stack; static void error_on_dpi_function(AST::AstNode *node) { if (node->type == AST::AST_DPI_FUNCTION) - log_error("Found DPI function %s at %s:%d.\n", node->str.c_str(), node->filename.c_str(), node->linenum); + log_file_error(node->filename, node->linenum, "Found DPI function %s.\n", node->str.c_str()); for (auto child : node->children) error_on_dpi_function(child); } struct VerilogFrontend : public Frontend { VerilogFrontend() : Frontend("verilog", "read modules from Verilog file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -78,6 +78,9 @@ struct VerilogFrontend : public Frontend { log(" -dump_ast2\n"); log(" dump abstract syntax tree (after simplification)\n"); log("\n"); + log(" -no_dump_ptr\n"); + log(" do not include hex memory addresses in dump (easier to diff dumps)\n"); + log("\n"); log(" -dump_vlog\n"); log(" dump ast as Verilog code (after simplification)\n"); log("\n"); @@ -137,9 +140,13 @@ struct VerilogFrontend : public Frontend { log(" -icells\n"); log(" interpret cell types starting with '$' as internal cell types\n"); log("\n"); - log(" -ignore_redef\n"); + log(" -nooverwrite\n"); log(" ignore re-definitions of modules. (the default behavior is to\n"); - log(" create an error message.)\n"); + log(" create an error message if the existing module is not a black box\n"); + log(" module, and overwrite the existing module otherwise.)\n"); + log("\n"); + log(" -overwrite\n"); + log(" overwrite existing modules with the same name\n"); log("\n"); log(" -defer\n"); log(" only read the abstract syntax tree and defer actual compilation\n"); @@ -176,10 +183,11 @@ struct VerilogFrontend : public Frontend { log("supported by the Yosys Verilog front-end.\n"); log("\n"); } - virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool flag_dump_ast1 = false; bool flag_dump_ast2 = false; + bool flag_no_dump_ptr = false; bool flag_dump_vlog = false; bool flag_dump_rtlil = false; bool flag_nolatches = false; @@ -191,7 +199,8 @@ struct VerilogFrontend : public Frontend { bool flag_nodpi = false; bool flag_noopt = false; bool flag_icells = false; - bool flag_ignore_redef = false; + bool flag_nooverwrite = false; + bool flag_overwrite = false; bool flag_defer = false; std::map<std::string, std::string> defines_map; std::list<std::string> include_dirs; @@ -236,6 +245,10 @@ struct VerilogFrontend : public Frontend { flag_dump_ast2 = true; continue; } + if (arg == "-no_dump_ptr") { + flag_no_dump_ptr = true; + continue; + } if (arg == "-dump_vlog") { flag_dump_vlog = true; continue; @@ -289,8 +302,14 @@ struct VerilogFrontend : public Frontend { flag_icells = true; continue; } - if (arg == "-ignore_redef") { - flag_ignore_redef = true; + if (arg == "-ignore_redef" || arg == "-nooverwrite") { + flag_nooverwrite = true; + flag_overwrite = false; + continue; + } + if (arg == "-overwrite") { + flag_nooverwrite = false; + flag_overwrite = true; continue; } if (arg == "-defer") { @@ -370,7 +389,7 @@ struct VerilogFrontend : public Frontend { if (flag_nodpi) error_on_dpi_function(current_ast); - AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_ignore_redef, flag_defer, default_nettype_wire); + AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); if (!flag_nopp) delete lexin; @@ -384,7 +403,7 @@ struct VerilogFrontend : public Frontend { struct VerilogDefaults : public Pass { VerilogDefaults() : Pass("verilog_defaults", "set default options for read_verilog") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -405,7 +424,7 @@ struct VerilogDefaults : public Pass { log("not imply -clear.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design*) + void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE { if (args.size() < 2) cmd_error(args, 1, "Missing argument."); @@ -442,7 +461,7 @@ struct VerilogDefaults : public Pass { struct VerilogDefines : public Pass { VerilogDefines() : Pass("verilog_defines", "define and undefine verilog defines") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -458,7 +477,7 @@ struct VerilogDefines : public Pass { log(" undefine the preprocessor symbol 'name'\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -508,13 +527,11 @@ void frontend_verilog_yyerror(char const *fmt, ...) va_list ap; char buffer[1024]; char *p = buffer; - p += snprintf(p, buffer + sizeof(buffer) - p, "Parser error in line %s:%d: ", - YOSYS_NAMESPACE_PREFIX AST::current_filename.c_str(), frontend_verilog_yyget_lineno()); va_start(ap, fmt); p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap); va_end(ap); p += snprintf(p, buffer + sizeof(buffer) - p, "\n"); - YOSYS_NAMESPACE_PREFIX log_error("%s", buffer); + YOSYS_NAMESPACE_PREFIX log_file_error(YOSYS_NAMESPACE_PREFIX AST::current_filename, frontend_verilog_yyget_lineno(), + "%s", buffer); exit(1); } - diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 8aa123e1e..83921bf0b 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -42,7 +42,7 @@ #include "kernel/log.h" #include "frontends/verilog/verilog_frontend.h" #include "frontends/ast/ast.h" -#include "verilog_parser.tab.h" +#include "verilog_parser.tab.hh" USING_YOSYS_NAMESPACE using namespace AST; @@ -145,6 +145,9 @@ YOSYS_NAMESPACE_END "endfunction" { return TOK_ENDFUNCTION; } "task" { return TOK_TASK; } "endtask" { return TOK_ENDTASK; } +"specify" { return TOK_SPECIFY; } +"endspecify" { return TOK_ENDSPECIFY; } +"specparam" { return TOK_SPECPARAM; } "package" { SV_KEYWORD(TOK_PACKAGE); } "endpackage" { SV_KEYWORD(TOK_ENDPACKAGE); } "parameter" { return TOK_PARAMETER; } @@ -238,10 +241,18 @@ YOSYS_NAMESPACE_END while (yystr[i]) { if (yystr[i] == '\\' && yystr[i + 1]) { i++; - if (yystr[i] == 'n') + if (yystr[i] == 'a') + yystr[i] = '\a'; + else if (yystr[i] == 'f') + yystr[i] = '\f'; + else if (yystr[i] == 'n') yystr[i] = '\n'; + else if (yystr[i] == 'r') + yystr[i] = '\r'; else if (yystr[i] == 't') yystr[i] = '\t'; + else if (yystr[i] == 'v') + yystr[i] = '\v'; else if ('0' <= yystr[i] && yystr[i] <= '7') { yystr[i] = yystr[i] - '0'; if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') { diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index dfdeabbdb..2389d7d31 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -110,7 +110,7 @@ static void free_attr(std::map<std::string, AstNode*> *al) %token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT %token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC %token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT -%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK +%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM %token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL %token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE %token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED @@ -376,9 +376,10 @@ wire_type: }; wire_type_token_list: - wire_type_token | wire_type_token_list wire_type_token; + wire_type_token | wire_type_token_list wire_type_token | + wire_type_token_io ; -wire_type_token: +wire_type_token_io: TOK_INPUT { astbuf3->is_input = true; } | @@ -388,7 +389,9 @@ wire_type_token: TOK_INOUT { astbuf3->is_input = true; astbuf3->is_output = true; - } | + }; + +wire_type_token: TOK_WIRE { } | TOK_REG { @@ -479,7 +482,7 @@ module_body: /* empty */; module_body_stmt: - task_func_decl | param_decl | localparam_decl | defparam_decl | wire_decl | assign_stmt | cell_stmt | + task_func_decl | specify_block |param_decl | localparam_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt | always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl; checker_decl: @@ -638,6 +641,194 @@ task_func_body: task_func_body behavioral_stmt | /* empty */; +specify_block: + TOK_SPECIFY specify_item_opt TOK_ENDSPECIFY | + TOK_SPECIFY TOK_ENDSPECIFY ; + +specify_item_opt: + specify_item_opt specify_item | + specify_item ; + +specify_item: + specparam_declaration + // | pulsestyle_declaration + // | showcancelled_declaration + | path_declaration + | system_timing_declaration + ; + +specparam_declaration: + TOK_SPECPARAM list_of_specparam_assignments ';' | + TOK_SPECPARAM specparam_range list_of_specparam_assignments ';' ; + +// IEEE 1364-2005 calls this sinmply 'range' but the current 'range' rule allows empty match +// and the 'non_opt_range' rule allows index ranges not allowed by 1364-2005 +// exxxxtending this for SV specparam would change this anyhow +specparam_range: + '[' constant_expression ':' constant_expression ']' ; + +list_of_specparam_assignments: + specparam_assignment | list_of_specparam_assignments ',' specparam_assignment; + +specparam_assignment: + TOK_ID '=' constant_mintypmax_expression ; + +/* +pulsestyle_declaration : + ; + +showcancelled_declaration : + ; +*/ + +path_declaration : + simple_path_declaration ';' + // | edge_sensitive_path_declaration + // | state_dependent_path_declaration + ; + +simple_path_declaration : + parallel_path_description '=' path_delay_value | + full_path_description '=' path_delay_value + ; + +path_delay_value : + '(' path_delay_expression list_of_path_delay_extra_expressions ')' + | path_delay_expression + | path_delay_expression list_of_path_delay_extra_expressions + ; + +list_of_path_delay_extra_expressions : +/* + t_path_delay_expression + | trise_path_delay_expression ',' tfall_path_delay_expression + | trise_path_delay_expression ',' tfall_path_delay_expression ',' tz_path_delay_expression + | t01_path_delay_expression ',' t10_path_delay_expression ',' t0z_path_delay_expression ',' + tz1_path_delay_expression ',' t1z_path_delay_expression ',' tz0_path_delay_expression + | t01_path_delay_expression ',' t10_path_delay_expression ',' t0z_path_delay_expression ',' + tz1_path_delay_expression ',' t1z_path_delay_expression ',' tz0_path_delay_expression ',' + t0x_path_delay_expression ',' tx1_path_delay_expression ',' t1x_path_delay_expression ',' + tx0_path_delay_expression ',' txz_path_delay_expression ',' tzx_path_delay_expression +*/ + ',' path_delay_expression + | ',' path_delay_expression ',' path_delay_expression + | ',' path_delay_expression ',' path_delay_expression ',' + path_delay_expression ',' path_delay_expression ',' path_delay_expression + | ',' path_delay_expression ',' path_delay_expression ',' + path_delay_expression ',' path_delay_expression ',' path_delay_expression ',' + path_delay_expression ',' path_delay_expression ',' path_delay_expression ',' + path_delay_expression ',' path_delay_expression ',' path_delay_expression + ; + +parallel_path_description : + '(' specify_input_terminal_descriptor opt_polarity_operator '=' '>' specify_output_terminal_descriptor ')' ; + +full_path_description : + '(' list_of_path_inputs '*' '>' list_of_path_outputs ')' ; + +// This was broken into 2 rules to solve shift/reduce conflicts +list_of_path_inputs : + specify_input_terminal_descriptor opt_polarity_operator | + specify_input_terminal_descriptor more_path_inputs opt_polarity_operator ; + +more_path_inputs : + ',' specify_input_terminal_descriptor | + more_path_inputs ',' specify_input_terminal_descriptor ; + +list_of_path_outputs : + specify_output_terminal_descriptor | + list_of_path_outputs ',' specify_output_terminal_descriptor ; + +opt_polarity_operator : + '+' + | '-' + | ; + +// Good enough for the time being +specify_input_terminal_descriptor : + TOK_ID ; + +// Good enough for the time being +specify_output_terminal_descriptor : + TOK_ID ; + +system_timing_declaration : + TOK_ID '(' system_timing_args ')' ';' ; + +system_timing_arg : + TOK_POSEDGE TOK_ID | + TOK_NEGEDGE TOK_ID | + expr ; + +system_timing_args : + system_timing_arg | + system_timing_args ',' system_timing_arg ; + +/* +t_path_delay_expression : + path_delay_expression; + +trise_path_delay_expression : + path_delay_expression; + +tfall_path_delay_expression : + path_delay_expression; + +tz_path_delay_expression : + path_delay_expression; + +t01_path_delay_expression : + path_delay_expression; + +t10_path_delay_expression : + path_delay_expression; + +t0z_path_delay_expression : + path_delay_expression; + +tz1_path_delay_expression : + path_delay_expression; + +t1z_path_delay_expression : + path_delay_expression; + +tz0_path_delay_expression : + path_delay_expression; + +t0x_path_delay_expression : + path_delay_expression; + +tx1_path_delay_expression : + path_delay_expression; + +t1x_path_delay_expression : + path_delay_expression; + +tx0_path_delay_expression : + path_delay_expression; + +txz_path_delay_expression : + path_delay_expression; + +tzx_path_delay_expression : + path_delay_expression; +*/ + +path_delay_expression : + constant_expression; + +constant_mintypmax_expression : + constant_expression + | constant_expression ':' constant_expression ':' constant_expression + ; + +// for the time being this is OK, but we may write our own expr here. +// as I'm not sure it is legal to use a full expr here (probably not) +// On the other hand, other rules requiring constant expressions also use 'expr' +// (such as param assignment), so we may leave this as-is, perhaps assing runtime checks for constant-ness +constant_expression: + expr ; + param_signed: TOK_SIGNED { astbuf1->is_signed = true; @@ -772,11 +963,43 @@ wire_name_list: wire_name_and_opt_assign: wire_name { - if (current_wire_rand) { + bool attr_anyconst = false; + bool attr_anyseq = false; + bool attr_allconst = false; + bool attr_allseq = false; + if (ast_stack.back()->children.back()->get_bool_attribute("\\anyconst")) { + delete ast_stack.back()->children.back()->attributes.at("\\anyconst"); + ast_stack.back()->children.back()->attributes.erase("\\anyconst"); + attr_anyconst = true; + } + if (ast_stack.back()->children.back()->get_bool_attribute("\\anyseq")) { + delete ast_stack.back()->children.back()->attributes.at("\\anyseq"); + ast_stack.back()->children.back()->attributes.erase("\\anyseq"); + attr_anyseq = true; + } + if (ast_stack.back()->children.back()->get_bool_attribute("\\allconst")) { + delete ast_stack.back()->children.back()->attributes.at("\\allconst"); + ast_stack.back()->children.back()->attributes.erase("\\allconst"); + attr_allconst = true; + } + if (ast_stack.back()->children.back()->get_bool_attribute("\\allseq")) { + delete ast_stack.back()->children.back()->attributes.at("\\allseq"); + ast_stack.back()->children.back()->attributes.erase("\\allseq"); + attr_allseq = true; + } + if (current_wire_rand || attr_anyconst || attr_anyseq || attr_allconst || attr_allseq) { AstNode *wire = new AstNode(AST_IDENTIFIER); AstNode *fcall = new AstNode(AST_FCALL); wire->str = ast_stack.back()->children.back()->str; fcall->str = current_wire_const ? "\\$anyconst" : "\\$anyseq"; + if (attr_anyconst) + fcall->str = "\\$anyconst"; + if (attr_anyseq) + fcall->str = "\\$anyseq"; + if (attr_allconst) + fcall->str = "\\$allconst"; + if (attr_allseq) + fcall->str = "\\$allseq"; fcall->attributes["\\reg"] = AstNode::mkconst_str(RTLIL::unescape_id(wire->str)); ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, fcall)); } @@ -1044,39 +1267,45 @@ opt_label: $$ = NULL; }; +opt_property: + TOK_PROPERTY | /* empty */; + +opt_stmt_label: + TOK_ID ':' | /* empty */; + assert: - TOK_ASSERT '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $3)); + opt_stmt_label TOK_ASSERT opt_property '(' expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5)); } | - TOK_ASSUME '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $3)); + opt_stmt_label TOK_ASSUME opt_property '(' expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5)); } | - TOK_ASSERT '(' TOK_EVENTUALLY expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $4)); + opt_stmt_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6)); } | - TOK_ASSUME '(' TOK_EVENTUALLY expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $4)); + opt_stmt_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6)); } | - TOK_COVER '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_COVER, $3)); + opt_stmt_label TOK_COVER opt_property '(' expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5)); } | - TOK_COVER '(' ')' ';' { + opt_stmt_label TOK_COVER opt_property '(' ')' ';' { ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false))); } | - TOK_COVER ';' { + opt_stmt_label TOK_COVER ';' { ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false))); } | - TOK_RESTRICT '(' expr ')' ';' { + opt_stmt_label TOK_RESTRICT opt_property '(' expr ')' ';' { if (norestrict_mode) - delete $3; + delete $5; else - ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $3)); + ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5)); } | - TOK_RESTRICT '(' TOK_EVENTUALLY expr ')' ';' { + opt_stmt_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' { if (norestrict_mode) - delete $4; + delete $6; else - ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $4)); + ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6)); }; assert_property: |