diff --git a/Makefile b/Makefile index 1caa0038b..11803ec0a 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,7 @@ ENABLE_EDITLINE := 0 ENABLE_VERIFIC := 0 ENABLE_COVER := 1 ENABLE_LIBYOSYS := 0 +ENABLE_PROTOBUF := 0 # other configuration flags ENABLE_GPROF := 0 @@ -22,6 +23,9 @@ ENABLE_DEBUG := 0 ENABLE_NDEBUG := 0 LINK_CURSES := 0 LINK_TERMCAP := 0 +LINK_ABC := 0 +# Needed for environments that don't have proper thread support (i.e. emscripten) +DISABLE_ABC_THREADS := 0 # clang sanitizers SANITIZER = @@ -103,7 +107,7 @@ OBJS = kernel/version_$(GIT_REV).o # is just a symlink to your actual ABC working directory, as 'make mrproper' # will remove the 'abc' directory and you do not want to accidentally # delete your work on ABC.. -ABCREV = f23ea8e +ABCREV = 6df1396 ABCPULL = 1 ABCURL ?= https://github.com/berkeley-abc/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 @@ -126,6 +130,7 @@ ifeq ($(CONFIG),clang) CXX = clang LD = clang++ CXXFLAGS += -std=c++11 -Os +ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H" ifneq ($(SANITIZER),) $(info [Clang Sanitizer] $(SANITIZER)) @@ -148,16 +153,19 @@ else ifeq ($(CONFIG),gcc) CXX = gcc LD = gcc CXXFLAGS += -std=c++11 -Os +ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H" else ifeq ($(CONFIG),gcc-4.8) CXX = gcc-4.8 LD = gcc-4.8 CXXFLAGS += -std=c++11 -Os +ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H" else ifeq ($(CONFIG),emcc) CXX = emcc LD = emcc CXXFLAGS := -std=c++11 $(filter-out -fPIC -ggdb,$(CXXFLAGS)) +ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DABC_MEMALIGN=8" EMCCFLAGS := -Os -Wno-warn-absolute-paths EMCCFLAGS += --memory-init-file 0 --embed-file share -s NO_EXIT_RUNTIME=1 EMCCFLAGS += -s EXPORTED_FUNCTIONS="['_main','_run','_prompt','_errmsg']" @@ -171,6 +179,11 @@ EXE = .js TARGETS := $(filter-out yosys-config,$(TARGETS)) EXTRA_TARGETS += yosysjs-$(YOSYS_VER).zip +ifeq ($(ENABLE_ABC),1) +LINK_ABC := 1 +DISABLE_ABC_THREADS := 1 +endif + viz.js: wget -O viz.js.part https://github.com/mdaines/viz.js/releases/download/0.0.3/viz.js mv viz.js.part viz.js @@ -192,8 +205,8 @@ CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE -DYOSYS_MXE_HACKS -Wno-attributes CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s LDLIBS := $(filter-out -lrt,$(LDLIBS)) -ABCMKARGS += ARCHFLAGS="-DSIZEOF_VOID_P=4 -DSIZEOF_LONG=4 -DSIZEOF_INT=4 -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w" -ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=1 CC="$(CXX)" CXX="$(CXX)" +ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w" +ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=1 EXE = .exe else ifeq ($(CONFIG),msys2) @@ -203,8 +216,8 @@ CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s LDLIBS := $(filter-out -lrt,$(LDLIBS)) -ABCMKARGS += ARCHFLAGS="-DSIZEOF_VOID_P=4 -DSIZEOF_LONG=4 -DSIZEOF_INT=4 -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w" -ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=0 CC="i686-w64-mingw32-gcc" CXX="$(CXX)" +ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w" +ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=0 EXE = .exe else ifneq ($(CONFIG),none) @@ -236,9 +249,15 @@ else ifeq ($(ENABLE_EDITLINE),1) CXXFLAGS += -DYOSYS_ENABLE_EDITLINE LDLIBS += -ledit -ltinfo -lbsd +else +ABCMKARGS += "ABC_USE_NO_READLINE=1" endif endif +ifeq ($(DISABLE_ABC_THREADS),1) +ABCMKARGS += "ABC_USE_NO_PTHREADS=1" +endif + ifeq ($(ENABLE_PLUGINS),1) CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags libffi) -DYOSYS_ENABLE_PLUGINS LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs libffi || echo -lffi) @@ -288,10 +307,17 @@ endif ifeq ($(ENABLE_ABC),1) CXXFLAGS += -DYOSYS_ENABLE_ABC +ifeq ($(LINK_ABC),1) +CXXFLAGS += -DYOSYS_LINK_ABC +ifeq ($(DISABLE_ABC_THREADS),0) +LDLIBS += -lpthread +endif +else ifeq ($(ABCEXTERNAL),) TARGETS += yosys-abc$(EXE) endif endif +endif ifeq ($(ENABLE_VERIFIC),1) VERIFIC_DIR ?= /usr/local/src/verific_lib_eval @@ -300,6 +326,10 @@ CXXFLAGS += $(patsubst %,-I$(VERIFIC_DIR)/%,$(VERIFIC_COMPONENTS)) -DYOSYS_ENABL LDLIBS += $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VERIFIC_COMPONENTS)) -lz endif +ifeq ($(ENABLE_PROTOBUF),1) +LDLIBS += $(shell pkg-config --cflags --libs protobuf) +endif + ifeq ($(ENABLE_COVER),1) CXXFLAGS += -DYOSYS_ENABLE_COVER endif @@ -411,6 +441,10 @@ include techlibs/common/Makefile.inc endif +ifeq ($(LINK_ABC),1) +OBJS += yosys-libabc.a +endif + top-all: $(TARGETS) $(EXTRA_TARGETS) @echo "" @echo " Build successful." @@ -455,7 +489,7 @@ yosys-config: misc/yosys-config.in -e 's#@BINDIR@#$(strip $(BINDIR))#;' -e 's#@DATDIR@#$(strip $(DATDIR))#;' < $< > yosys-config $(Q) chmod +x yosys-config -abc/abc-$(ABCREV)$(EXE): +abc/abc-$(ABCREV)$(EXE) abc/libabc-$(ABCREV).a: $(P) ifneq ($(ABCREV),default) $(Q) if test -d abc/.hg; then \ @@ -472,15 +506,19 @@ ifneq ($(ABCREV),default) fi endif $(Q) rm -f abc/abc-[0-9a-f]* - $(Q) cd abc && $(MAKE) $(S) $(ABCMKARGS) PROG="abc-$(ABCREV)$(EXE)" MSG_PREFIX="$(eval P_OFFSET = 5)$(call P_SHOW)$(eval P_OFFSET = 10) ABC: " + $(Q) cd abc && $(MAKE) $(S) $(ABCMKARGS) $(if $(filter %.a,$@),PROG="abc-$(ABCREV)",PROG="abc-$(ABCREV)$(EXE)") MSG_PREFIX="$(eval P_OFFSET = 5)$(call P_SHOW)$(eval P_OFFSET = 10) ABC: " $(if $(filter %.a,$@),libabc-$(ABCREV).a) ifeq ($(ABCREV),default) .PHONY: abc/abc-$(ABCREV)$(EXE) +.PHONY: abc/libabc-$(ABCREV).a endif yosys-abc$(EXE): abc/abc-$(ABCREV)$(EXE) $(P) cp abc/abc-$(ABCREV)$(EXE) yosys-abc$(EXE) +yosys-libabc.a: abc/libabc-$(ABCREV).a + $(P) cp abc/libabc-$(ABCREV).a yosys-libabc.a + ifneq ($(SEED),) SEEDOPT="-S $(SEED)" else @@ -564,7 +602,7 @@ clean: rm -rf share if test -d manual; then cd manual && sh clean.sh; fi rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS) - rm -f kernel/version_*.o kernel/version_*.cc abc/abc-[0-9a-f]* + rm -f kernel/version_*.o kernel/version_*.cc abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d rm -rf tests/asicworld/*.out tests/asicworld/*.log rm -rf tests/hana/*.out tests/hana/*.log @@ -577,7 +615,7 @@ clean: clean-abc: $(MAKE) -C abc DEP= clean - rm -f yosys-abc$(EXE) abc/abc-[0-9a-f]* + rm -f yosys-abc$(EXE) yosys-libabc.a abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a mrproper: clean git clean -xdf diff --git a/README.md b/README.md index d5184bd7d..c02691d94 100644 --- a/README.md +++ b/README.md @@ -52,19 +52,19 @@ For example on Ubuntu Linux 16.04 LTS the following commands will install all prerequisites for building yosys: $ sudo apt-get install build-essential clang bison flex \ - libreadline-dev gawk tcl-dev libffi-dev git mercurial \ + libreadline-dev gawk tcl-dev libffi-dev git \ graphviz xdot pkg-config python3 Similarily, on Mac OS X MacPorts or Homebrew can be used to install dependencies: $ brew tap Homebrew/bundle && brew bundle $ sudo port install bison flex readline gawk libffi \ - git mercurial graphviz pkgconfig python36 + git graphviz pkgconfig python36 On FreeBSD use the following command to install all prerequisites: # pkg install bison flex readline gawk libffi\ - git mercurial graphviz pkgconfig python3 python36 tcl-wrapper + git graphviz pkgconfig python3 python36 tcl-wrapper On FreeBSD system use gmake instead of make. To run tests use: % MAKE=gmake CC=cc gmake test @@ -418,7 +418,9 @@ Non-standard or SystemVerilog features for formal verification supported in any clocked block. - The syntax ``@($global_clock)`` can be used to create FFs that have no - explicit clock input ($ff cells). + explicit clock input ($ff cells). The same can be achieved by using + ``@(posedge )`` or ``@(negedge )`` when ```` + is marked with the ``(* gclk *)`` Verilog attribute. Supported features from SystemVerilog diff --git a/backends/protobuf/.gitignore b/backends/protobuf/.gitignore new file mode 100644 index 000000000..849b38d45 --- /dev/null +++ b/backends/protobuf/.gitignore @@ -0,0 +1,2 @@ +yosys.pb.cc +yosys.pb.h diff --git a/backends/protobuf/Makefile.inc b/backends/protobuf/Makefile.inc new file mode 100644 index 000000000..834cad42c --- /dev/null +++ b/backends/protobuf/Makefile.inc @@ -0,0 +1,8 @@ +ifeq ($(ENABLE_PROTOBUF),1) + +backends/protobuf/yosys.pb.cc backends/protobuf/yosys.pb.h: misc/yosys.proto + $(Q) cd misc && protoc --cpp_out "../backends/protobuf" yosys.proto + +OBJS += backends/protobuf/protobuf.o backends/protobuf/yosys.pb.o + +endif diff --git a/backends/protobuf/protobuf.cc b/backends/protobuf/protobuf.cc new file mode 100644 index 000000000..9a6fedee7 --- /dev/null +++ b/backends/protobuf/protobuf.cc @@ -0,0 +1,370 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2018 Serge Bazanski + * + * 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 + +#include "kernel/rtlil.h" +#include "kernel/register.h" +#include "kernel/sigtools.h" +#include "kernel/celltypes.h" +#include "kernel/cellaigs.h" +#include "kernel/log.h" +#include "yosys.pb.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct ProtobufDesignSerializer +{ + bool aig_mode_; + bool use_selection_; + yosys::pb::Design *pb_; + + Design *design_; + Module *module_; + + SigMap sigmap_; + int sigidcounter_; + dict sigids_; + pool aig_models_; + + + ProtobufDesignSerializer(bool use_selection, bool aig_mode) : + aig_mode_(aig_mode), use_selection_(use_selection) { } + + string get_name(IdString name) + { + return RTLIL::unescape_id(name); + } + + + void serialize_parameters(google::protobuf::Map *out, + const dict ¶meters) + { + for (auto ¶m : parameters) { + std::string key = get_name(param.first); + + + yosys::pb::Parameter pb_param; + + if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0) { + pb_param.set_str(param.second.decode_string()); + } else if (GetSize(param.second.bits) > 64) { + pb_param.set_str(param.second.as_string()); + } else { + pb_param.set_int_(param.second.as_int()); + } + + (*out)[key] = pb_param; + } + } + + void get_bits(yosys::pb::BitVector *out, SigSpec sig) + { + for (auto bit : sigmap_(sig)) { + auto sig = out->add_signal(); + + // Constant driver. + if (bit.wire == nullptr) { + if (bit == State::S0) sig->set_constant(sig->CONSTANT_DRIVER_LOW); + else if (bit == State::S1) sig->set_constant(sig->CONSTANT_DRIVER_HIGH); + else if (bit == State::Sz) sig->set_constant(sig->CONSTANT_DRIVER_Z); + else sig->set_constant(sig->CONSTANT_DRIVER_X); + continue; + } + + // Signal - give it a unique identifier. + if (sigids_.count(bit) == 0) { + sigids_[bit] = sigidcounter_++; + } + sig->set_id(sigids_[bit]); + } + } + + void serialize_module(yosys::pb::Module* out, Module *module) + { + module_ = module; + log_assert(module_->design == design_); + sigmap_.set(module_); + sigids_.clear(); + sigidcounter_ = 0; + + serialize_parameters(out->mutable_attribute(), module_->attributes); + + for (auto n : module_->ports) { + Wire *w = module->wire(n); + if (use_selection_ && !module_->selected(w)) + continue; + + yosys::pb::Module::Port pb_port; + pb_port.set_direction(w->port_input ? w->port_output ? + yosys::pb::DIRECTION_INOUT : yosys::pb::DIRECTION_INPUT : yosys::pb::DIRECTION_OUTPUT); + get_bits(pb_port.mutable_bits(), w); + (*out->mutable_port())[get_name(n)] = pb_port; + } + + for (auto c : module_->cells()) { + if (use_selection_ && !module_->selected(c)) + continue; + + yosys::pb::Module::Cell pb_cell; + pb_cell.set_hide_name(c->name[0] == '$'); + pb_cell.set_type(get_name(c->type)); + + if (aig_mode_) { + Aig aig(c); + if (aig.name.empty()) + continue; + pb_cell.set_model(aig.name); + aig_models_.insert(aig); + } + serialize_parameters(pb_cell.mutable_parameter(), c->parameters); + serialize_parameters(pb_cell.mutable_attribute(), c->attributes); + + if (c->known()) { + for (auto &conn : c->connections()) { + yosys::pb::Direction direction = yosys::pb::DIRECTION_OUTPUT; + if (c->input(conn.first)) + direction = c->output(conn.first) ? yosys::pb::DIRECTION_INOUT : yosys::pb::DIRECTION_INPUT; + (*pb_cell.mutable_port_direction())[get_name(conn.first)] = direction; + } + } + for (auto &conn : c->connections()) { + yosys::pb::BitVector vec; + get_bits(&vec, conn.second); + (*pb_cell.mutable_connection())[get_name(conn.first)] = vec; + } + + (*out->mutable_cell())[get_name(c->name)] = pb_cell; + } + + for (auto w : module_->wires()) { + if (use_selection_ && !module_->selected(w)) + continue; + + auto netname = out->add_netname(); + netname->set_hide_name(w->name[0] == '$'); + get_bits(netname->mutable_bits(), w); + serialize_parameters(netname->mutable_attributes(), w->attributes); + } + } + + + void serialize_models(google::protobuf::Map *models) + { + for (auto &aig : aig_models_) { + yosys::pb::Model pb_model; + for (auto &node : aig.nodes) { + auto pb_node = pb_model.add_node(); + if (node.portbit >= 0) { + if (node.inverter) { + pb_node->set_type(pb_node->TYPE_NPORT); + } else { + pb_node->set_type(pb_node->TYPE_PORT); + } + auto port = pb_node->mutable_port(); + port->set_portname(log_id(node.portname)); + port->set_bitindex(node.portbit); + } else if (node.left_parent < 0 && node.right_parent < 0) { + if (node.inverter) { + pb_node->set_type(pb_node->TYPE_TRUE); + } else { + pb_node->set_type(pb_node->TYPE_FALSE); + } + } else { + if (node.inverter) { + pb_node->set_type(pb_node->TYPE_NAND); + } else { + pb_node->set_type(pb_node->TYPE_AND); + } + auto gate = pb_node->mutable_gate(); + gate->set_left(node.left_parent); + gate->set_right(node.right_parent); + } + for (auto &op : node.outports) { + auto pb_op = pb_node->add_out_port(); + pb_op->set_name(log_id(op.first)); + pb_op->set_bit_index(op.second); + } + } + (*models)[aig.name] = pb_model; + } + } + + void serialize_design(yosys::pb::Design *pb, Design *design) + { + GOOGLE_PROTOBUF_VERIFY_VERSION; + pb_ = pb; + pb_->Clear(); + pb_->set_creator(yosys_version_str); + + design_ = design; + design_->sort(); + + auto modules = use_selection_ ? design_->selected_modules() : design_->modules(); + for (auto mod : modules) { + yosys::pb::Module pb_mod; + serialize_module(&pb_mod, mod); + (*pb->mutable_modules())[mod->name.str()] = pb_mod; + } + + serialize_models(pb_->mutable_models()); + } +}; + +struct ProtobufBackend : public Backend { + ProtobufBackend(): Backend("protobuf", "write design to a Protocol Buffer file") { } + virtual void help() + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" write_protobuf [options] [filename]\n"); + log("\n"); + log("Write a JSON netlist of the current design.\n"); + log("\n"); + log(" -aig\n"); + log(" include AIG models for the different gate types\n"); + log("\n"); + log(" -text\n"); + log(" output protobuf in Text/ASCII representation\n"); + log("\n"); + log("The schema of the output Protocol Buffer is defined in misc/yosys.pb in the\n"); + log("Yosys source code distribution.\n"); + log("\n"); + } + virtual void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) + { + bool aig_mode = false; + bool text_mode = false; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-aig") { + aig_mode = true; + continue; + } + if (args[argidx] == "-text") { + text_mode = true; + continue; + } + break; + } + extra_args(f, filename, args, argidx); + + log_header(design, "Executing Protobuf backend.\n"); + + yosys::pb::Design pb; + ProtobufDesignSerializer serializer(false, aig_mode); + serializer.serialize_design(&pb, design); + + if (text_mode) { + string out; + google::protobuf::TextFormat::PrintToString(pb, &out); + *f << out; + } else { + pb.SerializeToOstream(f); + } + } +} ProtobufBackend; + +struct ProtobufPass : public Pass { + ProtobufPass() : Pass("protobuf", "write design in Protobuf format") { } + virtual void help() + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" protobuf [options] [selection]\n"); + log("\n"); + log("Write a JSON netlist of all selected objects.\n"); + log("\n"); + log(" -o \n"); + log(" write to the specified file.\n"); + log("\n"); + log(" -aig\n"); + log(" include AIG models for the different gate types\n"); + log("\n"); + log(" -text\n"); + log(" output protobuf in Text/ASCII representation\n"); + log("\n"); + log("The schema of the output Protocol Buffer is defined in misc/yosys.pb in the\n"); + log("Yosys source code distribution.\n"); + log("\n"); + } + virtual void execute(std::vector args, RTLIL::Design *design) + { + std::string filename; + bool aig_mode = false; + bool text_mode = false; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-o" && argidx+1 < args.size()) { + filename = args[++argidx]; + continue; + } + if (args[argidx] == "-aig") { + aig_mode = true; + continue; + } + if (args[argidx] == "-text") { + text_mode = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + std::ostream *f; + std::stringstream buf; + + if (!filename.empty()) { + std::ofstream *ff = new std::ofstream; + ff->open(filename.c_str(), std::ofstream::trunc); + if (ff->fail()) { + delete ff; + log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno)); + } + f = ff; + } else { + f = &buf; + } + + yosys::pb::Design pb; + ProtobufDesignSerializer serializer(true, aig_mode); + serializer.serialize_design(&pb, design); + + if (text_mode) { + string out; + google::protobuf::TextFormat::PrintToString(pb, &out); + *f << out; + } else { + pb.SerializeToOstream(f); + } + + if (!filename.empty()) { + delete f; + } else { + log("%s", buf.str().c_str()); + } + } +} ProtobufPass; + +PRIVATE_NAMESPACE_END; diff --git a/examples/cmos/counter.ys b/examples/cmos/counter.ys index a784f3465..d0b093667 100644 --- a/examples/cmos/counter.ys +++ b/examples/cmos/counter.ys @@ -1,11 +1,12 @@ - read_verilog counter.v read_verilog -lib cmos_cells.v -proc;; memory;; techmap;; - +synth dfflibmap -liberty cmos_cells.lib -abc -liberty cmos_cells.lib;; +abc -liberty cmos_cells.lib +opt_clean + +stat -liberty cmos_cells.lib # http://vlsiarch.ecen.okstate.edu/flows/MOSIS_SCMOS/latest/cadence/lib/tsmc025/signalstorm/osu025_stdcells.lib # dfflibmap -liberty osu025_stdcells.lib @@ -13,4 +14,3 @@ abc -liberty cmos_cells.lib;; write_verilog synth.v write_spice synth.sp - diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 57ba9668d..d9f0039af 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -223,12 +223,18 @@ 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) @@ -242,6 +248,9 @@ 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); @@ -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); } diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc index c9b6a54b2..b9e53a4be 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 &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; diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index ee09c7523..62a8028b8 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -62,6 +62,7 @@ using namespace Verific; YOSYS_NAMESPACE_BEGIN int verific_verbose; +bool verific_import_pending; string verific_error_msg; void msg_func(msg_type_t msg_type, const char *message_id, linefile_type linefile, const char *msg, va_list args) @@ -189,12 +190,12 @@ RTLIL::SigSpec VerificImporter::operatorInport(Instance *inst, const char *portn } } -RTLIL::SigSpec VerificImporter::operatorOutput(Instance *inst) +RTLIL::SigSpec VerificImporter::operatorOutput(Instance *inst, const pool *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 { @@ -244,7 +245,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; } @@ -394,6 +397,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) { @@ -525,7 +529,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; } @@ -791,6 +795,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se dict init_nets; pool anyconst_nets, anyseq_nets; pool allconst_nets, allseq_nets; + any_all_nets.clear(); FOREACH_NET_OF_NETLIST(nl, mi, net) { @@ -871,23 +876,30 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se const char *allconst_attr = net->GetAttValue("allconst"); const char *allseq_attr = net->GetAttValue("allseq"); - if (rand_const_attr != nullptr && !strcmp(rand_const_attr, "1")) + if (rand_const_attr != nullptr && (!strcmp(rand_const_attr, "1") || !strcmp(rand_const_attr, "'1'"))) { anyconst_nets.insert(net); - - else if (rand_attr != nullptr && !strcmp(rand_attr, "1")) + any_all_nets.insert(net); + } + else if (rand_attr != nullptr && (!strcmp(rand_attr, "1") || !strcmp(rand_attr, "'1'"))) { anyseq_nets.insert(net); - - else if (anyconst_attr != nullptr && !strcmp(anyconst_attr, "1")) + any_all_nets.insert(net); + } + else if (anyconst_attr != nullptr && (!strcmp(anyconst_attr, "1") || !strcmp(anyconst_attr, "'1'"))) { anyconst_nets.insert(net); - - else if (anyseq_attr != nullptr && !strcmp(anyseq_attr, "1")) + any_all_nets.insert(net); + } + else if (anyseq_attr != nullptr && (!strcmp(anyseq_attr, "1") || !strcmp(anyseq_attr, "'1'"))) { anyseq_nets.insert(net); - - else if (allconst_attr != nullptr && !strcmp(allconst_attr, "1")) + any_all_nets.insert(net); + } + else if (allconst_attr != nullptr && (!strcmp(allconst_attr, "1") || !strcmp(allconst_attr, "'1'"))) { allconst_nets.insert(net); - - else if (allseq_attr != nullptr && !strcmp(allseq_attr, "1")) + 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) @@ -1064,7 +1076,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; } @@ -1382,7 +1396,8 @@ VerificClocking::VerificClocking(VerificImporter *importer, Net *net, bool sva_a 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();; @@ -1456,6 +1471,10 @@ VerificClocking::VerificClocking(VerificImporter *importer, Net *net, bool sva_a 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) @@ -1478,15 +1497,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) @@ -1497,6 +1521,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) @@ -1589,11 +1614,71 @@ struct VerificExtNets } }; +void verific_import(Design *design, std::string top) +{ + std::set 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_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() @@ -1608,6 +1693,14 @@ struct VerificPass : public Pass { 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[=] 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 ..\n"); + log("\n"); + log("Like -sv, but define FORMAL instead of SYNTHESIS.\n"); log("\n"); log(" verific {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl} ..\n"); log("\n"); @@ -1627,7 +1720,12 @@ struct VerificPass : public Pass { log("\n"); log(" verific -vlog-define [=]..\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 ..\n"); + log("\n"); + log("Remove Verilog defines previously set with -vlog-define.\n"); log("\n"); log("\n"); log(" verific -import [options] ..\n"); @@ -1684,6 +1782,9 @@ struct VerificPass : public Pass { #ifdef YOSYS_ENABLE_VERIFIC virtual void execute(std::vector 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); @@ -1694,8 +1795,6 @@ struct VerificPass : public Pass { RuntimeFlags::SetVar("veri_extract_dualport_rams", 0); RuntimeFlags::SetVar("veri_extract_multiport_rams", 1); RuntimeFlags::SetVar("db_infer_wide_operators", 1); - veri_file::DefineCmdLineMacro("VERIFIC"); - veri_file::DefineCmdLineMacro("SYNTHESIS"); verific_verbose = 0; @@ -1740,8 +1839,16 @@ struct VerificPass : public Pass { goto check_error; } + 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] == "-vlog95" || args[argidx] == "-vlog2k" || args[argidx] == "-sv2005" || - args[argidx] == "-sv2009" || args[argidx] == "-sv2012" || args[argidx] == "-sv")) + args[argidx] == "-sv2009" || args[argidx] == "-sv2012" || args[argidx] == "-sv" || args[argidx] == "-formal")) { Array file_names; unsigned verilog_mode; @@ -1754,17 +1861,38 @@ struct VerificPass : public Pass { 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") + else if (args[argidx] == "-sv2012" || args[argidx] == "-sv" || args[argidx] == "-formal") verilog_mode = veri_file::SYSTEM_VERILOG; else log_abort(); - for (argidx++; argidx < GetSize(args); argidx++) - file_names.Insert(args[argidx].c_str()); + veri_file::DefineMacro("VERIFIC"); + veri_file::DefineMacro(args[argidx] == "-formal" ? "FORMAL" : "SYNTHESIS"); + + 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()); + } + } + + 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; } @@ -1773,6 +1901,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; } @@ -1781,6 +1910,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; } @@ -1789,6 +1919,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; } @@ -1797,6 +1928,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; } @@ -2007,6 +2139,7 @@ struct VerificPass : public Pass { veri_file::Reset(); vhdl_file::Reset(); Libset::Reset(); + verific_import_pending = false; goto check_error; } @@ -2024,5 +2157,114 @@ 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} ..\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[=] 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} ..\n"); + log("\n"); + log("Load the specified VHDL files. (Requires Verific.)\n"); + log("\n"); + log("\n"); + log(" read -define [=]..\n"); + log("\n"); + log("Set global Verilog/SystemVerilog defines.\n"); + log("\n"); + log("\n"); + log(" read -undef ..\n"); + log("\n"); + log("Unset global Verilog/SystemVerilog defines.\n"); + log("\n"); + } + virtual void execute(std::vector 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; + } + + 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 2dd688e0d..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 verific_sva_prims; struct VerificImporter; @@ -40,6 +43,7 @@ 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, bool sva_at_only = false); @@ -65,6 +69,7 @@ struct VerificImporter std::map net_map; std::map sva_posedge_map; + pool any_all_nets; bool mode_gates, mode_keep, mode_nosva, mode_names, mode_verific; bool mode_autocover; @@ -79,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 *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 4e440b4ca..8e985c3a6 100644 --- a/frontends/verific/verificsva.cc +++ b/frontends/verific/verificsva.cc @@ -980,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) { @@ -1487,6 +1486,70 @@ 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->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); @@ -1620,10 +1683,46 @@ struct VerificSvaImporter } else { - if (mode_assert || mode_assume) { - parse_property(clocking.body_net, nullptr, &reject_bit); - } else { - parse_property(clocking.body_net, &accept_bit, nullptr); + Net *net = clocking.body_net; + SigBit trig; + + if (eventually_property(net, trig)) + { + SigBit sig_a, sig_en = trig; + parse_property(net, &sig_a, 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); + } } } 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 &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 &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/kernel/driver.cc b/kernel/driver.cc index bec872c24..178641101 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -85,20 +85,37 @@ USING_YOSYS_NAMESPACE #ifdef EMSCRIPTEN # include # include +# include extern "C" int main(int, char**); extern "C" void run(const char*); extern "C" const char *errmsg(); extern "C" const char *prompt(); -int main(int, char**) +int main(int argc, char **argv) { + EM_ASM( + if (ENVIRONMENT_IS_NODE) + { + FS.mkdir('/hostcwd'); + FS.mount(NODEFS, { root: '.' }, '/hostcwd'); + FS.mkdir('/hostfs'); + FS.mount(NODEFS, { root: '/' }, '/hostfs'); + } + ); + mkdir("/work", 0777); chdir("/work"); log_files.push_back(stdout); log_error_stderr = true; yosys_banner(); yosys_setup(); + + if (argc == 2) + { + // Run the first argument as a script file + run_frontend(argv[1], "script", 0, 0, 0); + } } void run(const char *command) diff --git a/kernel/yosys.cc b/kernel/yosys.cc index aa5901271..750a154e6 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -739,7 +739,7 @@ std::string proc_self_dirname() #ifdef EMSCRIPTEN std::string proc_share_dirname() { - return "/share"; + return "/share/"; } #else std::string proc_share_dirname() diff --git a/misc/yosys.proto b/misc/yosys.proto new file mode 100644 index 000000000..2870176cb --- /dev/null +++ b/misc/yosys.proto @@ -0,0 +1,175 @@ +// +// yosys -- Yosys Open SYnthesis Suite +// +// Copyright (C) 2018 Serge Bazanski +// +// 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. +// + +/// Protobuf definition of Yosys RTLIL dump/restore format for RTL designs. + +syntax = "proto3"; + +package yosys.pb; + +// Port direction. +enum Direction { + DIRECTION_INVALID = 0; + DIRECTION_INPUT = 1; + DIRECTION_OUTPUT = 2; + DIRECTION_INOUT = 3; +} + +// A freeform parameter/attribute value. +message Parameter { + oneof value { + int64 int = 1; + string str = 2; + } +} + +// A signal in the design - either a unique identifier for one, or a constant +// driver (low or high). +message Signal { + // A constant signal driver in the design. + enum ConstantDriver { + CONSTANT_DRIVER_INVALID = 0; + CONSTANT_DRIVER_LOW = 1; + CONSTANT_DRIVER_HIGH = 2; + CONSTANT_DRIVER_Z = 3; + CONSTANT_DRIVER_X = 4; + } + oneof type { + // Signal uniquely identified by ID number. + int64 id = 1; + // Constant driver. + ConstantDriver constant = 2; + } +} + +// A vector of signals. +message BitVector { + repeated Signal signal = 1; +} + +// A netlist module. +message Module { + // Freeform attributes. + map attribute = 1; + + // Named ports in this module. + message Port { + Direction direction = 1; + BitVector bits = 2; + } + map port = 2; + + // Named cells in this module. + message Cell { + // Set to true when the name of this cell is automatically created and + // likely not of interest for a regular user. + bool hide_name = 1; + string type = 2; + // Set if this module has an AIG model available. + string model = 3; + // Freeform parameters. + map parameter = 4; + // Freeform attributes. + map attribute = 5; + + /// Ports of the cell. + // Direction of the port, if interface is known. + map port_direction = 6; + // Connection of named port to signal(s). + map connection = 7; + } + map cell = 3; + + // Nets in this module. + message Netname { + // Set to true when the name of this net is automatically created and + // likely not of interest for a regular user. + bool hide_name = 1; + // Signal(s) that make up this net. + BitVector bits = 2; + // Freeform attributes. + map attributes = 3; + } + repeated Netname netname = 4; +} + +// And-Inverter-Graph model. +message Model { + message Node { + // Type of AIG node - or, what its' value is. + enum Type { + TYPE_INVALID = 0; + // The node's value is the value of the specified input port bit. + TYPE_PORT = 1; + // The node's value is the inverted value of the specified input + // port bit. + TYPE_NPORT = 2; + // The node's value is the ANDed value of specified nodes. + TYPE_AND = 3; + // The node's value is the NANDed value of specified nodes. + TYPE_NAND = 4; + // The node's value is a constant 1. + TYPE_TRUE = 5; + // The node's value is a constant 0. + TYPE_FALSE = 6; + }; + Type type = 1; + + message Port { + // Name of port. + string portname = 1; + // Bit index in port. + int64 bitindex = 2; + } + message Gate { + // Node index of left side of operation. + int64 left = 1; + // Node index of right side of operation. + int64 right = 2; + } + oneof node { + // Set for PORT, NPORT + Port port = 2; + // Set for AND, NAND. + Gate gate = 3; + } + + // Set when the node drives given output port(s). + message OutPort { + // Name of port. + string name = 1; + // Bit index in port. + int64 bit_index = 2; + } + repeated OutPort out_port = 4; + } + + // List of AIG nodes - each is explicitely numbered by its' index in this + // array. + repeated Node node = 1; +} + +// A Yosys design netlist dumped from RTLIL. +message Design { + // Human-readable freeform 'remark' string. + string creator = 1; + // List of named modules in design. + map modules = 2; + // List of named AIG models in design (if AIG export enabled). + map models = 3; +} diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc index c67953976..1cd942796 100644 --- a/passes/cmds/setundef.cc +++ b/passes/cmds/setundef.cc @@ -23,6 +23,13 @@ #include "kernel/rtlil.h" #include "kernel/log.h" +#define MODE_ZERO 0 +#define MODE_ONE 1 +#define MODE_UNDEF 2 +#define MODE_RANDOM 3 +#define MODE_ANYSEQ 4 +#define MODE_ANYCONST 5 + USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -97,30 +104,32 @@ struct SetundefWorker RTLIL::State next_bit() { - if (next_bit_mode == 0) + if (next_bit_mode == MODE_ZERO) return RTLIL::State::S0; - if (next_bit_mode == 1) + if (next_bit_mode == MODE_ONE) return RTLIL::State::S1; - if (next_bit_mode == 2) - log_abort(); - - if (next_bit_mode == 4) + if (next_bit_mode == MODE_UNDEF) return RTLIL::State::Sx; - // xorshift32 - next_bit_state ^= next_bit_state << 13; - next_bit_state ^= next_bit_state >> 17; - next_bit_state ^= next_bit_state << 5; - log_assert(next_bit_state != 0); + if (next_bit_mode == MODE_RANDOM) + { + // xorshift32 + next_bit_state ^= next_bit_state << 13; + next_bit_state ^= next_bit_state >> 17; + next_bit_state ^= next_bit_state << 5; + log_assert(next_bit_state != 0); - return ((next_bit_state >> (next_bit_state & 15)) & 16) ? RTLIL::State::S0 : RTLIL::State::S1; + return ((next_bit_state >> (next_bit_state & 15)) & 16) ? RTLIL::State::S0 : RTLIL::State::S1; + } + + log_abort(); } void operator()(RTLIL::SigSpec &sig) { - if (next_bit_mode == 2) { + if (next_bit_mode == MODE_ANYSEQ || next_bit_mode == MODE_ANYCONST) { siglist.push_back(&sig); return; } @@ -145,7 +154,7 @@ struct SetundefPass : public Pass { log(" also set undriven nets to constant values\n"); log("\n"); log(" -expose\n"); - log(" also expose undriven nets as inputs\n"); + log(" also expose undriven nets as inputs (use with -undriven)\n"); log("\n"); log(" -zero\n"); log(" replace with bits cleared (0)\n"); @@ -159,6 +168,9 @@ struct SetundefPass : public Pass { log(" -anyseq\n"); log(" replace with $anyseq drivers (for formal)\n"); log("\n"); + log(" -anyconst\n"); + log(" replace with $anyconst drivers (for formal)\n"); + log("\n"); log(" -random \n"); log(" replace with random bits using the specified integer als seed\n"); log(" value for the random number generator.\n"); @@ -191,25 +203,31 @@ struct SetundefPass : public Pass { } if (args[argidx] == "-zero") { got_value = true; - worker.next_bit_mode = 0; + worker.next_bit_mode = MODE_ZERO; worker.next_bit_state = 0; continue; } if (args[argidx] == "-one") { got_value = true; - worker.next_bit_mode = 1; + worker.next_bit_mode = MODE_ONE; worker.next_bit_state = 0; continue; } if (args[argidx] == "-anyseq") { got_value = true; - worker.next_bit_mode = 2; + worker.next_bit_mode = MODE_ANYSEQ; + worker.next_bit_state = 0; + continue; + } + if (args[argidx] == "-anyconst") { + got_value = true; + worker.next_bit_mode = MODE_ANYCONST; worker.next_bit_state = 0; continue; } if (args[argidx] == "-undef") { got_value = true; - worker.next_bit_mode = 4; + worker.next_bit_mode = MODE_UNDEF; worker.next_bit_state = 0; continue; } @@ -219,7 +237,7 @@ struct SetundefPass : public Pass { } if (args[argidx] == "-random" && !got_value && argidx+1 < args.size()) { got_value = true; - worker.next_bit_mode = 3; + worker.next_bit_mode = MODE_RANDOM; worker.next_bit_state = atoi(args[++argidx].c_str()) + 1; for (int i = 0; i < 10; i++) worker.next_bit(); @@ -232,7 +250,10 @@ struct SetundefPass : public Pass { if (expose_mode && !undriven_mode) log_cmd_error("Option -expose must be used with option -undriven.\n"); if (!got_value) - log_cmd_error("One of the options -zero, -one, -anyseq, or -random must be specified.\n"); + log_cmd_error("One of the options -zero, -one, -anyseq, -anyconst, or -random must be specified.\n"); + + if (init_mode && (worker.next_bit_mode == MODE_ANYSEQ || worker.next_bit_mode == MODE_ANYCONST)) + log_cmd_error("The options -init and -anyseq / -anyconst are exclusive.\n"); for (auto module : design->selected_modules()) { @@ -419,7 +440,7 @@ struct SetundefPass : public Pass { module->rewrite_sigspecs(worker); - if (worker.next_bit_mode == 2) + if (worker.next_bit_mode == MODE_ANYSEQ || worker.next_bit_mode == MODE_ANYCONST) { vector siglist; siglist.swap(worker.siglist); @@ -436,7 +457,10 @@ struct SetundefPass : public Pass { width++; if (width > 0) { - sig.replace(cursor, module->Anyseq(NEW_ID, width)); + if (worker.next_bit_mode == MODE_ANYSEQ) + sig.replace(cursor, module->Anyseq(NEW_ID, width)); + else + sig.replace(cursor, module->Anyconst(NEW_ID, width)); cursor += width; } else { cursor++; diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index e52a192db..f1d958a1a 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -142,7 +142,7 @@ struct statdata_t } } - void log_data() + void log_data(RTLIL::IdString mod_name, bool top_mod) { log(" Number of wires: %6d\n", num_wires); log(" Number of wire bits: %6d\n", num_wire_bits); @@ -163,7 +163,7 @@ struct statdata_t if (area != 0) { log("\n"); - log(" Chip area for this module: %f\n", area); + log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area); } } }; @@ -275,7 +275,7 @@ struct StatPass : public Pass { log("\n"); log("=== %s%s ===\n", RTLIL::id2cstr(mod->name), design->selected_whole_module(mod->name) ? "" : " (partially selected)"); log("\n"); - data.log_data(); + data.log_data(mod->name, false); } if (top_mod != NULL && GetSize(mod_stat) > 1) @@ -288,7 +288,7 @@ struct StatPass : public Pass { statdata_t data = hierarchy_worker(mod_stat, top_mod->name, 0); log("\n"); - data.log_data(); + data.log_data(top_mod->name, true); } log("\n"); diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 18dfa7184..e61851481 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -18,6 +18,7 @@ */ #include "kernel/yosys.h" +#include "frontends/verific/verific.h" #include #include #include @@ -258,7 +259,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check if (mod->wires_.count(portname) == 0) log_error("Array cell `%s.%s' connects to unknown port `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(conn.first)); int port_size = mod->wires_.at(portname)->width; - if (conn_size == port_size) + if (conn_size == port_size || conn_size == 0) continue; if (conn_size != port_size*num) log_error("Array cell `%s.%s' has invalid port vs. signal size for port `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(conn.first)); @@ -421,6 +422,7 @@ struct HierarchyPass : public Pass { bool flag_simcheck = false; bool purge_lib = false; RTLIL::Module *top_mod = NULL; + std::string load_top_mod; std::vector libdirs; bool auto_top_mode = false; @@ -511,7 +513,7 @@ struct HierarchyPass : public Pass { top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL; } if (top_mod == NULL) - log_cmd_error("Module `%s' not found!\n", args[argidx].c_str()); + load_top_mod = args[argidx]; continue; } if (args[argidx] == "-auto-top") { @@ -522,6 +524,22 @@ struct HierarchyPass : public Pass { } extra_args(args, argidx, design, false); + if (!load_top_mod.empty()) { +#ifdef YOSYS_ENABLE_VERIFIC + if (verific_import_pending) { + verific_import(design, load_top_mod); + top_mod = design->module(RTLIL::escape_id(load_top_mod)); + } +#endif + if (top_mod == NULL) + log_cmd_error("Module `%s' not found!\n", load_top_mod.c_str()); + } else { +#ifdef YOSYS_ENABLE_VERIFIC + if (verific_import_pending) + verific_import(design); +#endif + } + if (generate_mode) { generate(design, generate_cells, generate_ports); return; diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc index 40691d160..6e036397d 100644 --- a/passes/memory/memory_dff.cc +++ b/passes/memory/memory_dff.cc @@ -33,8 +33,20 @@ struct MemoryDffWorker dict sigbit_users_count; dict mux_cells_a, mux_cells_b; pool forward_merged_dffs, candidate_dffs; + pool init_bits; - MemoryDffWorker(Module *module) : module(module), sigmap(module) { } + MemoryDffWorker(Module *module) : module(module), sigmap(module) + { + for (auto wire : module->wires()) { + if (wire->attributes.count("\\init") == 0) + continue; + SigSpec sig = sigmap(wire); + Const initval = wire->attributes.count("\\init"); + for (int i = 0; i < GetSize(sig) && i < GetSize(initval); i++) + if (initval[i] == State::S0 || initval[i] == State::S1) + init_bits.insert(sig[i]); + } + } bool find_sig_before_dff(RTLIL::SigSpec &sig, RTLIL::SigSpec &clk, bool &clk_polarity, bool after = false) { @@ -45,6 +57,9 @@ struct MemoryDffWorker if (bit.wire == NULL) continue; + if (!after && init_bits.count(sigmap(bit))) + return false; + for (auto cell : dff_cells) { if (after && forward_merged_dffs.count(cell)) @@ -72,6 +87,9 @@ struct MemoryDffWorker if (d.size() != 1) continue; + if (after && init_bits.count(d)) + return false; + bit = d; clk = this_clk; clk_polarity = this_clk_polarity; diff --git a/passes/memory/memory_nordff.cc b/passes/memory/memory_nordff.cc index 5f87e8b79..87ab7c623 100644 --- a/passes/memory/memory_nordff.cc +++ b/passes/memory/memory_nordff.cc @@ -61,49 +61,59 @@ struct MemoryNordffPass : public Pass { SigSpec rd_addr = cell->getPort("\\RD_ADDR"); SigSpec rd_data = cell->getPort("\\RD_DATA"); + SigSpec rd_clk = cell->getPort("\\RD_CLK"); + SigSpec rd_en = cell->getPort("\\RD_EN"); Const rd_clk_enable = cell->getParam("\\RD_CLK_ENABLE"); + Const rd_clk_polarity = cell->getParam("\\RD_CLK_POLARITY"); for (int i = 0; i < rd_ports; i++) { bool clk_enable = rd_clk_enable[i] == State::S1; - if (!clk_enable) - continue; - - bool clk_polarity = cell->getParam("\\RD_CLK_POLARITY")[i] == State::S1; - bool transparent = cell->getParam("\\RD_TRANSPARENT")[i] == State::S1; - - SigSpec clk = cell->getPort("\\RD_CLK")[i] ; - SigSpec en = cell->getPort("\\RD_EN")[i]; - Cell *c; - - if (transparent) + if (clk_enable) { - SigSpec sig_q = module->addWire(NEW_ID, abits); - SigSpec sig_d = rd_addr.extract(abits * i, abits); - rd_addr.replace(abits * i, sig_q); - if (en != State::S1) - sig_d = module->Mux(NEW_ID, sig_q, sig_d, en); - c = module->addDff(NEW_ID, clk, sig_d, sig_q, clk_polarity); - } - else - { - SigSpec sig_d = module->addWire(NEW_ID, width); - SigSpec sig_q = rd_data.extract(width * i, width); - rd_data.replace(width *i, sig_d); - if (en != State::S1) - sig_d = module->Mux(NEW_ID, sig_q, sig_d, en); - c = module->addDff(NEW_ID, clk, sig_d, sig_q, clk_polarity); + bool clk_polarity = cell->getParam("\\RD_CLK_POLARITY")[i] == State::S1; + bool transparent = cell->getParam("\\RD_TRANSPARENT")[i] == State::S1; + + SigSpec clk = cell->getPort("\\RD_CLK")[i] ; + SigSpec en = cell->getPort("\\RD_EN")[i]; + Cell *c; + + if (transparent) + { + SigSpec sig_q = module->addWire(NEW_ID, abits); + SigSpec sig_d = rd_addr.extract(abits * i, abits); + rd_addr.replace(abits * i, sig_q); + if (en != State::S1) + sig_d = module->Mux(NEW_ID, sig_q, sig_d, en); + c = module->addDff(NEW_ID, clk, sig_d, sig_q, clk_polarity); + } + else + { + SigSpec sig_d = module->addWire(NEW_ID, width); + SigSpec sig_q = rd_data.extract(width * i, width); + rd_data.replace(width *i, sig_d); + if (en != State::S1) + sig_d = module->Mux(NEW_ID, sig_q, sig_d, en); + c = module->addDff(NEW_ID, clk, sig_d, sig_q, clk_polarity); + } + + log("Extracted %s FF from read port %d of %s.%s: %s\n", transparent ? "addr" : "data", + i, log_id(module), log_id(cell), log_id(c)); } - log("Extracted %s FF from read port %d of %s.%s: %s\n", transparent ? "addr" : "data", - i, log_id(module), log_id(cell), log_id(c)); + rd_en[i] = State::S1; + rd_clk[i] = State::S0; rd_clk_enable[i] = State::S0; + rd_clk_polarity[i] = State::S1; } cell->setPort("\\RD_ADDR", rd_addr); cell->setPort("\\RD_DATA", rd_data); + cell->setPort("\\RD_CLK", rd_clk); + cell->setPort("\\RD_EN", rd_en); cell->setParam("\\RD_CLK_ENABLE", rd_clk_enable); + cell->setParam("\\RD_CLK_POLARITY", rd_clk_polarity); } } } MemoryNordffPass; diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 009ba6b97..18868c6d7 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -60,6 +60,10 @@ #include "frontends/blif/blifparse.h" +#ifdef YOSYS_LINK_ABC +extern "C" int Abc_RealMain(int argc, char *argv[]); +#endif + USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -546,11 +550,13 @@ std::string replace_tempdir(std::string text, std::string tempdir_name, bool sho } std::string selfdir_name = proc_self_dirname(); - while (1) { - size_t pos = text.find(selfdir_name); - if (pos == std::string::npos) - break; - text = text.substr(0, pos) + "/" + text.substr(pos + GetSize(selfdir_name)); + if (selfdir_name != "/") { + while (1) { + size_t pos = text.find(selfdir_name); + if (pos == std::string::npos) + break; + text = text.substr(0, pos) + "/" + text.substr(pos + GetSize(selfdir_name)); + } } return text; @@ -943,8 +949,24 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str()); log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str()); +#ifndef YOSYS_LINK_ABC abc_output_filter filt(tempdir_name, show_tempdir); int ret = run_command(buffer, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1)); +#else + // These needs to be mutable, supposedly due to getopt + char *abc_argv[5]; + string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str()); + abc_argv[0] = strdup(exe_file.c_str()); + abc_argv[1] = strdup("-s"); + abc_argv[2] = strdup("-f"); + abc_argv[3] = strdup(tmp_script_name.c_str()); + abc_argv[4] = 0; + int ret = Abc_RealMain(4, abc_argv); + free(abc_argv[0]); + free(abc_argv[1]); + free(abc_argv[2]); + free(abc_argv[3]); +#endif if (ret != 0) log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret); diff --git a/passes/techmap/deminout.cc b/passes/techmap/deminout.cc index ed4e45762..0b8fd5246 100644 --- a/passes/techmap/deminout.cc +++ b/passes/techmap/deminout.cc @@ -57,7 +57,7 @@ struct DeminoutPass : public Pass { for (auto module : design->selected_modules()) { SigMap sigmap(module); - pool bits_written, bits_used, bits_inout; + pool bits_written, bits_used, bits_inout, bits_tribuf; dict bits_numports; for (auto wire : module->wires()) @@ -82,6 +82,25 @@ struct DeminoutPass : public Pass { if (cellport_in) for (auto bit : sigmap(conn.second)) bits_used.insert(bit); + + if (conn.first == "\\Y" && cell->type.in("$mux", "$pmux", "$_MUX_", "$_TBUF_")) + { + bool tribuf = (cell->type == "$_TBUF_"); + + if (!tribuf) { + for (auto &c : cell->connections()) { + if (!c.first.in("\\A", "\\B")) + continue; + for (auto b : sigmap(c.second)) + if (b == State::Sz) + tribuf = true; + } + } + + if (tribuf) + for (auto bit : sigmap(conn.second)) + bits_tribuf.insert(bit); + } } for (auto wire : module->selected_wires()) @@ -95,10 +114,15 @@ struct DeminoutPass : public Pass { if (bits_numports[bit] > 1 || bits_inout.count(bit)) new_input = true, new_output = true; - if (bits_written.count(bit)) + if (bits_written.count(bit)) { new_output = true; - else if (bits_used.count(bit)) - new_input = true; + if (bits_tribuf.count(bit)) + goto tribuf_bit; + } else { + tribuf_bit: + if (bits_used.count(bit)) + new_input = true; + } } if (new_input != new_output) { diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc index 4acbf7c0d..690ba87ed 100644 --- a/passes/techmap/iopadmap.cc +++ b/passes/techmap/iopadmap.cc @@ -146,11 +146,37 @@ struct IopadmapPass : public Pass { for (auto module : design->selected_modules()) { dict> skip_wires; + pool skip_wire_bits; + SigMap sigmap(module); + + for (auto cell : module->cells()) + { + if (cell->type == RTLIL::escape_id(inpad_celltype) && cell->hasPort(RTLIL::escape_id(inpad_portname2))) + for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(inpad_portname2)))) + skip_wire_bits.insert(bit); + + if (cell->type == RTLIL::escape_id(outpad_celltype) && cell->hasPort(RTLIL::escape_id(outpad_portname2))) + for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(outpad_portname2)))) + skip_wire_bits.insert(bit); + + if (cell->type == RTLIL::escape_id(inoutpad_celltype) && cell->hasPort(RTLIL::escape_id(inoutpad_portname2))) + for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(inoutpad_portname2)))) + skip_wire_bits.insert(bit); + + if (cell->type == RTLIL::escape_id(toutpad_celltype) && cell->hasPort(RTLIL::escape_id(toutpad_portname3))) + for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(toutpad_portname3)))) + skip_wire_bits.insert(bit); + + if (cell->type == RTLIL::escape_id(tinoutpad_celltype) && cell->hasPort(RTLIL::escape_id(tinoutpad_portname4))) + for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(tinoutpad_portname4)))) + skip_wire_bits.insert(bit); + } if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty()) { - SigMap sigmap(module); dict>> tbuf_bits; + pool> norewrites; + SigMap rewrites; for (auto cell : module->cells()) if (cell->type == "$_TBUF_") { @@ -177,6 +203,9 @@ struct IopadmapPass : public Pass { if (tbuf_bits.count(mapped_wire_bit) == 0) continue; + if (skip_wire_bits.count(mapped_wire_bit)) + continue; + auto &tbuf_cache = tbuf_bits.at(mapped_wire_bit); Cell *tbuf_cell = module->cell(tbuf_cache.first); @@ -219,6 +248,9 @@ struct IopadmapPass : public Pass { module->remove(tbuf_cell); skip_wires[wire->name].insert(i); + + norewrites.insert(make_pair(cell->name, RTLIL::escape_id(tinoutpad_portname4))); + rewrites.add(sigmap(wire_bit), owire); continue; } @@ -256,6 +288,22 @@ struct IopadmapPass : public Pass { } } } + + if (GetSize(norewrites)) + { + for (auto cell : module->cells()) + for (auto port : cell->connections()) + { + if (norewrites.count(make_pair(cell->name, port.first))) + continue; + + SigSpec orig_sig = sigmap(port.second); + SigSpec new_sig = rewrites(orig_sig); + + if (orig_sig != new_sig) + cell->setPort(port.first, new_sig); + } + } } for (auto wire : module->selected_wires()) @@ -272,6 +320,13 @@ struct IopadmapPass : public Pass { skip_bit_indices = skip_wires.at(wire->name); } + for (int i = 0; i < GetSize(wire); i++) + if (skip_wire_bits.count(sigmap(SigBit(wire, i)))) + skip_bit_indices.insert(i); + + if (GetSize(wire) == GetSize(skip_bit_indices)) + continue; + if (wire->port_input && !wire->port_output) { if (inpad_celltype.empty()) { log("Don't map input port %s.%s: Missing option -inpad.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name)); diff --git a/techlibs/common/prep.cc b/techlibs/common/prep.cc index 3dfc60383..cc977f97e 100644 --- a/techlibs/common/prep.cc +++ b/techlibs/common/prep.cc @@ -55,13 +55,14 @@ struct PrepPass : public ScriptPass log("\n"); log(" -memx\n"); log(" simulate verilog simulation behavior for out-of-bounds memory accesses\n"); - log(" using the 'memory_memx' pass. This option implies -nordff.\n"); + log(" using the 'memory_memx' pass.\n"); log("\n"); log(" -nomem\n"); log(" do not run any of the memory_* passes\n"); log("\n"); - log(" -nordff\n"); - log(" passed to 'memory_dff'. prohibits merging of FFs into memory read ports\n"); + log(" -rdff\n"); + log(" do not pass -nordff to 'memory_dff'. This enables merging of FFs into\n"); + log(" memory read ports.\n"); log("\n"); log(" -nokeepdc\n"); log(" do not call opt_* with -keepdc\n"); @@ -77,13 +78,12 @@ struct PrepPass : public ScriptPass log("\n"); } - string top_module, fsm_opts, memory_opts; - bool autotop, flatten, ifxmode, memxmode, nomemmode, nokeepdc; + string top_module, fsm_opts; + bool autotop, flatten, ifxmode, memxmode, nomemmode, nokeepdc, nordff; virtual void clear_flags() YS_OVERRIDE { top_module.clear(); - memory_opts.clear(); autotop = false; flatten = false; @@ -91,6 +91,7 @@ struct PrepPass : public ScriptPass memxmode = false; nomemmode = false; nokeepdc = false; + nordff = true; } virtual void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE @@ -129,7 +130,6 @@ struct PrepPass : public ScriptPass } if (args[argidx] == "-memx") { memxmode = true; - memory_opts += " -nordff"; continue; } if (args[argidx] == "-nomem") { @@ -137,7 +137,11 @@ struct PrepPass : public ScriptPass continue; } if (args[argidx] == "-nordff") { - memory_opts += " -nordff"; + nordff = true; + continue; + } + if (args[argidx] == "-rdff") { + nordff = false; continue; } if (args[argidx] == "-nokeepdc") { @@ -196,7 +200,7 @@ struct PrepPass : public ScriptPass run(memxmode ? "wreduce -memx" : "wreduce"); } if (!nomemmode) { - run("memory_dff" + (help_mode ? " [-nordff]" : memory_opts)); + run(string("memory_dff") + (help_mode ? " [-nordff]" : nordff ? " -nordff" : "")); if (help_mode || memxmode) run("memory_memx", "(if -memx)"); run("opt_clean"); diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v index 814895e70..45a02111f 100644 --- a/techlibs/ice40/cells_sim.v +++ b/techlibs/ice40/cells_sim.v @@ -1,6 +1,6 @@ -`define SB_DFF_REG reg Q = 0; -// `define SB_DFF_REG reg Q; +`define SB_DFF_REG reg Q = 0 +// `define SB_DFF_REG reg Q // SiliconBlue IO Cells @@ -132,21 +132,18 @@ endmodule // Positive Edge SiliconBlue FF Cells -module SB_DFF (output Q, input C, D); - `SB_DFF_REG +module SB_DFF (output `SB_DFF_REG, input C, D); always @(posedge C) Q <= D; endmodule -module SB_DFFE (output Q, input C, E, D); - `SB_DFF_REG +module SB_DFFE (output `SB_DFF_REG, input C, E, D); always @(posedge C) if (E) Q <= D; endmodule -module SB_DFFSR (output Q, input C, R, D); - `SB_DFF_REG +module SB_DFFSR (output `SB_DFF_REG, input C, R, D); always @(posedge C) if (R) Q <= 0; @@ -154,8 +151,7 @@ module SB_DFFSR (output Q, input C, R, D); Q <= D; endmodule -module SB_DFFR (output Q, input C, R, D); - `SB_DFF_REG +module SB_DFFR (output `SB_DFF_REG, input C, R, D); always @(posedge C, posedge R) if (R) Q <= 0; @@ -163,8 +159,7 @@ module SB_DFFR (output Q, input C, R, D); Q <= D; endmodule -module SB_DFFSS (output Q, input C, S, D); - `SB_DFF_REG +module SB_DFFSS (output `SB_DFF_REG, input C, S, D); always @(posedge C) if (S) Q <= 1; @@ -172,8 +167,7 @@ module SB_DFFSS (output Q, input C, S, D); Q <= D; endmodule -module SB_DFFS (output Q, input C, S, D); - `SB_DFF_REG +module SB_DFFS (output `SB_DFF_REG, input C, S, D); always @(posedge C, posedge S) if (S) Q <= 1; @@ -181,8 +175,7 @@ module SB_DFFS (output Q, input C, S, D); Q <= D; endmodule -module SB_DFFESR (output Q, input C, E, R, D); - `SB_DFF_REG +module SB_DFFESR (output `SB_DFF_REG, input C, E, R, D); always @(posedge C) if (E) begin if (R) @@ -192,8 +185,7 @@ module SB_DFFESR (output Q, input C, E, R, D); end endmodule -module SB_DFFER (output Q, input C, E, R, D); - `SB_DFF_REG +module SB_DFFER (output `SB_DFF_REG, input C, E, R, D); always @(posedge C, posedge R) if (R) Q <= 0; @@ -201,8 +193,7 @@ module SB_DFFER (output Q, input C, E, R, D); Q <= D; endmodule -module SB_DFFESS (output Q, input C, E, S, D); - `SB_DFF_REG +module SB_DFFESS (output `SB_DFF_REG, input C, E, S, D); always @(posedge C) if (E) begin if (S) @@ -212,8 +203,7 @@ module SB_DFFESS (output Q, input C, E, S, D); end endmodule -module SB_DFFES (output Q, input C, E, S, D); - `SB_DFF_REG +module SB_DFFES (output `SB_DFF_REG, input C, E, S, D); always @(posedge C, posedge S) if (S) Q <= 1; @@ -223,21 +213,18 @@ endmodule // Negative Edge SiliconBlue FF Cells -module SB_DFFN (output Q, input C, D); - `SB_DFF_REG +module SB_DFFN (output `SB_DFF_REG, input C, D); always @(negedge C) Q <= D; endmodule -module SB_DFFNE (output Q, input C, E, D); - `SB_DFF_REG +module SB_DFFNE (output `SB_DFF_REG, input C, E, D); always @(negedge C) if (E) Q <= D; endmodule -module SB_DFFNSR (output Q, input C, R, D); - `SB_DFF_REG +module SB_DFFNSR (output `SB_DFF_REG, input C, R, D); always @(negedge C) if (R) Q <= 0; @@ -245,8 +232,7 @@ module SB_DFFNSR (output Q, input C, R, D); Q <= D; endmodule -module SB_DFFNR (output Q, input C, R, D); - `SB_DFF_REG +module SB_DFFNR (output `SB_DFF_REG, input C, R, D); always @(negedge C, posedge R) if (R) Q <= 0; @@ -254,8 +240,7 @@ module SB_DFFNR (output Q, input C, R, D); Q <= D; endmodule -module SB_DFFNSS (output Q, input C, S, D); - `SB_DFF_REG +module SB_DFFNSS (output `SB_DFF_REG, input C, S, D); always @(negedge C) if (S) Q <= 1; @@ -263,8 +248,7 @@ module SB_DFFNSS (output Q, input C, S, D); Q <= D; endmodule -module SB_DFFNS (output Q, input C, S, D); - `SB_DFF_REG +module SB_DFFNS (output `SB_DFF_REG, input C, S, D); always @(negedge C, posedge S) if (S) Q <= 1; @@ -272,8 +256,7 @@ module SB_DFFNS (output Q, input C, S, D); Q <= D; endmodule -module SB_DFFNESR (output Q, input C, E, R, D); - `SB_DFF_REG +module SB_DFFNESR (output `SB_DFF_REG, input C, E, R, D); always @(negedge C) if (E) begin if (R) @@ -283,8 +266,7 @@ module SB_DFFNESR (output Q, input C, E, R, D); end endmodule -module SB_DFFNER (output Q, input C, E, R, D); - `SB_DFF_REG +module SB_DFFNER (output `SB_DFF_REG, input C, E, R, D); always @(negedge C, posedge R) if (R) Q <= 0; @@ -292,8 +274,7 @@ module SB_DFFNER (output Q, input C, E, R, D); Q <= D; endmodule -module SB_DFFNESS (output Q, input C, E, S, D); - `SB_DFF_REG +module SB_DFFNESS (output `SB_DFF_REG, input C, E, S, D); always @(negedge C) if (E) begin if (S) @@ -303,8 +284,7 @@ module SB_DFFNESS (output Q, input C, E, S, D); end endmodule -module SB_DFFNES (output Q, input C, E, S, D); - `SB_DFF_REG +module SB_DFFNES (output `SB_DFF_REG, input C, E, S, D); always @(negedge C, posedge S) if (S) Q <= 1; @@ -677,7 +657,7 @@ module ICESTORM_LC ( parameter [0:0] SET_NORESET = 0; parameter [0:0] ASYNC_SR = 0; - wire COUT = CARRY_ENABLE ? (I1 && I2) || ((I1 || I2) && CIN) : 1'bx; + assign COUT = CARRY_ENABLE ? (I1 && I2) || ((I1 || I2) && CIN) : 1'bx; wire [7:0] lut_s3 = I3 ? LUT_INIT[15:8] : LUT_INIT[7:0]; wire [3:0] lut_s2 = I2 ? lut_s3[ 7:4] : lut_s3[3:0]; diff --git a/techlibs/ice40/ice40_opt.cc b/techlibs/ice40/ice40_opt.cc index ae72f5d64..7af60f297 100644 --- a/techlibs/ice40/ice40_opt.cc +++ b/techlibs/ice40/ice40_opt.cc @@ -26,6 +26,13 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +static SigBit get_bit_or_zero(const SigSpec &sig) +{ + if (GetSize(sig) == 0) + return State::S0; + return sig[0]; +} + static void run_ice40_opts(Module *module, bool unlut_mode) { pool optimized_co; @@ -45,7 +52,11 @@ static void run_ice40_opts(Module *module, bool unlut_mode) SigSpec non_const_inputs, replacement_output; int count_zeros = 0, count_ones = 0; - SigBit inbit[3] = {cell->getPort("\\I0"), cell->getPort("\\I1"), cell->getPort("\\CI")}; + SigBit inbit[3] = { + get_bit_or_zero(cell->getPort("\\I0")), + get_bit_or_zero(cell->getPort("\\I1")), + get_bit_or_zero(cell->getPort("\\CI")) + }; for (int i = 0; i < 3; i++) if (inbit[i].wire == nullptr) { if (inbit[i] == State::S1) @@ -63,8 +74,8 @@ static void run_ice40_opts(Module *module, bool unlut_mode) replacement_output = non_const_inputs; if (GetSize(replacement_output)) { - optimized_co.insert(sigmap(cell->getPort("\\CO"))); - module->connect(cell->getPort("\\CO"), replacement_output); + optimized_co.insert(sigmap(cell->getPort("\\CO")[0])); + module->connect(cell->getPort("\\CO")[0], replacement_output); module->design->scratchpad_set_bool("opt.did_something", true); log("Optimized away SB_CARRY cell %s.%s: CO=%s\n", log_id(module), log_id(cell), log_signal(replacement_output)); @@ -78,10 +89,10 @@ static void run_ice40_opts(Module *module, bool unlut_mode) { SigSpec inbits; - inbits.append(cell->getPort("\\I0")); - inbits.append(cell->getPort("\\I1")); - inbits.append(cell->getPort("\\I2")); - inbits.append(cell->getPort("\\I3")); + inbits.append(get_bit_or_zero(cell->getPort("\\I0"))); + inbits.append(get_bit_or_zero(cell->getPort("\\I1"))); + inbits.append(get_bit_or_zero(cell->getPort("\\I2"))); + inbits.append(get_bit_or_zero(cell->getPort("\\I3"))); sigmap.apply(inbits); if (unlut_mode) @@ -104,8 +115,13 @@ static void run_ice40_opts(Module *module, bool unlut_mode) cell->setParam("\\LUT", cell->getParam("\\LUT_INIT")); cell->unsetParam("\\LUT_INIT"); - cell->setPort("\\A", SigSpec({cell->getPort("\\I3"), cell->getPort("\\I2"), cell->getPort("\\I1"), cell->getPort("\\I0")})); - cell->setPort("\\Y", cell->getPort("\\O")); + cell->setPort("\\A", SigSpec({ + get_bit_or_zero(cell->getPort("\\I3")), + get_bit_or_zero(cell->getPort("\\I2")), + get_bit_or_zero(cell->getPort("\\I1")), + get_bit_or_zero(cell->getPort("\\I0")) + })); + cell->setPort("\\Y", cell->getPort("\\O")[0]); cell->unsetPort("\\I0"); cell->unsetPort("\\I1"); cell->unsetPort("\\I2"); diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 177581d53..abd890a56 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -45,7 +45,11 @@ struct SynthIce40Pass : public ScriptPass log(" is omitted if this parameter is not specified.\n"); log("\n"); log(" -edif \n"); - log(" write the design to the specified edif file. writing of an output file\n"); + log(" write the design to the specified EDIF file. writing of an output file\n"); + log(" is omitted if this parameter is not specified.\n"); + log("\n"); + log(" -json \n"); + log(" write the design to the specified JSON file. writing of an output file\n"); log(" is omitted if this parameter is not specified.\n"); log("\n"); log(" -run :\n"); @@ -81,7 +85,7 @@ struct SynthIce40Pass : public ScriptPass log("\n"); } - string top_opt, blif_file, edif_file; + string top_opt, blif_file, edif_file, json_file; bool nocarry, nodffe, nobram, flatten, retime, abc2, vpr; virtual void clear_flags() YS_OVERRIDE @@ -89,6 +93,7 @@ struct SynthIce40Pass : public ScriptPass top_opt = "-auto-top"; blif_file = ""; edif_file = ""; + json_file = ""; nocarry = false; nodffe = false; nobram = false; @@ -118,6 +123,10 @@ struct SynthIce40Pass : public ScriptPass edif_file = args[++argidx]; continue; } + if (args[argidx] == "-json" && argidx+1 < args.size()) { + json_file = args[++argidx]; + continue; + } if (args[argidx] == "-run" && argidx+1 < args.size()) { size_t pos = args[argidx+1].find(':'); if (pos == std::string::npos) @@ -260,17 +269,15 @@ struct SynthIce40Pass : public ScriptPass if (!blif_file.empty() || help_mode) { if (vpr || help_mode) { run(stringf("opt_clean -purge"), - " " - " (vpr mode)"); + " (vpr mode)"); run(stringf("write_blif -attr -cname -conn -param %s", - help_mode ? "" : blif_file.c_str()), - " (vpr mode)"); + help_mode ? "" : blif_file.c_str()), + " (vpr mode)"); } if (!vpr) run(stringf("write_blif -gates -attr -param %s", - help_mode ? "" : blif_file.c_str()), - " " - " (non-vpr mode)"); + help_mode ? "" : blif_file.c_str()), + " (non-vpr mode)"); } } @@ -279,6 +286,12 @@ struct SynthIce40Pass : public ScriptPass if (!edif_file.empty() || help_mode) run(stringf("write_edif %s", help_mode ? "" : edif_file.c_str())); } + + if (check_label("json")) + { + if (!json_file.empty() || help_mode) + run(stringf("write_json %s", help_mode ? "" : json_file.c_str())); + } } } SynthIce40Pass; diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh index 31a6ae8ab..d6216244f 100755 --- a/tests/tools/autotest.sh +++ b/tests/tools/autotest.sh @@ -100,7 +100,7 @@ do echo -n "Test: $bn " fi - rm -f ${bn}.{err,log,sikp} + rm -f ${bn}.{err,log,skip} mkdir -p ${bn}.out rm -rf ${bn}.out/*