aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md3
-rw-r--r--frontends/verific/verific.cc120
-rw-r--r--frontends/verilog/Makefile.inc2
-rw-r--r--passes/cmds/rename.cc32
-rw-r--r--passes/hierarchy/uniquify.cc2
-rw-r--r--passes/memory/memory_bram.cc26
-rw-r--r--passes/sat/Makefile.inc1
-rw-r--r--passes/sat/cutpoint.cc168
-rw-r--r--passes/techmap/libparse.cc177
-rw-r--r--passes/techmap/libparse.h10
-rw-r--r--tests/liberty/.gitignore2
-rw-r--r--tests/liberty/busdef.lib81
-rw-r--r--tests/liberty/normal.lib359
-rw-r--r--tests/liberty/processdefs.lib48
-rwxr-xr-xtests/liberty/run-test.sh10
-rw-r--r--tests/liberty/semicolextra.lib48
-rw-r--r--tests/liberty/semicolmissing.lib72
-rw-r--r--tests/liberty/small.v16
-rw-r--r--tests/sva/extnets.sv22
19 files changed, 1137 insertions, 62 deletions
diff --git a/README.md b/README.md
index c5cd47707..4048ecbc7 100644
--- a/README.md
+++ b/README.md
@@ -315,6 +315,9 @@ Verilog Attributes and non-standard features
- The ``dynports'' attribute is used by the Verilog front-end to mark modules
that have ports with a width that depends on a parameter.
+- The ``hdlname'' attribute is used by some passes to document the original
+ (HDL) name of a module when renaming a module.
+
- The ``keep`` attribute on cells and wires is used to mark objects that should
never be removed by the optimizer. This is used for example for cells that
have hidden connections that are not part of the netlist, such as IO pads.
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index c412cd3a3..ed9727b88 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -1619,30 +1619,35 @@ struct VerificExtNets
int portname_cnt = 0;
// a map from Net to the same Net one level up in the design hierarchy
- std::map<Net*, Net*> net_level_up;
+ std::map<Net*, Net*> net_level_up_drive_up;
+ std::map<Net*, Net*> net_level_up_drive_down;
- Net *get_net_level_up(Net *net)
+ Net *route_up(Net *net, bool drive_up, Net *final_net = nullptr)
{
+ auto &net_level_up = drive_up ? net_level_up_drive_up : net_level_up_drive_down;
+
if (net_level_up.count(net) == 0)
{
Netlist *nl = net->Owner();
// Simply return if Netlist is not unique
- if (nl->NumOfRefs() != 1)
- return net;
+ log_assert(nl->NumOfRefs() == 1);
Instance *up_inst = (Instance*)nl->GetReferences()->GetLast();
Netlist *up_nl = up_inst->Owner();
// create new Port
string name = stringf("___extnets_%d", portname_cnt++);
- Port *new_port = new Port(name.c_str(), DIR_OUT);
+ Port *new_port = new Port(name.c_str(), drive_up ? DIR_OUT : DIR_IN);
nl->Add(new_port);
net->Connect(new_port);
// create new Net in up Netlist
- Net *new_net = new Net(name.c_str());
- up_nl->Add(new_net);
+ Net *new_net = final_net;
+ if (new_net == nullptr || new_net->Owner() != up_nl) {
+ new_net = new Net(name.c_str());
+ up_nl->Add(new_net);
+ }
up_inst->Connect(new_port, new_net);
net_level_up[net] = new_net;
@@ -1651,6 +1656,39 @@ struct VerificExtNets
return net_level_up.at(net);
}
+ Net *route_up(Net *net, bool drive_up, Netlist *dest, Net *final_net = nullptr)
+ {
+ while (net->Owner() != dest)
+ net = route_up(net, drive_up, final_net);
+ if (final_net != nullptr)
+ log_assert(net == final_net);
+ return net;
+ }
+
+ Netlist *find_common_ancestor(Netlist *A, Netlist *B)
+ {
+ std::set<Netlist*> ancestors_of_A;
+
+ Netlist *cursor = A;
+ while (1) {
+ ancestors_of_A.insert(cursor);
+ if (cursor->NumOfRefs() != 1)
+ break;
+ cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner();
+ }
+
+ cursor = B;
+ while (1) {
+ if (ancestors_of_A.count(cursor))
+ return cursor;
+ if (cursor->NumOfRefs() != 1)
+ break;
+ cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner();
+ }
+
+ log_error("No common ancestor found between %s and %s.\n", get_full_netlist_name(A).c_str(), get_full_netlist_name(B).c_str());
+ }
+
void run(Netlist *nl)
{
MapIter mi, mi2;
@@ -1674,19 +1712,37 @@ struct VerificExtNets
if (verific_verbose)
log("Fixing external net reference on port %s.%s.%s:\n", get_full_netlist_name(nl).c_str(), inst->Name(), port->Name());
- while (net->IsExternalTo(nl))
- {
- Net *newnet = get_net_level_up(net);
- if (newnet == net) break;
+ Netlist *ext_nl = net->Owner();
+
+ if (verific_verbose)
+ log(" external net owner: %s\n", get_full_netlist_name(ext_nl).c_str());
+
+ Netlist *ca_nl = find_common_ancestor(nl, ext_nl);
+
+ if (verific_verbose)
+ log(" common ancestor: %s\n", get_full_netlist_name(ca_nl).c_str());
+ Net *ca_net = route_up(net, !port->IsOutput(), ca_nl);
+ Net *new_net = ca_net;
+
+ if (ca_nl != nl)
+ {
if (verific_verbose)
- log(" external net: %s.%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name());
- net = newnet;
+ log(" net in common ancestor: %s\n", ca_net->Name());
+
+ string name = stringf("___extnets_%d", portname_cnt++);
+ new_net = new Net(name.c_str());
+ nl->Add(new_net);
+
+ Net *n = route_up(new_net, port->IsOutput(), ca_nl, ca_net);
+ log_assert(n == ca_net);
}
if (verific_verbose)
- log(" final net: %s.%s%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name(), net->IsExternalTo(nl) ? " (external)" : "");
- todo_connect.push_back(tuple<Instance*, Port*, Net*>(inst, port, net));
+ log(" new local net: %s\n", new_net->Name());
+
+ log_assert(!new_net->IsExternalTo(nl));
+ todo_connect.push_back(tuple<Instance*, Port*, Net*>(inst, port, new_net));
}
for (auto it : todo_connect) {
@@ -2330,21 +2386,43 @@ struct ReadPass : public Pass {
log("\n");
log("Add directory to global Verilog/SystemVerilog include directories.\n");
log("\n");
+ log("\n");
+ log(" read -verific\n");
+ log(" read -noverific\n");
+ log("\n");
+ log("Subsequent calls to 'read' will either use or not use Verific. Calling 'read'\n");
+ log("with -verific will result in an error on Yosys binaries that are built without\n");
+ log("Verific support. The default is to use Verific if it is available.\n");
+ log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
+#ifdef YOSYS_ENABLE_VERIFIC
+ static bool verific_available = !check_noverific_env();
+#else
+ static bool verific_available = false;
+#endif
+ static bool use_verific = verific_available;
+
if (args.size() < 2 || args[1][0] != '-')
log_cmd_error("Missing mode parameter.\n");
+ if (args[1] == "-verific" || args[1] == "-noverific") {
+ if (args.size() != 2)
+ log_cmd_error("Additional arguments to -verific/-noverific.\n");
+ if (args[1] == "-verific") {
+ if (!verific_available)
+ log_cmd_error("This version of Yosys is built without Verific support.\n");
+ use_verific = true;
+ } else {
+ use_verific = false;
+ }
+ return;
+ }
+
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";
diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc
index dbaace585..0a1f97ac0 100644
--- a/frontends/verilog/Makefile.inc
+++ b/frontends/verilog/Makefile.inc
@@ -14,6 +14,8 @@ frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l
$(Q) mkdir -p $(dir $@)
$(P) flex -o frontends/verilog/verilog_lexer.cc $<
+frontends/verilog/verilog_parser.tab.o: CXXFLAGS += -DYYMAXDEPTH=100000
+
OBJS += frontends/verilog/verilog_parser.tab.o
OBJS += frontends/verilog/verilog_lexer.o
OBJS += frontends/verilog/preproc.o
diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc
index 698ce7235..9b1830b7b 100644
--- a/passes/cmds/rename.cc
+++ b/passes/cmds/rename.cc
@@ -24,7 +24,7 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-static void rename_in_module(RTLIL::Module *module, std::string from_name, std::string to_name)
+static void rename_in_module(RTLIL::Module *module, std::string from_name, std::string to_name, bool flag_output)
{
from_name = RTLIL::escape_id(from_name);
to_name = RTLIL::escape_id(to_name);
@@ -37,13 +37,18 @@ static void rename_in_module(RTLIL::Module *module, std::string from_name, std::
Wire *w = it.second;
log("Renaming wire %s to %s in module %s.\n", log_id(w), log_id(to_name), log_id(module));
module->rename(w, to_name);
- if (w->port_id)
+ if (w->port_id || flag_output) {
+ if (flag_output)
+ w->port_output = true;
module->fixup_ports();
+ }
return;
}
for (auto &it : module->cells_)
if (it.first == from_name) {
+ if (flag_output)
+ log_cmd_error("Called with -output but the specified object is a cell.\n");
log("Renaming cell %s to %s in module %s.\n", log_id(it.second), log_id(to_name), log_id(module));
module->rename(it.second, to_name);
return;
@@ -108,15 +113,26 @@ struct RenamePass : public Pass {
log("Rename the specified object. Note that selection patterns are not supported\n");
log("by this command.\n");
log("\n");
+ log("\n");
+ log("\n");
+ log(" rename -output old_name new_name\n");
+ log("\n");
+ log("Like above, but also make the wire an output. This will fail if the object is\n");
+ log("not a wire.\n");
+ log("\n");
+ log("\n");
log(" rename -src [selection]\n");
log("\n");
log("Assign names auto-generated from the src attribute to all selected wires and\n");
log("cells with private names.\n");
log("\n");
+ log("\n");
log(" rename -wire [selection]\n");
+ log("\n");
log("Assign auto-generated names based on the wires they drive to all selected\n");
log("cells with private names. Ignores cells driving privatly named wires.\n");
log("\n");
+ log("\n");
log(" rename -enumerate [-pattern <pattern>] [selection]\n");
log("\n");
log("Assign short auto-generated names to all selected wires and cells with private\n");
@@ -124,11 +140,13 @@ struct RenamePass : public Pass {
log("The character %% in the pattern is replaced with a integer number. The default\n");
log("pattern is '_%%_'.\n");
log("\n");
+ log("\n");
log(" rename -hide [selection]\n");
log("\n");
log("Assign private names (the ones with $-prefix) to all selected wires and cells\n");
log("with public names. This ignores all selected ports.\n");
log("\n");
+ log("\n");
log(" rename -top new_name\n");
log("\n");
log("Rename top module.\n");
@@ -142,6 +160,7 @@ struct RenamePass : public Pass {
bool flag_enumerate = false;
bool flag_hide = false;
bool flag_top = false;
+ bool flag_output = false;
bool got_mode = false;
size_t argidx;
@@ -153,6 +172,11 @@ struct RenamePass : public Pass {
got_mode = true;
continue;
}
+ if (arg == "-output" && !got_mode) {
+ flag_output = true;
+ got_mode = true;
+ continue;
+ }
if (arg == "-wire" && !got_mode) {
flag_wire = true;
got_mode = true;
@@ -322,10 +346,12 @@ struct RenamePass : public Pass {
if (!design->selected_active_module.empty())
{
if (design->modules_.count(design->selected_active_module) > 0)
- rename_in_module(design->modules_.at(design->selected_active_module), from_name, to_name);
+ rename_in_module(design->modules_.at(design->selected_active_module), from_name, to_name, flag_output);
}
else
{
+ if (flag_output)
+ log_cmd_error("Mode -output requires that there is an active module selected.\n");
for (auto &mod : design->modules_) {
if (mod.first == from_name || RTLIL::unescape_id(mod.first) == from_name) {
to_name = RTLIL::escape_id(to_name);
diff --git a/passes/hierarchy/uniquify.cc b/passes/hierarchy/uniquify.cc
index c88ecd82e..e6154e94f 100644
--- a/passes/hierarchy/uniquify.cc
+++ b/passes/hierarchy/uniquify.cc
@@ -87,6 +87,8 @@ struct UniquifyPass : public Pass {
smod->name = newname;
cell->type = newname;
smod->set_bool_attribute("\\unique");
+ if (smod->attributes.count("\\hdlname") == 0)
+ smod->attributes["\\hdlname"] = string(log_id(tmod->name));
design->add(smod);
did_something = true;
diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc
index cf4095d06..85ed1c053 100644
--- a/passes/memory/memory_bram.cc
+++ b/passes/memory/memory_bram.cc
@@ -542,7 +542,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
}
// assign write ports
-
+ pair<SigBit, bool> wr_clkdom;
for (int cell_port_i = 0, bram_port_i = 0; cell_port_i < wr_ports; cell_port_i++)
{
bool clken = wr_clken[cell_port_i] == State::S1;
@@ -552,7 +552,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
pair<SigBit, bool> clkdom(clksig, clkpol);
if (!clken)
clkdom = pair<SigBit, bool>(State::S1, false);
-
+ wr_clkdom = clkdom;
log(" Write port #%d is in clock domain %s%s.\n",
cell_port_i, clkdom.second ? "" : "!",
clken ? log_signal(clkdom.first) : "~async~");
@@ -641,6 +641,7 @@ grow_read_ports:;
pi.sig_data = SigSpec();
pi.sig_en = SigSpec();
pi.make_outreg = false;
+ pi.make_transp = false;
}
new_portinfos.push_back(pi);
if (pi.dupidx == dup_count-1) {
@@ -718,7 +719,13 @@ grow_read_ports:;
if (read_transp.count(pi.transp) && read_transp.at(pi.transp) != transp) {
if (match.make_transp && wr_ports <= 1) {
pi.make_transp = true;
- enable_make_transp = true;
+ if (pi.clocks != 0) {
+ if (wr_ports == 1 && wr_clkdom != clkdom) {
+ log(" Bram port %c%d.%d cannot have soft transparency logic added as read and write clock domains differ.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
+ goto skip_bram_rport;
+ }
+ enable_make_transp = true;
+ }
} else {
log(" Bram port %c%d.%d has incompatible read transparency.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
goto skip_bram_rport;
@@ -913,17 +920,18 @@ grow_read_ports:;
} else {
SigSpec bram_dout = module->addWire(NEW_ID, bram.dbits);
c->setPort(stringf("\\%sDATA", pf), bram_dout);
-
- if (pi.make_outreg) {
+ if (pi.make_outreg && pi.make_transp) {
+ log(" Moving output register to address for transparent port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
+ SigSpec sig_addr_q = module->addWire(NEW_ID, bram.abits);
+ module->addDff(NEW_ID, pi.sig_clock, sig_addr, sig_addr_q, pi.effective_clkpol);
+ c->setPort(stringf("\\%sADDR", pf), sig_addr_q);
+ } else if (pi.make_outreg) {
SigSpec bram_dout_q = module->addWire(NEW_ID, bram.dbits);
if (!pi.sig_en.empty())
bram_dout = module->Mux(NEW_ID, bram_dout_q, bram_dout, pi.sig_en);
module->addDff(NEW_ID, pi.sig_clock, bram_dout, bram_dout_q, pi.effective_clkpol);
bram_dout = bram_dout_q;
- }
-
- if (pi.make_transp)
- {
+ } else if (pi.make_transp) {
log(" Adding extra logic for transparent port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
SigSpec transp_en_d = module->Mux(NEW_ID, SigSpec(0, make_transp_enbits),
diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc
index 4eced2ff1..fc3ac879e 100644
--- a/passes/sat/Makefile.inc
+++ b/passes/sat/Makefile.inc
@@ -11,4 +11,5 @@ OBJS += passes/sat/async2sync.o
OBJS += passes/sat/supercover.o
OBJS += passes/sat/fmcombine.o
OBJS += passes/sat/mutate.o
+OBJS += passes/sat/cutpoint.o
diff --git a/passes/sat/cutpoint.cc b/passes/sat/cutpoint.cc
new file mode 100644
index 000000000..048aec7f3
--- /dev/null
+++ b/passes/sat/cutpoint.cc
@@ -0,0 +1,168 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct CutpointPass : public Pass {
+ CutpointPass() : Pass("cutpoint", "add hi/lo cover cells for each wire bit") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" cutpoint [options] [selection]\n");
+ log("\n");
+ log("This command adds formal cut points to the design.\n");
+ log("\n");
+ log(" -undef\n");
+ log(" set cupoint nets to undef (x). the default behavior is to create a\n");
+ log(" $anyseq cell and drive the cutpoint net from that\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ bool flag_undef = false;
+
+ log_header(design, "Executing CUTPOINT pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-undef") {
+ flag_undef = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ if (design->selected_whole_module(module->name)) {
+ log("Making all outputs of module %s cut points, removing module contents.\n", log_id(module));
+ module->new_connections(std::vector<RTLIL::SigSig>());
+ for (auto cell : vector<Cell*>(module->cells()))
+ module->remove(cell);
+ vector<Wire*> output_wires;
+ for (auto wire : module->wires())
+ if (wire->port_output)
+ output_wires.push_back(wire);
+ for (auto wire : output_wires)
+ module->connect(wire, flag_undef ? Const(State::Sx, GetSize(wire)) : module->Anyseq(NEW_ID, GetSize(wire)));
+ continue;
+ }
+
+ SigMap sigmap(module);
+ pool<SigBit> cutpoint_bits;
+
+ for (auto cell : module->selected_cells()) {
+ if (cell->type == "$anyseq")
+ continue;
+ log("Removing cell %s.%s, making all cell outputs cutpoints.\n", log_id(module), log_id(cell));
+ for (auto &conn : cell->connections()) {
+ if (cell->output(conn.first))
+ module->connect(conn.second, flag_undef ? Const(State::Sx, GetSize(conn.second)) : module->Anyseq(NEW_ID, GetSize(conn.second)));
+ }
+ module->remove(cell);
+ }
+
+ for (auto wire : module->selected_wires()) {
+ if (wire->port_output) {
+ log("Making output wire %s.%s a cutpoint.\n", log_id(module), log_id(wire));
+ Wire *new_wire = module->addWire(NEW_ID, wire);
+ module->swap_names(wire, new_wire);
+ module->connect(new_wire, flag_undef ? Const(State::Sx, GetSize(new_wire)) : module->Anyseq(NEW_ID, GetSize(new_wire)));
+ wire->port_id = 0;
+ wire->port_input = false;
+ wire->port_output = false;
+ continue;
+ }
+ log("Making wire %s.%s a cutpoint.\n", log_id(module), log_id(wire));
+ for (auto bit : sigmap(wire))
+ cutpoint_bits.insert(bit);
+ }
+
+ if (!cutpoint_bits.empty())
+ {
+ for (auto cell : module->cells()) {
+ for (auto &conn : cell->connections()) {
+ if (!cell->output(conn.first))
+ continue;
+ SigSpec sig = sigmap(conn.second);
+ int bit_count = 0;
+ for (auto &bit : sig) {
+ if (cutpoint_bits.count(bit))
+ bit_count++;
+ }
+ if (bit_count == 0)
+ continue;
+ SigSpec dummy = module->addWire(NEW_ID, bit_count);
+ bit_count = 0;
+ for (auto &bit : sig) {
+ if (cutpoint_bits.count(bit))
+ bit = dummy[bit_count++];
+ }
+ cell->setPort(conn.first, sig);
+ }
+ }
+
+ vector<Wire*> rewrite_wires;
+ for (auto wire : module->wires()) {
+ if (!wire->port_input)
+ continue;
+ int bit_count = 0;
+ for (auto &bit : sigmap(wire))
+ if (cutpoint_bits.count(bit))
+ bit_count++;
+ if (bit_count)
+ rewrite_wires.push_back(wire);
+ }
+
+ for (auto wire : rewrite_wires) {
+ Wire *new_wire = module->addWire(NEW_ID, wire);
+ SigSpec lhs, rhs, sig = sigmap(wire);
+ for (int i = 0; i < GetSize(sig); i++)
+ if (!cutpoint_bits.count(sig[i])) {
+ lhs.append(SigBit(wire, i));
+ rhs.append(SigBit(new_wire, i));
+ }
+ if (GetSize(lhs))
+ module->connect(lhs, rhs);
+ module->swap_names(wire, new_wire);
+ wire->port_id = 0;
+ wire->port_input = false;
+ wire->port_output = false;
+ }
+
+ SigSpec sig(cutpoint_bits);
+ sig.sort_and_unify();
+
+ for (auto chunk : sig.chunks()) {
+ SigSpec s(chunk);
+ module->connect(s, flag_undef ? Const(State::Sx, GetSize(s)) : module->Anyseq(NEW_ID, GetSize(s)));
+ }
+ }
+ }
+ }
+} CutpointPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc
index 3927a657b..991cc4498 100644
--- a/passes/techmap/libparse.cc
+++ b/passes/techmap/libparse.cc
@@ -24,6 +24,7 @@
#include <istream>
#include <fstream>
#include <iostream>
+#include <sstream>
#ifndef FILTERLIB
#include "kernel/log.h"
@@ -86,15 +87,17 @@ int LibertyParser::lexer(std::string &str)
{
int c;
+ // eat whitespace
do {
c = f.get();
} while (c == ' ' || c == '\t' || c == '\r');
- if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.' || c == '[' || c == ']') {
+ // search for identifiers, numbers, plus or minus.
+ if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') {
str = c;
while (1) {
c = f.get();
- if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.' || c == '[' || c == ']')
+ if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.')
str += c;
else
break;
@@ -111,6 +114,8 @@ int LibertyParser::lexer(std::string &str)
}
}
+ // if it wasn't an identifer, number of array range,
+ // maybe it's a string?
if (c == '"') {
str = "";
while (1) {
@@ -125,9 +130,10 @@ int LibertyParser::lexer(std::string &str)
return 'v';
}
+ // if it wasn't a string, perhaps it's a comment or a forward slash?
if (c == '/') {
c = f.get();
- if (c == '*') {
+ if (c == '*') { // start of '/*' block comment
int last_c = 0;
while (c > 0 && (last_c != '*' || c != '/')) {
last_c = c;
@@ -136,7 +142,7 @@ int LibertyParser::lexer(std::string &str)
line++;
}
return lexer(str);
- } else if (c == '/') {
+ } else if (c == '/') { // start of '//' line comment
while (c > 0 && c != '\n')
c = f.get();
line++;
@@ -144,24 +150,31 @@ int LibertyParser::lexer(std::string &str)
}
f.unget();
// fprintf(stderr, "LEX: char >>/<<\n");
- return '/';
+ return '/'; // a single '/' charater.
}
+ // check for a backslash
if (c == '\\') {
- c = f.get();
+ c = f.get();
if (c == '\r')
c = f.get();
- if (c == '\n')
+ if (c == '\n') {
+ line++;
return lexer(str);
+ }
f.unget();
return '\\';
}
+ // check for a new line
if (c == '\n') {
line++;
return 'n';
}
+ // anything else, such as ';' will get passed
+ // through as literal items.
+
// if (c >= 32 && c < 255)
// fprintf(stderr, "LEX: char >>%c<<\n", c);
// else
@@ -175,14 +188,39 @@ LibertyAst *LibertyParser::parse()
int tok = lexer(str);
- while (tok == 'n')
+ // there are liberty files in the wild that
+ // have superfluous ';' at the end of
+ // a { ... }. We simply ignore a ';' here.
+ // and get to the next statement.
+
+ while ((tok == 'n') || (tok == ';'))
tok = lexer(str);
if (tok == '}' || tok < 0)
return NULL;
- if (tok != 'v')
- error();
+ if (tok != 'v') {
+ std::string eReport;
+ switch(tok)
+ {
+ case 'n':
+ error("Unexpected newline.");
+ break;
+ case '[':
+ case ']':
+ case '}':
+ case '{':
+ case '\"':
+ case ':':
+ eReport = "Unexpected '";
+ eReport += static_cast<char>(tok);
+ eReport += "'.";
+ error(eReport);
+ break;
+ default:
+ error();
+ }
+ }
LibertyAst *ast = new LibertyAst;
ast->id = str;
@@ -191,12 +229,11 @@ LibertyAst *LibertyParser::parse()
{
tok = lexer(str);
- if (tok == ';')
+ // allow both ';' and new lines to
+ // terminate a statement.
+ if ((tok == ';') || (tok == 'n'))
break;
- if (tok == 'n')
- continue;
-
if (tok == ':' && ast->value.empty()) {
tok = lexer(ast->value);
if (tok != 'v')
@@ -210,7 +247,12 @@ LibertyAst *LibertyParser::parse()
ast->value += str;
tok = lexer(str);
}
- if (tok == ';')
+
+ // In a liberty file, all key : value pairs should end in ';'
+ // However, there are some liberty files in the wild that
+ // just have a newline. We'll be kind and accept a newline
+ // instead of the ';' too..
+ if ((tok == ';') || (tok == 'n'))
break;
else
error();
@@ -225,8 +267,70 @@ LibertyAst *LibertyParser::parse()
continue;
if (tok == ')')
break;
- if (tok != 'v')
- error();
+
+ // FIXME: the AST needs to be extended to store
+ // these vector ranges.
+ if (tok == '[')
+ {
+ // parse vector range [A] or [A:B]
+ std::string arg;
+ tok = lexer(arg);
+ if (tok != 'v')
+ {
+ // expected a vector array index
+ error("Expected a number.");
+ }
+ else
+ {
+ // fixme: check for number A
+ }
+ tok = lexer(arg);
+ // optionally check for : in case of [A:B]
+ // if it isn't we just expect ']'
+ // as we have [A]
+ if (tok == ':')
+ {
+ tok = lexer(arg);
+ if (tok != 'v')
+ {
+ // expected a vector array index
+ error("Expected a number.");
+ }
+ else
+ {
+ // fixme: check for number B
+ tok = lexer(arg);
+ }
+ }
+ // expect a closing bracket of array range
+ if (tok != ']')
+ {
+ error("Expected ']' on array range.");
+ }
+ continue;
+ }
+ if (tok != 'v') {
+ std::string eReport;
+ switch(tok)
+ {
+ case 'n':
+ error("Unexpected newline.");
+ break;
+ case '[':
+ case ']':
+ case '}':
+ case '{':
+ case '\"':
+ case ':':
+ eReport = "Unexpected '";
+ eReport += static_cast<char>(tok);
+ eReport += "'.";
+ error(eReport);
+ break;
+ default:
+ error();
+ }
+ }
ast->args.push_back(arg);
}
continue;
@@ -255,6 +359,14 @@ void LibertyParser::error()
log_error("Syntax error in liberty file on line %d.\n", line);
}
+void LibertyParser::error(const std::string &str)
+{
+ std::stringstream ss;
+ ss << "Syntax error in liberty file on line " << line << ".\n";
+ ss << " " << str << "\n";
+ log_error("%s", ss.str().c_str());
+}
+
#else
void LibertyParser::error()
@@ -263,25 +375,34 @@ void LibertyParser::error()
exit(1);
}
+void LibertyParser::error(const std::string &str)
+{
+ std::stringstream ss;
+ ss << "Syntax error in liberty file on line " << line << ".\n";
+ ss << " " << str << "\n";
+ printf("%s", ss.str().c_str());
+ exit(1);
+}
+
/**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/
#define CHECK_NV(result, check) \
do { \
- auto _R = (result); \
- if (!(_R check)) { \
- fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \
- #result, (long int)_R, #check, __FILE__, __LINE__); \
- abort(); \
- } \
+ auto _R = (result); \
+ if (!(_R check)) { \
+ fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \
+ #result, (long int)_R, #check, __FILE__, __LINE__); \
+ abort(); \
+ } \
} while(0)
#define CHECK_COND(result) \
do { \
- if (!(result)) { \
- fprintf(stderr, "Error from '%s' in %s:%d.\n", \
- #result, __FILE__, __LINE__); \
- abort(); \
- } \
+ if (!(result)) { \
+ fprintf(stderr, "Error from '%s' in %s:%d.\n", \
+ #result, __FILE__, __LINE__); \
+ abort(); \
+ } \
} while(0)
/**** END: http://svn.clifford.at/tools/trunk/examples/check.h ****/
diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h
index cf6325570..c9ebd06c5 100644
--- a/passes/techmap/libparse.h
+++ b/passes/techmap/libparse.h
@@ -46,9 +46,17 @@ namespace Yosys
LibertyAst *ast;
LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {}
~LibertyParser() { if (ast) delete ast; }
+
+ /* lexer return values:
+ 'v': identifier, string, array range [...] -> str holds the token string
+ 'n': newline
+ anything else is a single character.
+ */
int lexer(std::string &str);
- LibertyAst *parse();
+
+ LibertyAst *parse();
void error();
+ void error(const std::string &str);
};
}
diff --git a/tests/liberty/.gitignore b/tests/liberty/.gitignore
new file mode 100644
index 000000000..e6ec49c4a
--- /dev/null
+++ b/tests/liberty/.gitignore
@@ -0,0 +1,2 @@
+*.log
+test.ys
diff --git a/tests/liberty/busdef.lib b/tests/liberty/busdef.lib
new file mode 100644
index 000000000..b5e3d50b9
--- /dev/null
+++ b/tests/liberty/busdef.lib
@@ -0,0 +1,81 @@
+/********************************************/
+/* */
+/* Supergate cell library for Bench marking */
+/* */
+/* Symbiotic EDA GmbH / Moseley Instruments */
+/* Niels A. Moseley */
+/* */
+/* Process: none */
+/* */
+/* Date : 02-11-2018 */
+/* Version: 1.0 */
+/* */
+/********************************************/
+
+library(supergate) {
+ technology (cmos);
+ revision : 1.0;
+
+ time_unit : "1ps";
+ pulling_resistance_unit : "1kohm";
+ voltage_unit : "1V";
+ current_unit : "1uA";
+
+ capacitive_load_unit(1,ff);
+
+ default_inout_pin_cap : 7.0;
+ default_input_pin_cap : 7.0;
+ default_output_pin_cap : 0.0;
+ default_fanout_load : 1.0;
+
+ default_wire_load_capacitance : 0.1;
+ default_wire_load_resistance : 1.0e-3;
+ default_wire_load_area : 0.0;
+
+ nom_process : 1.0;
+ nom_temperature : 25.0;
+ nom_voltage : 1.2;
+
+ delay_model : generic_cmos;
+
+ type( IO_bus_3_to_0 ) {
+ base_type : array ;
+ data_type : bit ;
+ bit_width : 4;
+ bit_from : 3 ;
+ bit_to : 0 ;
+ downto : true ;
+ }
+
+ cell (SRAM) {
+ area : 1 ;
+ memory() {
+ type : ram;
+ address_width : 4;
+ word_width : 4;
+ }
+ pin(CE1) {
+ direction : input;
+ capacitance : 0.021;
+ max_transition : 1.024;
+ switch_pin : true;
+ }
+ bus(I1) {
+ bus_type : IO_bus_3_to_0 ;
+ direction : input;
+ pin (I1[3:0]) {
+ timing() {
+ related_pin : "CE1" ;
+ timing_type : setup_rising ;
+ rise_constraint (scalar) {
+ values("0.0507786");
+ }
+ fall_constraint (scalar) {
+ values("0.0507786");
+ }
+ }
+ }
+ }
+ }
+
+} /* end */
diff --git a/tests/liberty/normal.lib b/tests/liberty/normal.lib
new file mode 100644
index 000000000..4621194dd
--- /dev/null
+++ b/tests/liberty/normal.lib
@@ -0,0 +1,359 @@
+/********************************************/
+/* */
+/* Supergate cell library for Bench marking */
+/* */
+/* Symbiotic EDA GmbH / Moseley Instruments */
+/* Niels A. Moseley */
+/* */
+/* Process: none */
+/* */
+/* Date : 02-11-2018 */
+/* Version: 1.0 */
+/* */
+/********************************************/
+
+library(supergate) {
+ technology (cmos);
+ revision : 1.0;
+
+ time_unit : "1ps";
+ pulling_resistance_unit : "1kohm";
+ voltage_unit : "1V";
+ current_unit : "1uA";
+
+ capacitive_load_unit(1,ff);
+
+ default_inout_pin_cap : 7.0;
+ default_input_pin_cap : 7.0;
+ default_output_pin_cap : 0.0;
+ default_fanout_load : 1.0;
+
+ default_wire_load_capacitance : 0.1;
+ default_wire_load_resistance : 1.0e-3;
+ default_wire_load_area : 0.0;
+
+ nom_process : 1.0;
+ nom_temperature : 25.0;
+ nom_voltage : 1.2;
+
+ delay_model : generic_cmos;
+
+ /* Inverter */
+ cell (inv) {
+ area : 1;
+ pin(A) {
+ direction : input;
+ }
+
+ pin(Y) {
+ direction : output;
+ function : "A'";
+ }
+ }
+
+ /* tri-state inverter */
+ cell (tri_inv) {
+ area : 4;
+ pin(A) {
+ direction : input;
+ }
+ pin(S) {
+ direction : input;
+ }
+ pin(Z) {
+ direction : output;
+ function : "A'";
+ three_State : "S'";
+ }
+ }
+
+ cell (buffer) {
+ area : 5;
+ pin(A) {
+ direction : input;
+ }
+ pin(Y) {
+ direction : output;
+ function : "A";
+ }
+ }
+
+ /* 2-input NAND gate */
+ cell (nand2) {
+ area : 3;
+ pin(A) {
+ direction : input;
+ }
+ pin(B) {
+ direction : input;
+ }
+ pin(Y) {
+ direction: output;
+ function : "(A * B)'";
+ }
+ }
+
+ /* 2-input NOR gate */
+ cell (nor2) {
+ area : 3;
+ pin(A) {
+ direction : input;
+ }
+ pin(B) {
+ direction : input;
+ }
+ pin(Y) {
+ direction: output;
+ function : "(A + B)'";
+ }
+ }
+
+ /* 2-input XOR */
+ cell (xor2) {
+ area : 6;
+ pin(A) {
+ direction : input;
+ }
+ pin(B) {
+ direction : input;
+ }
+ pin(Y) {
+ direction: output;
+ function : "(A *B') + (A' * B)";
+ }
+ }
+
+ /* 2-input inverting MUX */
+ cell (imux2) {
+ area : 5;
+ pin(A) {
+ direction : input;
+ }
+ pin(B) {
+ direction : input;
+ }
+ pin(S) {
+ direction : input;
+ }
+ pin(Y) {
+ direction: output;
+ function : "( (A * S) + (B * S') )'";
+ }
+ }
+
+ /* D-type flip-flop with asynchronous reset and preset */
+ cell (dff) {
+ area : 6;
+ ff("IQ", "IQN") {
+ next_state : "D";
+ clocked_on : "CLK";
+ clear : "RESET";
+ preset : "PRESET";
+ clear_preset_var1 : L;
+ clear_preset_var2 : L;
+ }
+ pin(D) {
+ direction : input;
+ }
+ pin(CLK) {
+ direction : input;
+ }
+ pin(RESET) {
+ direction : input;
+ }
+ pin(PRESET) {
+ direction : input;
+ }
+ pin(Q) {
+ direction: output;
+ function : "IQ";
+ timing() {
+ timing_type : rising_edge;
+ intrinsic_rise : 65;
+ intrinsic_fall : 65;
+ rise_resistance : 0;
+ fall_resistance : 0;
+ related_pin : "CLK";
+ }
+ timing () {
+ timing_type : clear;
+ timing_sense : positive_unate;
+ intrinsic_fall : 75;
+ related_pin : "RESET";
+ }
+ timing () {
+ timing_type : preset;
+ timing_sense : negative_unate;
+ intrinsic_rise : 75;
+ related_pin : "PRESET";
+ }
+ }
+ pin(QN) {
+ direction: output;
+ function : "IQN";
+ timing() {
+ timing_type : rising_edge;
+ intrinsic_rise : 65;
+ intrinsic_fall : 65;
+ rise_resistance : 0;
+ fall_resistance : 0;
+ related_pin : "CLK";
+ }
+ timing () {
+ timing_type : preset;
+ timing_sense : negative_unate;
+ intrinsic_rise : 75;
+ related_pin : "RESET";
+ }
+ timing () {
+ timing_type : clear;
+ timing_sense : positive_unate;
+ intrinsic_fall : 75;
+ related_pin : "PRESET";
+ }
+ }
+ }
+
+ /* Latch */
+ cell(latch) {
+ area : 5;
+ latch ("IQ","IQN") {
+ enable : "G";
+ data_in : "D";
+ }
+
+ pin(D) {
+ direction : input;
+ }
+ pin(G) {
+ direction : input;
+ }
+
+ pin(Q) {
+ direction : output;
+ function : "IQ";
+ internal_node : "Q";
+
+ timing() {
+ timing_type : rising_edge;
+ intrinsic_rise : 65;
+ intrinsic_fall : 65;
+ rise_resistance : 0;
+ fall_resistance : 0;
+ related_pin : "G";
+ }
+
+ timing() {
+ timing_sense : positive_unate;
+ intrinsic_rise : 65;
+ intrinsic_fall : 65;
+ rise_resistance : 0;
+ fall_resistance : 0;
+ related_pin : "D";
+ }
+ }
+
+ pin(QN) {
+ direction : output;
+ function : "IQN";
+ internal_node : "QN";
+
+ timing() {
+ timing_type : rising_edge;
+ intrinsic_rise : 65;
+ intrinsic_fall : 65;
+ rise_resistance : 0;
+ fall_resistance : 0;
+ related_pin : "G";
+ }
+
+ timing() {
+ timing_sense : negative_unate;
+ intrinsic_rise : 65;
+ intrinsic_fall : 65;
+ rise_resistance : 0;
+ fall_resistance : 0;
+ related_pin : "D";
+ }
+ }
+ }
+
+ /* 3 input AND-OR-INVERT gate */
+ cell (aoi211) {
+ area : 3;
+ pin(A) {
+ direction : input;
+ }
+ pin(B) {
+ direction : input;
+ }
+ pin(C) {
+ direction : input;
+ }
+ pin(Y) {
+ direction: output;
+ function : "((A * B) + C)'";
+ }
+ }
+
+
+ /* 3 input OR-AND-INVERT gate */
+ cell (oai211) {
+ area : 3;
+ pin(A) {
+ direction : input;
+ }
+ pin(B) {
+ direction : input;
+ }
+ pin(C) {
+ direction : input;
+ }
+ pin(Y) {
+ direction: output;
+ function : "((A + B) * C)'";
+ }
+ }
+
+ /* half adder */
+ cell (halfadder) {
+ area : 5;
+ pin(A) {
+ direction : input;
+ }
+ pin(B) {
+ direction : input;
+ }
+ pin(C) {
+ direction : output;
+ function : "(A * B)";
+ }
+ pin(Y) {
+ direction: output;
+ function : "(A *B') + (A' * B)";
+ }
+ }
+
+ /* full adder */
+ cell (fulladder) {
+ area : 8;
+ pin(A) {
+ direction : input;
+ }
+ pin(B) {
+ direction : input;
+ }
+ pin(CI) {
+ direction : input;
+ }
+ pin(CO) {
+ direction : output;
+ function : "(((A * B)+(B * CI))+(CI * A))";
+ }
+ pin(Y) {
+ direction: output;
+ function : "((A^B)^CI)";
+ }
+ }
+
+} /* end */
diff --git a/tests/liberty/processdefs.lib b/tests/liberty/processdefs.lib
new file mode 100644
index 000000000..37a6bbaf8
--- /dev/null
+++ b/tests/liberty/processdefs.lib
@@ -0,0 +1,48 @@
+/********************************************/
+/* */
+/* Supergate cell library for Bench marking */
+/* */
+/* Symbiotic EDA GmbH / Moseley Instruments */
+/* Niels A. Moseley */
+/* */
+/* Process: none */
+/* */
+/* Date : 25-03-2019 */
+/* Version: 1.0 */
+/* */
+/********************************************/
+
+library(processdefs) {
+ technology (cmos);
+ revision : 1.0;
+
+ time_unit : "1ps";
+ pulling_resistance_unit : "1kohm";
+ voltage_unit : "1V";
+ current_unit : "1uA";
+
+ capacitive_load_unit(1,ff);
+
+ default_inout_pin_cap : 7.0;
+ default_input_pin_cap : 7.0;
+ default_output_pin_cap : 0.0;
+ default_fanout_load : 1.0;
+
+ default_wire_load_capacitance : 0.1;
+ default_wire_load_resistance : 1.0e-3;
+ default_wire_load_area : 0.0;
+
+ nom_process : 1.0;
+ nom_temperature : 25.0;
+ nom_voltage : 1.2;
+
+ delay_model : generic_cmos;
+
+ define_cell_area(bond_pads,pad_slots)
+ input_voltage(cmos) {
+ vil : 0.3 * VDD ;
+ vih : 0.7 * VDD ;
+ vimin : -0.5 ;
+ vimax : VDD + 0.5 ;
+ }
+}
diff --git a/tests/liberty/run-test.sh b/tests/liberty/run-test.sh
new file mode 100755
index 000000000..7e2ed2370
--- /dev/null
+++ b/tests/liberty/run-test.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+set -e
+
+for x in *.lib; do
+ echo "Running $x.."
+ echo "read_verilog small.v" > test.ys
+ echo "synth -top small" >> test.ys
+ echo "dfflibmap -liberty ${x}" >> test.ys
+ ../../yosys -ql ${x%.lib}.log -s test.ys
+done
diff --git a/tests/liberty/semicolextra.lib b/tests/liberty/semicolextra.lib
new file mode 100644
index 000000000..6a7fa77cc
--- /dev/null
+++ b/tests/liberty/semicolextra.lib
@@ -0,0 +1,48 @@
+/*
+
+ Test case for https://www.reddit.com/r/yosys/comments/b5texg/yosys_fails_to_parse_apparentlycorrect_liberty/
+
+ fall_constraint (SETUP_HOLD) formatting.
+
+*/
+
+library(supergate) {
+ technology (cmos);
+ revision : 1.0;
+
+ cell (DFF) {
+ cell_footprint : dff;
+ area : 50;
+ pin(D) {
+ direction : input;
+ capacitance : 0.002;
+ timing() {
+ related_pin : "CK";
+ timing_type : setup_rising;
+
+ fall_constraint (SETUP_HOLD) { values ("0.4000, 0.3000, 0.2000, 0.1000, 0.0000", \
+ "0.4000, 0.3000, 0.2000, 0.1000, 0.000", \
+ "0.5000, 0.4000, 0.3000, 0.2000, 0.0000", \
+ "0.7000, 0.6000, 0.5000, 0.4000, 0.2000", \
+ "1.0000, 1.0000, 0.9000, 0.8000, 0.6000"); };
+ }
+ }
+
+ pin(CK) {
+ direction : input;
+ clock : true;
+ capacitance : 0.00290;
+ }
+
+ ff(IQ,IQN) {
+ clocked_on : "CK";
+ next_state : "D";
+ }
+ pin(Q) {
+ direction : output;
+ capacitance : 0.003;
+ max_capacitance : 0.3;
+ }
+ cell_leakage_power : 0.3;
+ }
+}
diff --git a/tests/liberty/semicolmissing.lib b/tests/liberty/semicolmissing.lib
new file mode 100644
index 000000000..f7c20750a
--- /dev/null
+++ b/tests/liberty/semicolmissing.lib
@@ -0,0 +1,72 @@
+/********************************************/
+/* */
+/* Supergate cell library for Bench marking */
+/* */
+/* Symbiotic EDA GmbH / Moseley Instruments */
+/* Niels A. Moseley */
+/* */
+/* Process: none */
+/* */
+/* Date : 24-03-2019 */
+/* Version: 1.0 */
+/* Version: 1.1 - Removed semicolons in */
+/* full adder */
+/* */
+/********************************************/
+
+/*
+ semi colon is missing in full-adder specification
+ some TSMC liberty files are formatted this way..
+*/
+
+library(supergate) {
+ technology (cmos);
+ revision : 1.0;
+
+ time_unit : "1ps";
+ pulling_resistance_unit : "1kohm";
+ voltage_unit : "1V";
+ current_unit : "1uA";
+
+ capacitive_load_unit(1,ff);
+
+ default_inout_pin_cap : 7.0;
+ default_input_pin_cap : 7.0;
+ default_output_pin_cap : 0.0;
+ default_fanout_load : 1.0;
+
+ default_wire_load_capacitance : 0.1;
+ default_wire_load_resistance : 1.0e-3;
+ default_wire_load_area : 0.0;
+
+ nom_process : 1.0;
+ nom_temperature : 25.0;
+ nom_voltage : 1.2;
+
+ delay_model : generic_cmos;
+
+ /* full adder */
+ cell (fulladder) {
+ area : 8
+ pin(A) {
+ direction : input
+ }
+ pin(B) {
+ direction : input
+ }
+ pin(CI) {
+ direction : input
+ }
+ pin(CO) {
+ direction : output
+ function : "(((A * B)+(B * CI))+(CI * A))"
+ }
+ pin(Y) {
+ direction: output
+ function : "((A^B)^CI)"
+ }
+ }
+
+} /* end */
+
+
diff --git a/tests/liberty/small.v b/tests/liberty/small.v
new file mode 100644
index 000000000..bd94be4fc
--- /dev/null
+++ b/tests/liberty/small.v
@@ -0,0 +1,16 @@
+/** small, meaningless design to test loading of liberty files */
+
+module small
+(
+ input clk,
+ output reg[7:0] count
+);
+
+initial count = 0;
+
+always @ (posedge clk)
+begin
+ count <= count + 1'b1;
+end
+
+endmodule
diff --git a/tests/sva/extnets.sv b/tests/sva/extnets.sv
new file mode 100644
index 000000000..47312de7a
--- /dev/null
+++ b/tests/sva/extnets.sv
@@ -0,0 +1,22 @@
+module top(input i, output o);
+ A A();
+ B B();
+ assign A.i = i;
+ assign o = B.o;
+ always @* assert(o == i);
+endmodule
+
+module A;
+ wire i, y;
+`ifdef FAIL
+ assign B.x = i;
+`else
+ assign B.x = !i;
+`endif
+ assign y = !B.y;
+endmodule
+
+module B;
+ wire x, y, o;
+ assign y = x, o = A.y;
+endmodule