diff options
Diffstat (limited to 'frontends/verific')
-rw-r--r-- | frontends/verific/verific.cc | 490 | ||||
-rw-r--r-- | frontends/verific/verific.h | 12 | ||||
-rw-r--r-- | frontends/verific/verificsva.cc | 360 |
3 files changed, 718 insertions, 144 deletions
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 7b5dac309..b8dd72b98 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -62,8 +62,11 @@ using namespace Verific; YOSYS_NAMESPACE_BEGIN int verific_verbose; +bool verific_import_pending; string verific_error_msg; +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) { string message_prefix = stringf("VERIFIC-%s [%s] ", @@ -99,9 +102,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 +126,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 +192,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 +247,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 +399,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 +531,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 +795,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 +872,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 +986,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 +999,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 +1016,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 +1078,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 +1097,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 +1128,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 +1274,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 +1348,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 +1369,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 +1392,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 +1473,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 +1499,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 +1523,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,11 +1616,73 @@ struct VerificExtNets } }; +void verific_import(Design *design, std::string top) +{ + 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() @@ -1536,6 +1693,18 @@ 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(" verific {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl} <vhdl-file>..\n"); log("\n"); @@ -1555,7 +1724,12 @@ 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 -import [options] <top-module>..\n"); @@ -1578,6 +1752,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"); @@ -1609,6 +1786,9 @@ struct VerificPass : public Pass { #ifdef YOSYS_ENABLE_VERIFIC virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { + 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); @@ -1616,8 +1796,12 @@ struct VerificPass : public Pass { 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"); + RuntimeFlags::SetVar("veri_extract_dualport_rams", 0); + RuntimeFlags::SetVar("veri_extract_multiport_rams", 1); + RuntimeFlags::SetVar("db_infer_wide_operators", 1); + + // WARNING: instantiating unknown module 'XYZ' (VERI-1063) + Message::SetMessageType("VERI-1063", VERIFIC_ERROR); verific_verbose = 0; @@ -1637,13 +1821,13 @@ struct VerificPass : public Pass { 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,38 +1846,65 @@ 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; - } + 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] == "-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; - } + veri_file::DefineMacro("VERIFIC"); + veri_file::DefineMacro(args[argidx] == "-formal" ? "FORMAL" : "SYNTHESIS"); - 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; - } + 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()); + } + } - 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 (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", veri_file::MFCU)) + log_cmd_error("Reading Verilog/SystemVerilog sources failed.\n"); + + verific_import_pending = true; goto check_error; } @@ -1702,6 +1913,7 @@ struct VerificPass : public Pass { for (argidx++; argidx < GetSize(args); argidx++) if (!vhdl_file::Analyze(args[argidx].c_str(), "work", 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; } @@ -1710,6 +1922,7 @@ struct VerificPass : public Pass { for (argidx++; argidx < GetSize(args); argidx++) if (!vhdl_file::Analyze(args[argidx].c_str(), "work", 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; } @@ -1718,6 +1931,7 @@ struct VerificPass : public Pass { for (argidx++; argidx < GetSize(args); argidx++) if (!vhdl_file::Analyze(args[argidx].c_str(), "work", 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; } @@ -1726,6 +1940,7 @@ struct VerificPass : public Pass { for (argidx++; argidx < GetSize(args); argidx++) if (!vhdl_file::Analyze(args[argidx].c_str(), "work", 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 +1949,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; @@ -1766,6 +1982,10 @@ struct VerificPass : public Pass { mode_names = true; continue; } + if (args[argidx] == "-autocover") { + mode_autocover = true; + continue; + } if (args[argidx] == "-V") { mode_verific = true; continue; @@ -1898,6 +2118,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 +2141,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 +2151,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; } @@ -1945,5 +2171,133 @@ struct VerificPass : public Pass { #endif } VerificPass; -PRIVATE_NAMESPACE_END +struct ReadPass : public Pass { + ReadPass() : Pass("read", "load HDL designs") { } + virtual void help() + { + // |---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"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + { + 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..cbd9314db 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); diff --git a/frontends/verific/verificsva.cc b/frontends/verific/verificsva.cc index 5abe0eb35..85b842186 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" @@ -942,7 +980,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 +1137,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 +1272,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 +1308,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 +1486,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 +1667,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 +1739,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 |