diff options
61 files changed, 806 insertions, 401 deletions
diff --git a/.editorconfig b/.editorconfig index 4d6f5ef7a..f5444d81a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,3 +5,8 @@ indent_style = tab indent_size = tab trim_trailing_whitespace = true insert_final_newline = true + +[abc/**] +indent_style = space +indent_size = 2 +trim_trailing_whitespace = false @@ -8,7 +8,7 @@ Yosys 0.9 .. Yosys 0.9-dev * Various - Added "write_xaiger" backend - - Added "abc9" pass for timing-aware techmapping (experimental, FPGA only, no FFs) + - Added "abc9" pass for timing-aware techmapping (experimental, FPGA only) - Added "synth_xilinx -abc9" (experimental) - Added "synth_ice40 -abc9" (experimental) - Added "synth -abc9" (experimental) @@ -58,7 +58,6 @@ Yosys 0.9 .. Yosys 0.9-dev - Added support for SystemVerilog wildcard port connections (.*) - Added "xilinx_dffopt" pass - Added "scratchpad" pass - - Added "abc9 -dff" - Added "synth_xilinx -dff" - Improved support of $readmem[hb] Memory Content File inclusion - Added "opt_lut_ins" pass @@ -66,6 +65,7 @@ Yosys 0.9 .. Yosys 0.9-dev - Removed "dffsr2dff" (use opt_rmdff instead) - Added "design -delete" - Added "select -unset" + - Use YosysHQ/abc instead of upstream berkeley-abc/abc Yosys 0.8 .. Yosys 0.9 ---------------------- @@ -4,6 +4,7 @@ CONFIG := clang # CONFIG := gcc-4.8 # CONFIG := afl-gcc # CONFIG := emcc +# CONFIG := wasi # CONFIG := mxe # CONFIG := msys2 # CONFIG := msys2-64 @@ -32,7 +33,9 @@ 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) +# Needed for environments that can't run executables (i.e. emscripten, wasm) +DISABLE_SPAWN := 0 +# Needed for environments that don't have proper thread support (i.e. emscripten, wasm--for now) DISABLE_ABC_THREADS := 0 # clang sanitizers @@ -42,7 +45,7 @@ SANITIZER = # SANITIZER = undefined # SANITIZER = cfi -PROGRAM_PREFIX := +PROGRAM_PREFIX := OS := $(shell uname -s) PREFIX ?= /usr/local @@ -133,9 +136,9 @@ bumpversion: # 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 = ed90ce2 +ABCREV = d14acd8 ABCPULL = 1 -ABCURL ?= https://github.com/berkeley-abc/abc +ABCURL ?= https://github.com/YosysHQ/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 # set ABCEXTERNAL = <abc-command> to use an external ABC instance @@ -253,6 +256,8 @@ LDFLAGS += $(EMCCFLAGS) LDLIBS = EXE = .js +DISABLE_SPAWN := 1 + TARGETS := $(filter-out $(PROGRAM_PREFIX)yosys-config,$(TARGETS)) EXTRA_TARGETS += yosysjs-$(YOSYS_VER).zip @@ -274,6 +279,35 @@ yosysjs-$(YOSYS_VER).zip: yosys.js yosys.wasm viz.js misc/yosysjs/* yosys.html: misc/yosys.html $(P) cp misc/yosys.html yosys.html +else ifeq ($(CONFIG),wasi) +ifeq ($(WASI_SDK),) +CXX = clang++ +LD = clang++ +AR = llvm-ar +RANLIB = llvm-ranlib +WASIFLAGS := -target wasm32-wasi --sysroot $(WASI_SYSROOT) $(WASIFLAGS) +else +CXX = $(WASI_SDK)/bin/clang++ +LD = $(WASI_SDK)/bin/clang++ +AR = $(WASI_SDK)/bin/ar +RANLIB = $(WASI_SDK)/bin/ranlib +WASIFLAGS := --sysroot $(WASI_SDK)/share/wasi-sysroot $(WASIFLAGS) +endif +CXXFLAGS := $(WASIFLAGS) -std=c++11 -Os $(filter-out -fPIC,$(CXXFLAGS)) +LDFLAGS := $(WASIFLAGS) -Wl,-z,stack-size=1048576 $(filter-out -rdynamic,$(LDFLAGS)) +LDLIBS := $(filter-out -lrt,$(LDLIBS)) +ABCMKARGS += AR="$(AR)" RANLIB="$(RANLIB)" +ABCMKARGS += ARCHFLAGS="$(WASIFLAGS) -DABC_USE_STDINT_H -DABC_NO_DYNAMIC_LINKING" +ABCMKARGS += OPTFLAGS="-Os" +EXE = .wasm + +DISABLE_SPAWN := 1 + +ifeq ($(ENABLE_ABC),1) +LINK_ABC := 1 +DISABLE_ABC_THREADS := 1 +endif + else ifeq ($(CONFIG),mxe) PKG_CONFIG = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-pkg-config CXX = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-g++ @@ -396,6 +430,10 @@ ifeq ($(DISABLE_ABC_THREADS),1) ABCMKARGS += "ABC_USE_NO_PTHREADS=1" endif +ifeq ($(DISABLE_SPAWN),1) +CXXFLAGS += -DYOSYS_DISABLE_SPAWN +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) @@ -584,10 +622,10 @@ include $(YOSYS_SRC)/techlibs/*/Makefile.inc else -include frontends/verilog/Makefile.inc -include frontends/ilang/Makefile.inc -include frontends/ast/Makefile.inc -include frontends/blif/Makefile.inc +include $(YOSYS_SRC)/frontends/verilog/Makefile.inc +include $(YOSYS_SRC)/frontends/ilang/Makefile.inc +include $(YOSYS_SRC)/frontends/ast/Makefile.inc +include $(YOSYS_SRC)/frontends/blif/Makefile.inc OBJS += passes/hierarchy/hierarchy.o OBJS += passes/cmds/select.o @@ -597,14 +635,14 @@ OBJS += passes/cmds/cover.o OBJS += passes/cmds/design.o OBJS += passes/cmds/plugin.o -include passes/proc/Makefile.inc -include passes/opt/Makefile.inc -include passes/techmap/Makefile.inc +include $(YOSYS_SRC)/passes/proc/Makefile.inc +include $(YOSYS_SRC)/passes/opt/Makefile.inc +include $(YOSYS_SRC)/passes/techmap/Makefile.inc -include backends/verilog/Makefile.inc -include backends/ilang/Makefile.inc +include $(YOSYS_SRC)/backends/verilog/Makefile.inc +include $(YOSYS_SRC)/backends/ilang/Makefile.inc -include techlibs/common/Makefile.inc +include $(YOSYS_SRC)/techlibs/common/Makefile.inc endif @@ -911,6 +949,14 @@ config-emcc: clean echo 'ENABLE_READLINE := 0' >> Makefile.conf echo 'ENABLE_ZLIB := 0' >> Makefile.conf +config-wasi: clean + echo 'CONFIG := wasi' > Makefile.conf + echo 'ENABLE_TCL := 0' >> Makefile.conf + echo 'ENABLE_ABC := 0' >> Makefile.conf + echo 'ENABLE_PLUGINS := 0' >> Makefile.conf + echo 'ENABLE_READLINE := 0' >> Makefile.conf + echo 'ENABLE_ZLIB := 0' >> Makefile.conf + config-mxe: clean echo 'CONFIG := mxe' > Makefile.conf echo 'ENABLE_PLUGINS := 0' >> Makefile.conf @@ -118,6 +118,13 @@ Tests are located in the tests subdirectory and can be executed using the test t $ make test +To use a separate (out-of-tree) build directory, provide a path to the Makefile. + + $ mkdir build; cd build + $ make -f ../Makefile + +Out-of-tree builds require a clean source tree. + Getting Started =============== @@ -388,7 +395,7 @@ Verilog Attributes and non-standard features - The cell attribute ``wildcard_port_conns`` represents wildcard port connections (SystemVerilog ``.*``). These are resolved to concrete - connections to matching wires in ``hierarchy``. + connections to matching wires in ``hierarchy``. - In addition to the ``(* ... *)`` attribute syntax, Yosys supports the non-standard ``{* ... *}`` attribute syntax to set default attributes diff --git a/backends/aiger/aiger.cc b/backends/aiger/aiger.cc index cac32a8da..e5a41b5c5 100644 --- a/backends/aiger/aiger.cc +++ b/backends/aiger/aiger.cc @@ -629,30 +629,30 @@ struct AigerWriter int a = aig_map.at(sig[i]); if (verbose_map) - wire_lines[a] += stringf("wire %d %d %s\n", a, i, log_id(wire)); + wire_lines[a] += stringf("wire %d %d %s\n", a, wire->start_offset+i, log_id(wire)); if (wire->port_input) { log_assert((a & 1) == 0); - input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, i, log_id(wire)); + input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, wire->start_offset+i, log_id(wire)); } if (wire->port_output) { int o = ordered_outputs.at(sig[i]); - output_lines[o] += stringf("output %d %d %s\n", o, i, log_id(wire)); + output_lines[o] += stringf("output %d %d %s\n", o, wire->start_offset+i, log_id(wire)); } if (init_inputs.count(sig[i])) { int a = init_inputs.at(sig[i]); log_assert((a & 1) == 0); - init_lines[a] += stringf("init %d %d %s\n", (a >> 1)-1, i, log_id(wire)); + init_lines[a] += stringf("init %d %d %s\n", (a >> 1)-1, wire->start_offset+i, log_id(wire)); } if (ordered_latches.count(sig[i])) { int l = ordered_latches.at(sig[i]); if (zinit_mode && (aig_latchinit.at(l) == 1)) - latch_lines[l] += stringf("invlatch %d %d %s\n", l, i, log_id(wire)); + latch_lines[l] += stringf("invlatch %d %d %s\n", l, wire->start_offset+i, log_id(wire)); else - latch_lines[l] += stringf("latch %d %d %s\n", l, i, log_id(wire)); + latch_lines[l] += stringf("latch %d %d %s\n", l, wire->start_offset+i, log_id(wire)); } } } diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 3c7c745fe..1fb7210cb 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -725,13 +725,12 @@ struct XAigerWriter if (input_bits.count(b)) { int a = aig_map.at(b); log_assert((a & 1) == 0); - input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, i, log_id(wire)); + input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, wire->start_offset+i, log_id(wire)); } if (output_bits.count(b)) { int o = ordered_outputs.at(b); - int init = 2; - output_lines[o] += stringf("output %d %d %s %d\n", o - GetSize(co_bits), i, log_id(wire), init); + output_lines[o] += stringf("output %d %d %s\n", o - GetSize(co_bits), wire->start_offset+i, log_id(wire)); continue; } } diff --git a/backends/cxxrtl/cxxrtl.cc b/backends/cxxrtl/cxxrtl.cc index 237700b29..e7711962f 100644 --- a/backends/cxxrtl/cxxrtl.cc +++ b/backends/cxxrtl/cxxrtl.cc @@ -212,14 +212,14 @@ bool is_ff_cell(RTLIL::IdString type) bool is_internal_cell(RTLIL::IdString type) { - return type[0] == '$' && !type.begins_with("$paramod\\"); + return type[0] == '$' && !type.begins_with("$paramod"); } bool is_cxxrtl_blackbox_cell(const RTLIL::Cell *cell) { RTLIL::Module *cell_module = cell->module->design->module(cell->type); log_assert(cell_module != nullptr); - return cell_module->get_bool_attribute(ID(cxxrtl.blackbox)); + return cell_module->get_bool_attribute(ID(cxxrtl_blackbox)); } enum class CxxrtlPortType { @@ -231,14 +231,14 @@ enum class CxxrtlPortType { CxxrtlPortType cxxrtl_port_type(const RTLIL::Cell *cell, RTLIL::IdString port) { RTLIL::Module *cell_module = cell->module->design->module(cell->type); - if (cell_module == nullptr || !cell_module->get_bool_attribute(ID(cxxrtl.blackbox))) + if (cell_module == nullptr || !cell_module->get_bool_attribute(ID(cxxrtl_blackbox))) return CxxrtlPortType::UNKNOWN; RTLIL::Wire *cell_output_wire = cell_module->wire(port); log_assert(cell_output_wire != nullptr); - bool is_comb = cell_output_wire->get_bool_attribute(ID(cxxrtl.comb)); - bool is_sync = cell_output_wire->get_bool_attribute(ID(cxxrtl.sync)); + bool is_comb = cell_output_wire->get_bool_attribute(ID(cxxrtl_comb)); + bool is_sync = cell_output_wire->get_bool_attribute(ID(cxxrtl_sync)); if (is_comb && is_sync) - log_cmd_error("Port `%s.%s' is marked as both `cxxrtl.comb` and `cxxrtl.sync`.\n", + log_cmd_error("Port `%s.%s' is marked as both `cxxrtl_comb` and `cxxrtl_sync`.\n", log_id(cell_module), log_signal(cell_output_wire)); else if (is_comb) return CxxrtlPortType::COMB; @@ -606,7 +606,7 @@ struct CxxrtlWorker { std::string mangle(const RTLIL::Module *module) { - return mangle_module_name(module->name, /*is_blackbox=*/module->get_bool_attribute(ID(cxxrtl.blackbox))); + return mangle_module_name(module->name, /*is_blackbox=*/module->get_bool_attribute(ID(cxxrtl_blackbox))); } std::string mangle(const RTLIL::Memory *memory) @@ -634,19 +634,19 @@ struct CxxrtlWorker { std::vector<std::string> template_param_names(const RTLIL::Module *module) { - if (!module->has_attribute(ID(cxxrtl.template))) + if (!module->has_attribute(ID(cxxrtl_template))) return {}; - if (module->attributes.at(ID(cxxrtl.template)).flags != RTLIL::CONST_FLAG_STRING) - log_cmd_error("Attribute `cxxrtl.template' of module `%s' is not a string.\n", log_id(module)); + if (module->attributes.at(ID(cxxrtl_template)).flags != RTLIL::CONST_FLAG_STRING) + log_cmd_error("Attribute `cxxrtl_template' of module `%s' is not a string.\n", log_id(module)); - std::vector<std::string> param_names = split_by(module->get_string_attribute(ID(cxxrtl.template)), " \t"); + std::vector<std::string> param_names = split_by(module->get_string_attribute(ID(cxxrtl_template)), " \t"); for (const auto ¶m_name : param_names) { // Various lowercase prefixes (p_, i_, cell_, ...) are used for member variables, so require // parameters to start with an uppercase letter to avoid name conflicts. (This is the convention // in both Verilog and C++, anyway.) if (!isupper(param_name[0])) - log_cmd_error("Attribute `cxxrtl.template' of module `%s' includes a parameter `%s', " + log_cmd_error("Attribute `cxxrtl_template' of module `%s' includes a parameter `%s', " "which does not start with an uppercase letter.\n", log_id(module), param_name.c_str()); } @@ -677,7 +677,7 @@ struct CxxrtlWorker { { RTLIL::Module *cell_module = cell->module->design->module(cell->type); log_assert(cell_module != nullptr); - if (!cell_module->get_bool_attribute(ID(cxxrtl.blackbox))) + if (!cell_module->get_bool_attribute(ID(cxxrtl_blackbox))) return ""; std::vector<std::string> param_names = template_param_names(cell_module); @@ -726,12 +726,13 @@ struct CxxrtlWorker { void dump_const_init(const RTLIL::Const &data, int width, int offset = 0, bool fixed_width = false) { + const int CHUNK_SIZE = 32; f << "{"; while (width > 0) { - const int CHUNK_SIZE = 32; - uint32_t chunk = data.extract(offset, width > CHUNK_SIZE ? CHUNK_SIZE : width).as_int(); + int chunk_width = min(width, CHUNK_SIZE); + uint32_t chunk = data.extract(offset, chunk_width).as_int(); if (fixed_width) - f << stringf("0x%08xu", chunk); + f << stringf("0x%.*xu", (3 + chunk_width) / 4, chunk); else f << stringf("%#xu", chunk); if (width > CHUNK_SIZE) @@ -1418,8 +1419,8 @@ struct CxxrtlWorker { f << indent << "value<" << wire->width << "> " << mangle(wire) << ";\n"; } else { std::string width; - if (wire->module->has_attribute(ID(cxxrtl.blackbox)) && wire->has_attribute(ID(cxxrtl.width))) { - width = wire->get_string_attribute(ID(cxxrtl.width)); + if (wire->module->has_attribute(ID(cxxrtl_blackbox)) && wire->has_attribute(ID(cxxrtl_width))) { + width = wire->get_string_attribute(ID(cxxrtl_width)); } else { width = std::to_string(wire->width); } @@ -1521,7 +1522,7 @@ struct CxxrtlWorker { { inc_indent(); f << indent << "bool converged = " << (eval_converges.at(module) ? "true" : "false") << ";\n"; - if (!module->get_bool_attribute(ID(cxxrtl.blackbox))) { + if (!module->get_bool_attribute(ID(cxxrtl_blackbox))) { for (auto wire : module->wires()) { if (edge_wires[wire]) { for (auto edge_type : edge_types) { @@ -1573,10 +1574,10 @@ struct CxxrtlWorker { f << indent << "prev_" << mangle(wire) << " = " << mangle(wire) << ";\n"; continue; } - if (!module->get_bool_attribute(ID(cxxrtl.blackbox)) || wire->port_id != 0) + if (!module->get_bool_attribute(ID(cxxrtl_blackbox)) || wire->port_id != 0) f << indent << "changed |= " << mangle(wire) << ".commit();\n"; } - if (!module->get_bool_attribute(ID(cxxrtl.blackbox))) { + if (!module->get_bool_attribute(ID(cxxrtl_blackbox))) { for (auto memory : module->memories) { if (!writable_memories[memory.second]) continue; @@ -1623,8 +1624,8 @@ struct CxxrtlWorker { void dump_module_intf(RTLIL::Module *module) { dump_attrs(module); - if (module->get_bool_attribute(ID(cxxrtl.blackbox))) { - if (module->has_attribute(ID(cxxrtl.template))) + if (module->get_bool_attribute(ID(cxxrtl_blackbox))) { + if (module->has_attribute(ID(cxxrtl_template))) f << indent << "template" << template_params(module, /*is_decl=*/true) << "\n"; f << indent << "struct " << mangle(module) << " : public module {\n"; inc_indent(); @@ -1686,7 +1687,7 @@ struct CxxrtlWorker { dump_attrs(cell); RTLIL::Module *cell_module = module->design->module(cell->type); log_assert(cell_module != nullptr); - if (cell_module->get_bool_attribute(ID(cxxrtl.blackbox))) { + if (cell_module->get_bool_attribute(ID(cxxrtl_blackbox))) { f << indent << "std::unique_ptr<" << mangle(cell_module) << template_args(cell) << "> "; f << mangle(cell) << " = " << mangle(cell_module) << template_args(cell); f << "::create(" << escape_cxx_string(cell->name.str()) << ", "; @@ -1711,7 +1712,7 @@ struct CxxrtlWorker { void dump_module_impl(RTLIL::Module *module) { - if (module->get_bool_attribute(ID(cxxrtl.blackbox))) + if (module->get_bool_attribute(ID(cxxrtl_blackbox))) return; f << indent << "bool " << mangle(module) << "::eval() {\n"; dump_eval_method(module); @@ -1730,9 +1731,9 @@ struct CxxrtlWorker { for (auto module : design->modules()) { if (!design->selected_module(module)) continue; - if (module->get_bool_attribute(ID(cxxrtl.blackbox))) + if (module->get_bool_attribute(ID(cxxrtl_blackbox))) modules.push_back(module); // cxxrtl blackboxes first - if (module->get_blackbox_attribute() || module->get_bool_attribute(ID(cxxrtl.blackbox))) + if (module->get_blackbox_attribute() || module->get_bool_attribute(ID(cxxrtl_blackbox))) continue; topo_design.node(module); @@ -1821,16 +1822,16 @@ struct CxxrtlWorker { SigMap &sigmap = sigmaps[module]; sigmap.set(module); - if (module->get_bool_attribute(ID(cxxrtl.blackbox))) { + if (module->get_bool_attribute(ID(cxxrtl_blackbox))) { for (auto port : module->ports) { RTLIL::Wire *wire = module->wire(port); - if (wire->has_attribute(ID(cxxrtl.edge))) { - RTLIL::Const edge_attr = wire->attributes[ID(cxxrtl.edge)]; + if (wire->has_attribute(ID(cxxrtl_edge))) { + RTLIL::Const edge_attr = wire->attributes[ID(cxxrtl_edge)]; if (!(edge_attr.flags & RTLIL::CONST_FLAG_STRING) || (int)edge_attr.decode_string().size() != GetSize(wire)) - log_cmd_error("Attribute `cxxrtl.edge' of port `%s.%s' is not a string with one character per bit.\n", + log_cmd_error("Attribute `cxxrtl_edge' of port `%s.%s' is not a string with one character per bit.\n", log_id(module), log_signal(wire)); - std::string edges = wire->get_string_attribute(ID(cxxrtl.edge)); + std::string edges = wire->get_string_attribute(ID(cxxrtl_edge)); for (int i = 0; i < GetSize(wire); i++) { RTLIL::SigSpec wire_sig = wire; switch (edges[i]) { @@ -1839,7 +1840,7 @@ struct CxxrtlWorker { case 'n': register_edge_signal(sigmap, wire_sig[i], RTLIL::STn); break; case 'a': register_edge_signal(sigmap, wire_sig[i], RTLIL::STe); break; default: - log_cmd_error("Attribute `cxxrtl.edge' of port `%s.%s' contains specifiers " + log_cmd_error("Attribute `cxxrtl_edge' of port `%s.%s' contains specifiers " "other than '-', 'p', 'n', or 'a'.\n", log_id(module), log_signal(wire)); } @@ -1868,12 +1869,12 @@ struct CxxrtlWorker { RTLIL::Module *cell_module = design->module(cell->type); if (cell_module && cell_module->get_blackbox_attribute() && - !cell_module->get_bool_attribute(ID(cxxrtl.blackbox))) + !cell_module->get_bool_attribute(ID(cxxrtl_blackbox))) log_cmd_error("External blackbox cell `%s' is not marked as a CXXRTL blackbox.\n", log_id(cell->type)); if (cell_module && - cell_module->get_bool_attribute(ID(cxxrtl.blackbox)) && - cell_module->get_bool_attribute(ID(cxxrtl.template))) + cell_module->get_bool_attribute(ID(cxxrtl_blackbox)) && + cell_module->get_bool_attribute(ID(cxxrtl_template))) blackbox_specializations[cell_module].insert(template_args(cell)); FlowGraph::Node *node = flow.add_node(cell); @@ -2064,7 +2065,7 @@ struct CxxrtlWorker { has_sync_init = has_packed_mem = false; for (auto module : design->modules()) { - if (module->get_blackbox_attribute() && !module->has_attribute(ID(cxxrtl.blackbox))) + if (module->get_blackbox_attribute() && !module->has_attribute(ID(cxxrtl_blackbox))) continue; if (!design->selected_whole_module(module)) @@ -2155,12 +2156,12 @@ struct CxxrtlBackend : public Backend { log("For example, the following Verilog code defines a CXXRTL black box interface for\n"); log("a synchronous debug sink:\n"); log("\n"); - log(" (* cxxrtl.blackbox *)\n"); + log(" (* cxxrtl_blackbox *)\n"); log(" module debug(...);\n"); - log(" (* cxxrtl.edge = \"p\" *) input clk;\n"); + log(" (* cxxrtl_edge = \"p\" *) input clk;\n"); log(" input en;\n"); log(" input [7:0] i_data;\n"); - log(" (* cxxrtl.sync *) output [7:0] o_data;\n"); + log(" (* cxxrtl_sync *) output [7:0] o_data;\n"); log(" endmodule\n"); log("\n"); log("For this HDL interface, this backend will generate the following C++ interface:\n"); @@ -2205,13 +2206,13 @@ struct CxxrtlBackend : public Backend { log("port widths. For example, the following Verilog code defines a CXXRTL black box\n"); log("interface for a configurable width debug sink:\n"); log("\n"); - log(" (* cxxrtl.blackbox, cxxrtl.template = \"WIDTH\" *)\n"); + log(" (* cxxrtl_blackbox, cxxrtl_template = \"WIDTH\" *)\n"); log(" module debug(...);\n"); log(" parameter WIDTH = 8;\n"); - log(" (* cxxrtl.edge = \"p\" *) input clk;\n"); + log(" (* cxxrtl_edge = \"p\" *) input clk;\n"); log(" input en;\n"); - log(" (* cxxrtl.width = \"WIDTH\" *) input [WIDTH - 1:0] i_data;\n"); - log(" (* cxxrtl.width = \"WIDTH\" *) output [WIDTH - 1:0] o_data;\n"); + log(" (* cxxrtl_width = \"WIDTH\" *) input [WIDTH - 1:0] i_data;\n"); + log(" (* cxxrtl_width = \"WIDTH\" *) output [WIDTH - 1:0] o_data;\n"); log(" endmodule\n"); log("\n"); log("For this parametric HDL interface, this backend will generate the following C++\n"); @@ -2245,27 +2246,27 @@ struct CxxrtlBackend : public Backend { log("\n"); log("The following attributes are recognized by this backend:\n"); log("\n"); - log(" cxxrtl.blackbox\n"); + log(" cxxrtl_blackbox\n"); log(" only valid on modules. if specified, the module contents are ignored,\n"); log(" and the generated code includes only the module interface and a factory\n"); log(" function, which will be called to instantiate the module.\n"); log("\n"); - log(" cxxrtl.edge\n"); + log(" cxxrtl_edge\n"); log(" only valid on inputs of black boxes. must be one of \"p\", \"n\", \"a\".\n"); log(" if specified on signal `clk`, the generated code includes edge detectors\n"); log(" `posedge_p_clk()` (if \"p\"), `negedge_p_clk()` (if \"n\"), or both (if\n"); log(" \"a\"), simplifying implementation of clocked black boxes.\n"); log("\n"); - log(" cxxrtl.template\n"); + log(" cxxrtl_template\n"); log(" only valid on black boxes. must contain a space separated sequence of\n"); log(" identifiers that have a corresponding black box parameters. for each\n"); log(" of them, the generated code includes a `size_t` template parameter.\n"); log("\n"); - log(" cxxrtl.width\n"); + log(" cxxrtl_width\n"); log(" only valid on ports of black boxes. must be a constant expression, which\n"); log(" is directly inserted into generated code.\n"); log("\n"); - log(" cxxrtl.comb, cxxrtl.sync\n"); + log(" cxxrtl_comb, cxxrtl_sync\n"); log(" only valid on outputs of black boxes. if specified, indicates that every\n"); log(" bit of the output port is driven, correspondingly, by combinatorial or\n"); log(" synchronous logic. this knowledge is used for scheduling optimizations.\n"); diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index 92cf92fa8..6fda92d73 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -784,7 +784,7 @@ void AigerReader::post_process() ff->attributes[ID::abc9_mergeability] = mergeability[i]; } - dict<RTLIL::IdString, int> wideports_cache; + dict<RTLIL::IdString, std::pair<int,int>> wideports_cache; if (!map_filename.empty()) { std::ifstream mf(map_filename); @@ -799,11 +799,12 @@ void AigerReader::post_process() log_assert(wire->port_input); log_debug("Renaming input %s", log_id(wire)); + RTLIL::Wire *existing = nullptr; if (index == 0) { // Cope with the fact that a CI might be identical // to a PI (necessary due to ABC); in those cases // simply connect the latter to the former - RTLIL::Wire* existing = module->wire(escaped_s); + existing = module->wire(escaped_s); if (!existing) module->rename(wire, escaped_s); else { @@ -812,20 +813,29 @@ void AigerReader::post_process() } log_debug(" -> %s\n", log_id(escaped_s)); } - else if (index > 0) { - std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index); - RTLIL::Wire* existing = module->wire(indexed_name); - if (!existing) { + else { + RTLIL::IdString indexed_name = stringf("%s[%d]", escaped_s.c_str(), index); + existing = module->wire(indexed_name); + if (!existing) module->rename(wire, indexed_name); - if (wideports) - wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index); - } else { module->connect(wire, existing); wire->port_input = false; } log_debug(" -> %s\n", log_id(indexed_name)); } + + if (wideports && !existing) { + auto r = wideports_cache.insert(escaped_s); + if (r.second) { + r.first->second.first = index; + r.first->second.second = index; + } + else { + r.first->second.first = std::min(r.first->second.first, index); + r.first->second.second = std::max(r.first->second.second, index); + } + } } else if (type == "output") { log_assert(static_cast<unsigned>(variable + co_count) < outputs.size()); @@ -834,14 +844,14 @@ void AigerReader::post_process() log_assert(wire->port_output); log_debug("Renaming output %s", log_id(wire)); + RTLIL::Wire *existing; if (index == 0) { // Cope with the fact that a CO might be identical // to a PO (necessary due to ABC); in those cases // simply connect the latter to the former - RTLIL::Wire* existing = module->wire(escaped_s); - if (!existing) { + existing = module->wire(escaped_s); + if (!existing) module->rename(wire, escaped_s); - } else { wire->port_output = false; existing->port_output = true; @@ -850,14 +860,11 @@ void AigerReader::post_process() } log_debug(" -> %s\n", log_id(escaped_s)); } - else if (index > 0) { - std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index); - RTLIL::Wire* existing = module->wire(indexed_name); - if (!existing) { + else { + RTLIL::IdString indexed_name = stringf("%s[%d]", escaped_s.c_str(), index); + existing = module->wire(indexed_name); + if (!existing) module->rename(wire, indexed_name); - if (wideports) - wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index); - } else { wire->port_output = false; existing->port_output = true; @@ -865,10 +872,18 @@ void AigerReader::post_process() } log_debug(" -> %s\n", log_id(indexed_name)); } - int init; - mf >> init; - if (init < 2) - wire->attributes[ID::init] = init; + + if (wideports && !existing) { + auto r = wideports_cache.insert(escaped_s); + if (r.second) { + r.first->second.first = index; + r.first->second.second = index; + } + else { + r.first->second.first = std::min(r.first->second.first, index); + r.first->second.second = std::max(r.first->second.second, index); + } + } } else if (type == "box") { RTLIL::Cell* cell = module->cell(stringf("$box%d", variable)); @@ -882,7 +897,8 @@ void AigerReader::post_process() for (auto &wp : wideports_cache) { auto name = wp.first; - int width = wp.second + 1; + int min = wp.second.first; + int max = wp.second.second; RTLIL::Wire *wire = module->wire(name); if (wire) @@ -891,7 +907,7 @@ void AigerReader::post_process() // Do not make ports with a mix of input/output into // wide ports bool port_input = false, port_output = false; - for (int i = 0; i < width; i++) { + for (int i = min; i <= max; i++) { RTLIL::IdString other_name = name.str() + stringf("[%d]", i); RTLIL::Wire *other_wire = module->wire(other_name); if (other_wire) { @@ -900,20 +916,21 @@ void AigerReader::post_process() } } - wire = module->addWire(name, width); + wire = module->addWire(name, max-min+1); + wire->start_offset = min; wire->port_input = port_input; wire->port_output = port_output; - for (int i = 0; i < width; i++) { - RTLIL::IdString other_name = name.str() + stringf("[%d]", i); + for (int i = min; i <= max; i++) { + RTLIL::IdString other_name = stringf("%s[%d]", name.c_str(), i); RTLIL::Wire *other_wire = module->wire(other_name); if (other_wire) { other_wire->port_input = false; other_wire->port_output = false; if (wire->port_input) - module->connect(other_wire, SigSpec(wire, i)); + module->connect(other_wire, SigSpec(wire, i-min)); else - module->connect(SigSpec(wire, i), other_wire); + module->connect(SigSpec(wire, i-min), other_wire); } } } diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 733556621..6a9af3f57 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -946,6 +946,7 @@ RTLIL::Const AstNode::realAsConst(int width) // create a new AstModule from an AST_MODULE AST node static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast = NULL, bool quiet = false) { + log_assert(current_scope.empty()); log_assert(ast->type == AST_MODULE || ast->type == AST_INTERFACE); if (defer) @@ -1117,6 +1118,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast } ignoreThisSignalsInInitial = RTLIL::SigSpec(); + current_scope.clear(); } else { for (auto &attr : ast->attributes) { @@ -1229,11 +1231,13 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump // process enum/other declarations (*it)->simplify(true, false, false, 1, -1, false, false); design->verilog_packages.push_back((*it)->clone()); + current_scope.clear(); } else { // must be global definition (*it)->simplify(false, false, false, 1, -1, false, false); //process enum/other declarations design->verilog_globals.push_back((*it)->clone()); + current_scope.clear(); } } } diff --git a/frontends/rpc/Makefile.inc b/frontends/rpc/Makefile.inc index 7b270b6fe..fa1d068f9 100644 --- a/frontends/rpc/Makefile.inc +++ b/frontends/rpc/Makefile.inc @@ -1,3 +1,3 @@ -ifneq ($(CONFIG),emcc) +ifeq ($(DISABLE_SPAWN),0) OBJS += frontends/rpc/rpc_frontend.o endif diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 519151310..fe4bda68e 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -149,7 +149,7 @@ RTLIL::IdString VerificImporter::new_verific_id(Verific::DesignObj *obj) return s; } -void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, DesignObj *obj) +void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, DesignObj *obj, Netlist *nl) { MapIter mi; Att *attr; @@ -163,6 +163,68 @@ void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &att continue; attributes[RTLIL::escape_id(attr->Key())] = RTLIL::Const(std::string(attr->Value())); } + + if (nl) { + auto type_range = nl->GetTypeRange(obj->Name()); + if (!type_range) + return; + if (!type_range->IsTypeEnum()) + return; + if (nl->IsFromVhdl() && strcmp(type_range->GetTypeName(), "STD_LOGIC") == 0) + return; + auto type_name = type_range->GetTypeName(); + if (!type_name) + return; + attributes.emplace(ID::wiretype, RTLIL::escape_id(type_name)); + + MapIter mi; + const char *k, *v; + FOREACH_MAP_ITEM(type_range->GetEnumIdMap(), mi, &k, &v) { + if (nl->IsFromVerilog()) { + // Expect <decimal>'b<binary> + auto p = strchr(v, '\''); + if (p) { + if (*(p+1) != 'b') + p = nullptr; + else + for (auto q = p+2; *q != '\0'; q++) + if (*q != '0' && *q != '1') { + p = nullptr; + break; + } + } + if (p == nullptr) + log_error("Expected TypeRange value '%s' to be of form <decimal>'b<binary>.\n", v); + attributes.emplace(stringf("\\enum_value_%s", p+2), RTLIL::escape_id(k)); + } + else if (nl->IsFromVhdl()) { + // Expect "<binary>" + auto p = v; + if (p) { + if (*p != '"') + p = nullptr; + else { + auto *q = p+1; + for (; *q != '"'; q++) + if (*q != '0' && *q != '1') { + p = nullptr; + break; + } + if (p && *(q+1) != '\0') + p = nullptr; + } + } + if (p == nullptr) + log_error("Expected TypeRange value '%s' to be of form \"<binary>\".\n", v); + auto l = strlen(p); + auto q = (char*)malloc(l+1-2); + strncpy(q, p+1, l-2); + q[l-2] = '\0'; + attributes.emplace(stringf("\\enum_value_%s", q), RTLIL::escape_id(k)); + free(q); + } + } + } } RTLIL::SigSpec VerificImporter::operatorInput(Instance *inst) @@ -845,7 +907,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se log(" importing port %s.\n", port->Name()); RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(port->Name())); - import_attributes(wire->attributes, port); + import_attributes(wire->attributes, port, nl); wire->port_id = nl->IndexOf(port) + 1; @@ -872,7 +934,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(portbus->Name()), portbus->Size()); wire->start_offset = min(portbus->LeftIndex(), portbus->RightIndex()); - import_attributes(wire->attributes, portbus); + import_attributes(wire->attributes, portbus, nl); if (portbus->GetDir() == DIR_INOUT || portbus->GetDir() == DIR_IN) wire->port_input = true; @@ -1021,7 +1083,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se log(" importing net %s as %s.\n", net->Name(), log_id(wire_name)); RTLIL::Wire *wire = module->addWire(wire_name); - import_attributes(wire->attributes, net); + import_attributes(wire->attributes, net, nl); net_map[net] = wire; } @@ -1046,7 +1108,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se RTLIL::Wire *wire = module->addWire(wire_name, netbus->Size()); wire->start_offset = min(netbus->LeftIndex(), netbus->RightIndex()); - import_attributes(wire->attributes, netbus); + import_attributes(wire->attributes, netbus, nl); RTLIL::Const initval = Const(State::Sx, GetSize(wire)); bool initval_valid = false; diff --git a/frontends/verific/verific.h b/frontends/verific/verific.h index 2ccfcd42c..f168a2588 100644 --- a/frontends/verific/verific.h +++ b/frontends/verific/verific.h @@ -79,7 +79,7 @@ struct VerificImporter RTLIL::SigBit net_map_at(Verific::Net *net); RTLIL::IdString new_verific_id(Verific::DesignObj *obj); - void import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, Verific::DesignObj *obj); + void import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, Verific::DesignObj *obj, Verific::Netlist *nl = nullptr); RTLIL::SigSpec operatorInput(Verific::Instance *inst); RTLIL::SigSpec operatorInput1(Verific::Instance *inst); diff --git a/kernel/constids.inc b/kernel/constids.inc index 68a5782fd..27b652e24 100644 --- a/kernel/constids.inc +++ b/kernel/constids.inc @@ -29,6 +29,7 @@ X(B) X(BI) X(blackbox) X(B_SIGNED) +X(bugpoint_keep) X(B_WIDTH) X(C) X(cells_not_processed) @@ -199,6 +200,7 @@ X(wand) X(whitebox) X(WIDTH) X(wildcard_port_conns) +X(wiretype) X(wor) X(WORDS) X(WR_ADDR) diff --git a/kernel/driver.cc b/kernel/driver.cc index 5f0959776..57ed7b8b4 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -155,6 +155,19 @@ int yosys_history_offset = 0; std::string yosys_history_file; #endif +#if defined(__wasm) +extern "C" { + // FIXME: WASI does not currently support exceptions. + void* __cxa_allocate_exception(size_t thrown_size) throw() { + return malloc(thrown_size); + } + bool __cxa_uncaught_exception() throw(); + void __cxa_throw(void* thrown_exception, struct std::type_info * tinfo, void (*dest)(void*)) { + std::terminate(); + } +} +#endif + void yosys_atexit() { #if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) @@ -587,9 +600,11 @@ int main(int argc, char **argv) ru_buffer.ru_utime.tv_usec += ru_buffer_children.ru_utime.tv_usec; ru_buffer.ru_stime.tv_sec += ru_buffer_children.ru_stime.tv_sec; ru_buffer.ru_stime.tv_usec += ru_buffer_children.ru_stime.tv_usec; +#if defined(__linux__) || defined(__FreeBSD__) ru_buffer.ru_maxrss = std::max(ru_buffer.ru_maxrss, ru_buffer_children.ru_maxrss); +#endif } -# if defined(__linux__) || defined(__FreeBSD__) +#if defined(__linux__) || defined(__FreeBSD__) meminfo = stringf(", MEM: %.2f MB peak", ru_buffer.ru_maxrss / 1024.0); #endif diff --git a/kernel/register.cc b/kernel/register.cc index 925d0d776..02974e534 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -238,6 +238,7 @@ void Pass::call(RTLIL::Design *design, std::string command) return; if (tok[0] == '!') { +#if !defined(YOSYS_DISABLE_SPAWN) cmd_buf = command.substr(command.find('!') + 1); while (!cmd_buf.empty() && (cmd_buf.back() == ' ' || cmd_buf.back() == '\t' || cmd_buf.back() == '\r' || cmd_buf.back() == '\n')) @@ -247,6 +248,9 @@ void Pass::call(RTLIL::Design *design, std::string command) if (retCode != 0) log_cmd_error("Shell command returned error code %d.\n", retCode); return; +#else + log_cmd_error("Shell is not available.\n"); +#endif } while (!tok.empty()) { diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 2aefe30b1..196e301b6 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -2619,16 +2619,15 @@ void RTLIL::Cell::setParam(RTLIL::IdString paramname, RTLIL::Const value) const RTLIL::Const &RTLIL::Cell::getParam(RTLIL::IdString paramname) const { - static const RTLIL::Const empty; const auto &it = parameters.find(paramname); if (it != parameters.end()) return it->second; if (module && module->design) { RTLIL::Module *m = module->design->module(type); if (m) - return m->parameter_default_values.at(paramname, empty); + return m->parameter_default_values.at(paramname); } - return empty; + throw std::out_of_range("Cell::getParam()"); } void RTLIL::Cell::sort() diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 01131601f..2ec3dca0c 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -45,8 +45,10 @@ # include <unistd.h> # include <dirent.h> # include <sys/types.h> -# include <sys/wait.h> # include <sys/stat.h> +# if !defined(YOSYS_DISABLE_SPAWN) +# include <sys/wait.h> +# endif #endif #if !defined(_WIN32) && defined(YOSYS_ENABLE_GLOB) @@ -336,16 +338,13 @@ bool patmatch(const char *pattern, const char *string) return false; } +#if !defined(YOSYS_DISABLE_SPAWN) int run_command(const std::string &command, std::function<void(const std::string&)> process_line) { if (!process_line) return system(command.c_str()); -#ifdef EMSCRIPTEN - FILE *f = nullptr; -#else FILE *f = popen(command.c_str(), "r"); -#endif if (f == nullptr) return -1; @@ -368,10 +367,16 @@ int run_command(const std::string &command, std::function<void(const std::string return WEXITSTATUS(ret); #endif } +#endif std::string make_temp_file(std::string template_str) { -#ifdef _WIN32 +#if defined(__wasm) + size_t pos = template_str.rfind("XXXXXX"); + log_assert(pos != std::string::npos); + static size_t index = 0; + template_str.replace(pos, 6, stringf("%06zu", index++)); +#elif defined(_WIN32) if (template_str.rfind("/tmp/", 0) == 0) { # ifdef __MINGW32__ char longpath[MAX_PATH + 1]; @@ -420,10 +425,14 @@ std::string make_temp_file(std::string template_str) std::string make_temp_dir(std::string template_str) { -#ifdef _WIN32 +#if defined(_WIN32) template_str = make_temp_file(template_str); mkdir(template_str.c_str()); return template_str; +#elif defined(__wasm) + template_str = make_temp_file(template_str); + mkdir(template_str.c_str(), 0777); + return template_str; #else # ifndef NDEBUG size_t pos = template_str.rfind("XXXXXX"); @@ -806,7 +815,7 @@ std::string proc_self_dirname() path += char(shortpath[i]); return path; } -#elif defined(EMSCRIPTEN) +#elif defined(EMSCRIPTEN) || defined(__wasm) std::string proc_self_dirname() { return "/"; @@ -815,7 +824,7 @@ std::string proc_self_dirname() #error "Don't know how to determine process executable base path!" #endif -#ifdef EMSCRIPTEN +#if defined(EMSCRIPTEN) || defined(__wasm) std::string proc_share_dirname() { return "/share/"; diff --git a/kernel/yosys.h b/kernel/yosys.h index ed48eec09..af1e376b1 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -264,7 +264,9 @@ int readsome(std::istream &f, char *s, int n); std::string next_token(std::string &text, const char *sep = " \t\r\n", bool long_strings = false); std::vector<std::string> split_tokens(const std::string &text, const char *sep = " \t\r\n"); bool patmatch(const char *pattern, const char *string); +#if !defined(YOSYS_DISABLE_SPAWN) int run_command(const std::string &command, std::function<void(const std::string&)> process_line = std::function<void(const std::string&)>()); +#endif std::string make_temp_file(std::string template_str = "/tmp/yosys_XXXXXX"); std::string make_temp_dir(std::string template_str = "/tmp/yosys_XXXXXX"); bool check_file_exists(std::string filename, bool is_exec = false); diff --git a/libs/ezsat/ezminisat.cc b/libs/ezsat/ezminisat.cc index 4be5fd493..ac4defac3 100644 --- a/libs/ezsat/ezminisat.cc +++ b/libs/ezsat/ezminisat.cc @@ -29,11 +29,12 @@ #include <limits.h> #include <stdint.h> -#include <csignal> #include <cinttypes> -#ifndef _WIN32 +#if !defined(_WIN32) && !defined(__wasm) +# include <csignal> # include <unistd.h> +# define HAS_ALARM #endif #include "../minisat/Solver.h" @@ -84,7 +85,7 @@ bool ezMiniSAT::eliminated(int idx) } #endif -#ifndef _WIN32 +#if defined(HAS_ALARM) ezMiniSAT *ezMiniSAT::alarmHandlerThis = NULL; clock_t ezMiniSAT::alarmHandlerTimeout = 0; @@ -183,7 +184,7 @@ contradiction: #endif } -#ifndef _WIN32 +#if defined(HAS_ALARM) struct sigaction sig_action; struct sigaction old_sig_action; int old_alarm_timeout = 0; @@ -202,7 +203,7 @@ contradiction: bool foundSolution = minisatSolver->solve(assumps); -#ifndef _WIN32 +#if defined(HAS_ALARM) if (solverTimeout > 0) { if (alarmHandlerTimeout == 0) solverTimoutStatus = true; diff --git a/libs/minisat/00_PATCH_wasm.patch b/libs/minisat/00_PATCH_wasm.patch new file mode 100644 index 000000000..0bcff7d77 --- /dev/null +++ b/libs/minisat/00_PATCH_wasm.patch @@ -0,0 +1,34 @@ +--- System.cc ++++ System.cc +@@ -101,7 +101,7 @@ double Minisat::memUsedPeak(bool) { return 0; } + #endif + + +-#if !defined(_MSC_VER) && !defined(__MINGW32__) ++#if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__wasm) + void Minisat::limitMemory(uint64_t max_mem_mb) + { + // FIXME: OpenBSD does not support RLIMIT_AS. Not sure how well RLIMIT_DATA works instead. +@@ -133,7 +133,7 @@ void Minisat::limitMemory(uint64_t /*max_mem_mb*/) + #endif + + +-#if !defined(_MSC_VER) && !defined(__MINGW32__) ++#if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__wasm) + void Minisat::limitTime(uint32_t max_cpu_time) + { + if (max_cpu_time != 0){ +@@ -156,9 +156,13 @@ void Minisat::limitTime(uint32_t /*max_cpu_time*/) + + void Minisat::sigTerm(void handler(int)) + { ++#if defined(__wasm) ++ (void)handler; ++#else + signal(SIGINT, handler); + signal(SIGTERM,handler); + #ifdef SIGXCPU + signal(SIGXCPU,handler); + #endif ++#endif + } diff --git a/libs/minisat/00_UPDATE.sh b/libs/minisat/00_UPDATE.sh index ea26215ab..51107e450 100755 --- a/libs/minisat/00_UPDATE.sh +++ b/libs/minisat/00_UPDATE.sh @@ -16,4 +16,4 @@ patch -p0 < 00_PATCH_mkLit_default_arg.patch patch -p0 < 00_PATCH_remove_zlib.patch patch -p0 < 00_PATCH_no_fpu_control.patch patch -p0 < 00_PATCH_typofixes.patch - +patch -p0 < 00_PATCH_wasm.patch diff --git a/libs/minisat/System.cc b/libs/minisat/System.cc index 1921a1d71..345be8c4c 100644 --- a/libs/minisat/System.cc +++ b/libs/minisat/System.cc @@ -101,7 +101,7 @@ double Minisat::memUsedPeak(bool) { return 0; } #endif -#if !defined(_MSC_VER) && !defined(__MINGW32__) +#if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__wasm) void Minisat::limitMemory(uint64_t max_mem_mb) { // FIXME: OpenBSD does not support RLIMIT_AS. Not sure how well RLIMIT_DATA works instead. @@ -133,7 +133,7 @@ void Minisat::limitMemory(uint64_t /*max_mem_mb*/) #endif -#if !defined(_MSC_VER) && !defined(__MINGW32__) +#if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__wasm) void Minisat::limitTime(uint32_t max_cpu_time) { if (max_cpu_time != 0){ @@ -156,9 +156,13 @@ void Minisat::limitTime(uint32_t /*max_cpu_time*/) void Minisat::sigTerm(void handler(int)) { +#if defined(__wasm) + (void)handler; +#else signal(SIGINT, handler); signal(SIGTERM,handler); #ifdef SIGXCPU signal(SIGXCPU,handler); #endif +#endif } diff --git a/manual/CHAPTER_Auxprogs.tex b/manual/CHAPTER_Auxprogs.tex index 724d37f0b..f09b18f76 100644 --- a/manual/CHAPTER_Auxprogs.tex +++ b/manual/CHAPTER_Auxprogs.tex @@ -19,7 +19,8 @@ for details. \section{yosys-abc} -This is a unmodified copy of ABC \citeweblink{ABC}. Not all versions of Yosys -work with all versions of ABC. So Yosys comes with its own yosys-abc to avoid +This is a fork of ABC \citeweblink{ABC} with a small set of custom modifications +that have not yet been accepted upstream. Not all versions of Yosys work with +all versions of ABC. So Yosys comes with its own yosys-abc to avoid compatibility issues between the two. diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc index 60f20fa6d..a88980eaf 100644 --- a/passes/cmds/Makefile.inc +++ b/passes/cmds/Makefile.inc @@ -1,5 +1,7 @@ +ifeq ($(DISABLE_SPAWN),0) OBJS += passes/cmds/exec.o +endif OBJS += passes/cmds/add.o OBJS += passes/cmds/delete.o OBJS += passes/cmds/design.o @@ -32,6 +34,8 @@ OBJS += passes/cmds/chformal.o OBJS += passes/cmds/chtype.o OBJS += passes/cmds/blackbox.o OBJS += passes/cmds/ltp.o +ifeq ($(DISABLE_SPAWN),0) OBJS += passes/cmds/bugpoint.o +endif OBJS += passes/cmds/scratchpad.o OBJS += passes/cmds/logger.o diff --git a/passes/cmds/bugpoint.cc b/passes/cmds/bugpoint.cc index a75927393..00aac596f 100644 --- a/passes/cmds/bugpoint.cc +++ b/passes/cmds/bugpoint.cc @@ -30,23 +30,21 @@ struct BugpointPass : public Pass { { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" bugpoint [options]\n"); + log(" bugpoint [options] -script <filename>\n"); log("\n"); - log("This command minimizes testcases that crash Yosys. It removes an arbitrary part\n"); - log("of the design and recursively invokes Yosys with a given script, repeating these\n"); - log("steps while it can find a smaller design that still causes a crash. Once this\n"); - log("command finishes, it replaces the current design with the smallest testcase it\n"); - log("was able to produce.\n"); + log("This command minimizes the current design that is known to crash Yosys with the\n"); + log("given script into a smaller testcase. It does this by removing an arbitrary part\n"); + log("of the design and recursively invokes a new Yosys process with this modified design\n"); + log("and the same script, repeating these steps while it can find a smaller design that\n"); + log("still causes a crash. Once this command finishes, it replaces the current design\n"); + log("with the smallest testcase it was able to produce.\n"); log("\n"); - log("It is possible to specify the kinds of design part that will be removed. If none\n"); - log("are specified, all parts of design will be removed.\n"); + log(" -script <filename>\n"); + log(" use this script to crash Yosys. required.\n"); log("\n"); log(" -yosys <filename>\n"); log(" use this Yosys binary. if not specified, `yosys` is used.\n"); log("\n"); - log(" -script <filename>\n"); - log(" use this script to crash Yosys. required.\n"); - log("\n"); log(" -grep <string>\n"); log(" only consider crashes that place this string in the log file.\n"); log("\n"); @@ -60,14 +58,21 @@ struct BugpointPass : public Pass { log(" finishing. produces smaller and more useful testcases, but may fail to\n"); log(" produce any testcase at all if the crash is related to dangling wires.\n"); log("\n"); + log("It is possible to constrain which parts of the design will be considered for\n"); + log("removal. Unless one or more of the following options are specified, all parts\n"); + log("will be considered.\n"); + log("\n"); log(" -modules\n"); - log(" try to remove modules.\n"); + log(" try to remove modules. modules with a (* bugpoint_keep *) attribute\n"); + log(" will be skipped.\n"); log("\n"); log(" -ports\n"); - log(" try to remove module ports.\n"); + log(" try to remove module ports. ports with a (* bugpoint_keep *) attribute\n"); + log(" will be skipped (useful for clocks, resets, etc.)\n"); log("\n"); log(" -cells\n"); - log(" try to remove cells.\n"); + log(" try to remove cells. cells with a (* bugpoint_keep *) attribute will\n"); + log(" be skipped.\n"); log("\n"); log(" -connections\n"); log(" try to reconnect ports to 'x.\n"); @@ -139,9 +144,12 @@ struct BugpointPass : public Pass { if (module->get_blackbox_attribute()) continue; + if (module->get_bool_attribute(ID::bugpoint_keep)) + continue; + if (index++ == seed) { - log("Trying to remove module %s.\n", module->name.c_str()); + log_header(design, "Trying to remove module %s.\n", log_id(module)); removed_module = module; break; } @@ -160,18 +168,21 @@ struct BugpointPass : public Pass { for (auto wire : mod->wires()) { + if (!wire->port_id) + continue; + if (!stage2 && wire->get_bool_attribute(ID($bugpoint))) continue; - if (wire->port_input || wire->port_output) + if (wire->get_bool_attribute(ID::bugpoint_keep)) + continue; + + if (index++ == seed) { - if (index++ == seed) - { - log("Trying to remove module port %s.\n", log_signal(wire)); - wire->port_input = wire->port_output = false; - mod->fixup_ports(); - return design_copy; - } + log_header(design, "Trying to remove module port %s.\n", log_id(wire)); + wire->port_input = wire->port_output = false; + mod->fixup_ports(); + return design_copy; } } } @@ -183,12 +194,16 @@ struct BugpointPass : public Pass { if (mod->get_blackbox_attribute()) continue; + Cell *removed_cell = nullptr; for (auto cell : mod->cells()) { + if (cell->get_bool_attribute(ID::bugpoint_keep)) + continue; + if (index++ == seed) { - log("Trying to remove cell %s.%s.\n", mod->name.c_str(), cell->name.c_str()); + log_header(design, "Trying to remove cell %s.%s.\n", log_id(mod), log_id(cell)); removed_cell = cell; break; } @@ -219,7 +234,7 @@ struct BugpointPass : public Pass { if (index++ == seed) { - log("Trying to remove cell port %s.%s.%s.\n", mod->name.c_str(), cell->name.c_str(), it.first.c_str()); + log_header(design, "Trying to remove cell port %s.%s.%s.\n", log_id(mod), log_id(cell), log_id(it.first)); RTLIL::SigSpec port_x(State::Sx, port.size()); cell->unsetPort(it.first); cell->setPort(it.first, port_x); @@ -228,7 +243,7 @@ struct BugpointPass : public Pass { if (!stage2 && (cell->input(it.first) || cell->output(it.first)) && index++ == seed) { - log("Trying to expose cell port %s.%s.%s as module port.\n", mod->name.c_str(), cell->name.c_str(), it.first.c_str()); + log_header(design, "Trying to expose cell port %s.%s.%s as module port.\n", log_id(mod), log_id(cell), log_id(it.first)); RTLIL::Wire *wire = mod->addWire(NEW_ID, port.size()); wire->set_bool_attribute(ID($bugpoint)); wire->port_input = cell->input(it.first); @@ -260,7 +275,7 @@ struct BugpointPass : public Pass { { if (index++ == seed) { - log("Trying to remove assign %s %s in %s.%s.\n", log_signal((*it).first), log_signal((*it).second), mod->name.c_str(), pr.first.c_str()); + log_header(design, "Trying to remove assign %s %s in %s.%s.\n", log_signal(it->first), log_signal(it->second), log_id(mod), log_id(pr.first)); cs->actions.erase(it); return design_copy; } @@ -286,7 +301,7 @@ struct BugpointPass : public Pass { { if (index++ == seed) { - log("Trying to remove sync %s update %s %s in %s.%s.\n", log_signal(sy->signal), log_signal((*it).first), log_signal((*it).second), mod->name.c_str(), pr.first.c_str()); + log_header(design, "Trying to remove sync %s update %s %s in %s.%s.\n", log_signal(sy->signal), log_signal(it->first), log_signal(it->second), log_id(mod), log_id(pr.first)); sy->actions.erase(it); return design_copy; } @@ -304,6 +319,9 @@ struct BugpointPass : public Pass { bool fast = false, clean = false; bool modules = false, ports = false, cells = false, connections = false, assigns = false, updates = false, has_part = false; + log_header(design, "Executing BUGPOINT pass (minimize testcases).\n"); + log_push(); + size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -447,6 +465,8 @@ struct BugpointPass : public Pass { design->add(module->clone()); delete crashing_design; } + + log_pop(); } } BugpointPass; diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc index 628ac4c5e..89d27c9aa 100644 --- a/passes/cmds/cover.cc +++ b/passes/cmds/cover.cc @@ -101,8 +101,8 @@ struct CoverPass : public Pass { const std::string &filename = args[++argidx]; FILE *f = nullptr; if (args[argidx-1] == "-d") { - #ifdef _WIN32 - log_cmd_error("The 'cover -d' option is not supported on win32.\n"); + #if defined(_WIN32) || defined(__wasm) + log_cmd_error("The 'cover -d' option is not supported on this platform.\n"); #else char filename_buffer[4096]; snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", filename.c_str(), getpid()); diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc index c04ff438a..6e728c16f 100644 --- a/passes/cmds/select.cc +++ b/passes/cmds/select.cc @@ -630,8 +630,10 @@ static void select_stmt(RTLIL::Design *design, std::string arg, bool disable_emp std::string arg_mod, arg_memb; std::unordered_map<std::string, bool> arg_mod_found; std::unordered_map<std::string, bool> arg_memb_found; - auto isalpha = [](const char &x) { return ((x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z')); }; - bool prefixed = GetSize(arg) >= 2 && isalpha(arg[0]) && arg[1] == ':'; + + auto isprefixed = [](const string &s) { + return GetSize(s) >= 2 && ((s[0] >= 'a' && s[0] <= 'z') || (s[0] >= 'A' && s[0] <= 'Z')) && s[1] == ':'; + }; if (arg.size() == 0) return; @@ -759,31 +761,40 @@ static void select_stmt(RTLIL::Design *design, std::string arg, bool disable_emp return; } + bool select_blackboxes = false; + if (arg.substr(0, 1) == "=") { + arg = arg.substr(1); + select_blackboxes = true; + } + if (!design->selected_active_module.empty()) { arg_mod = design->selected_active_module; arg_memb = arg; - if (!prefixed) arg_memb_found[arg_memb] = false; + if (!isprefixed(arg_memb)) + arg_memb_found[arg_memb] = false; } else - if (prefixed && arg[0] >= 'a' && arg[0] <= 'z') { + if (isprefixed(arg) && arg[0] >= 'a' && arg[0] <= 'z') { arg_mod = "*", arg_memb = arg; } else { size_t pos = arg.find('/'); if (pos == std::string::npos) { arg_mod = arg; - if (!prefixed) arg_mod_found[arg_mod] = false; + if (!isprefixed(arg_mod)) + arg_mod_found[arg_mod] = false; } else { arg_mod = arg.substr(0, pos); - if (!prefixed) arg_mod_found[arg_mod] = false; + if (!isprefixed(arg_mod)) + arg_mod_found[arg_mod] = false; arg_memb = arg.substr(pos+1); - bool arg_memb_prefixed = GetSize(arg_memb) >= 2 && isalpha(arg_memb[0]) && arg_memb[1] == ':'; - if (!arg_memb_prefixed) arg_memb_found[arg_memb] = false; + if (!isprefixed(arg_memb)) + arg_memb_found[arg_memb] = false; } } work_stack.push_back(RTLIL::Selection()); RTLIL::Selection &sel = work_stack.back(); - if (arg == "*" && arg_mod == "*") { + if (arg == "*" && arg_mod == "*" && select_blackboxes) { select_filter_active_mod(design, work_stack.back()); return; } @@ -791,6 +802,9 @@ static void select_stmt(RTLIL::Design *design, std::string arg, bool disable_emp sel.full_selection = false; for (auto mod : design->modules()) { + if (!select_blackboxes && mod->get_blackbox_attribute()) + continue; + if (arg_mod.compare(0, 2, "A:") == 0) { if (!match_attr(mod->attributes, arg_mod.substr(2))) continue; @@ -1104,6 +1118,9 @@ struct SelectPass : public Pass { log(" <obj_pattern>\n"); log(" select the specified object(s) from the current module\n"); log("\n"); + log("By default, patterns will not match black/white-box modules or their"); + log("contents. To include such objects, prefix the pattern with '='.\n"); + log("\n"); log("A <mod_pattern> can be a module name, wildcard expression (*, ?, [..])\n"); log("matching module names, or one of the following:\n"); log("\n"); diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc index 155ed0fcd..fa922454a 100644 --- a/passes/cmds/show.cc +++ b/passes/cmds/show.cc @@ -682,7 +682,7 @@ struct ShowPass : public Pass { std::vector<std::pair<std::string, RTLIL::Selection>> color_selections; std::vector<std::pair<std::string, RTLIL::Selection>> label_selections; -#if defined(EMSCRIPTEN) || defined(_WIN32) +#if defined(_WIN32) || defined(YOSYS_DISABLE_SPAWN) std::string format = "dot"; std::string prefix = "show"; #else @@ -849,10 +849,15 @@ struct ShowPass : public Pass { std::string cmd = stringf(DOT_CMD, format.c_str(), dot_file.c_str(), out_file.c_str(), out_file.c_str(), out_file.c_str()); #undef DOT_CMD log("Exec: %s\n", cmd.c_str()); - if (run_command(cmd) != 0) - log_cmd_error("Shell command failed!\n"); + #if !defined(YOSYS_DISABLE_SPAWN) + if (run_command(cmd) != 0) + log_cmd_error("Shell command failed!\n"); + #endif } + #if defined(YOSYS_DISABLE_SPAWN) + log_assert(viewer_exe.empty() && !format.empty()); + #else if (!viewer_exe.empty()) { #ifdef _WIN32 // system()/cmd.exe does not understand single quotes nor @@ -876,6 +881,7 @@ struct ShowPass : public Pass { if (run_command(cmd) != 0) log_cmd_error("Shell command failed!\n"); } + #endif if (flag_pause) { #ifdef YOSYS_ENABLE_READLINE diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 2b35ace5e..0f5bff680 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -682,25 +682,37 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A)); RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B)); RTLIL::SigSpec sig_y = cell->getPort(ID::Y); + bool is_signed = cell->getParam(ID::A_SIGNED).as_bool(); bool sub = cell->type == ID($sub); + int minsz = GetSize(sig_y); + minsz = std::min(minsz, GetSize(sig_a)); + minsz = std::min(minsz, GetSize(sig_b)); + int i; - for (i = 0; i < GetSize(sig_y); i++) { - RTLIL::SigBit b = sig_b.at(i, State::Sx); - RTLIL::SigBit a = sig_a.at(i, State::Sx); - if (b == State::S0 && a != State::Sx) + for (i = 0; i < minsz; i++) { + RTLIL::SigBit b = sig_b[i]; + RTLIL::SigBit a = sig_a[i]; + if (b == State::S0) module->connect(sig_y[i], a); else if (sub && b == State::S1 && a == State::S1) module->connect(sig_y[i], State::S0); - else if (!sub && a == State::S0 && b != State::Sx) + else if (!sub && a == State::S0) module->connect(sig_y[i], b); else break; } if (i > 0) { cover_list("opt.opt_expr.fine", "$add", "$sub", cell->type.str()); - cell->setPort(ID::A, sig_a.extract_end(i)); - cell->setPort(ID::B, sig_b.extract_end(i)); + log_debug("Stripping %d LSB bits of %s cell %s in module %s.\n", i, log_id(cell->type), log_id(cell), log_id(module)); + SigSpec new_a = sig_a.extract_end(i); + SigSpec new_b = sig_b.extract_end(i); + if (new_a.empty() && is_signed) + new_a = sig_a[i-1]; + if (new_b.empty() && is_signed) + new_b = sig_b[i-1]; + cell->setPort(ID::A, new_a); + cell->setPort(ID::B, new_b); cell->setPort(ID::Y, sig_y.extract_end(i)); cell->fixup_parameters(); did_something = true; @@ -716,6 +728,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons RTLIL::SigSpec sig_x = cell->getPort(ID::X); RTLIL::SigSpec sig_y = cell->getPort(ID::Y); RTLIL::SigSpec sig_co = cell->getPort(ID::CO); + bool is_signed = cell->getParam(ID::A_SIGNED).as_bool(); if (sig_bi != State::S0 && sig_bi != State::S1) goto skip_fine_alu; @@ -725,16 +738,20 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons bool bi = sig_bi == State::S1; bool ci = sig_ci == State::S1; + int minsz = GetSize(sig_y); + minsz = std::min(minsz, GetSize(sig_a)); + minsz = std::min(minsz, GetSize(sig_b)); + int i; - for (i = 0; i < GetSize(sig_y); i++) { - RTLIL::SigBit b = sig_b.at(i, State::Sx); - RTLIL::SigBit a = sig_a.at(i, State::Sx); - if (b == ((bi ^ ci) ? State::S1 : State::S0) && a != State::Sx) { + for (i = 0; i < minsz; i++) { + RTLIL::SigBit b = sig_b[i]; + RTLIL::SigBit a = sig_a[i]; + if (b == ((bi ^ ci) ? State::S1 : State::S0)) { module->connect(sig_y[i], a); module->connect(sig_x[i], ci ? module->Not(NEW_ID, a).as_bit() : a); module->connect(sig_co[i], ci ? State::S1 : State::S0); } - else if (a == (ci ? State::S1 : State::S0) && b != State::Sx) { + else if (a == (ci ? State::S1 : State::S0)) { module->connect(sig_y[i], bi ? module->Not(NEW_ID, b).as_bit() : b); module->connect(sig_x[i], (bi ^ ci) ? module->Not(NEW_ID, b).as_bit() : b); module->connect(sig_co[i], ci ? State::S1 : State::S0); @@ -744,8 +761,15 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (i > 0) { cover("opt.opt_expr.fine.$alu"); - cell->setPort(ID::A, sig_a.extract_end(i)); - cell->setPort(ID::B, sig_b.extract_end(i)); + log_debug("Stripping %d LSB bits of %s cell %s in module %s.\n", i, log_id(cell->type), log_id(cell), log_id(module)); + SigSpec new_a = sig_a.extract_end(i); + SigSpec new_b = sig_b.extract_end(i); + if (new_a.empty() && is_signed) + new_a = sig_a[i-1]; + if (new_b.empty() && is_signed) + new_b = sig_b[i-1]; + cell->setPort(ID::A, new_a); + cell->setPort(ID::B, new_b); cell->setPort(ID::X, sig_x.extract_end(i)); cell->setPort(ID::Y, sig_y.extract_end(i)); cell->setPort(ID::CO, sig_co.extract_end(i)); diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc index bfddfd0eb..f16cc4a0b 100644 --- a/passes/pmgen/ice40_dsp.cc +++ b/passes/pmgen/ice40_dsp.cc @@ -73,11 +73,11 @@ void create_ice40_dsp(ice40_dsp_pm &pm) // SB_MAC16 Input Interface SigSpec A = st.sigA; - A.extend_u0(16, st.mul->parameters.at(ID::A_SIGNED, State::S0).as_bool()); + A.extend_u0(16, st.mul->getParam(ID::A_SIGNED).as_bool()); log_assert(GetSize(A) == 16); SigSpec B = st.sigB; - B.extend_u0(16, st.mul->parameters.at(ID::B_SIGNED, State::S0).as_bool()); + B.extend_u0(16, st.mul->getParam(ID::B_SIGNED).as_bool()); log_assert(GetSize(B) == 16); SigSpec CD = st.sigCD; @@ -248,8 +248,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm) cell->setParam(ID(BOTADDSUB_CARRYSELECT), Const(0, 2)); cell->setParam(ID(MODE_8x8), State::S0); - cell->setParam(ID::A_SIGNED, st.mul->parameters.at(ID::A_SIGNED, State::S0).as_bool()); - cell->setParam(ID::B_SIGNED, st.mul->parameters.at(ID::B_SIGNED, State::S0).as_bool()); + cell->setParam(ID::A_SIGNED, st.mul->getParam(ID::A_SIGNED).as_bool()); + cell->setParam(ID::B_SIGNED, st.mul->getParam(ID::B_SIGNED).as_bool()); if (st.ffO) { if (st.o_lo) diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 9d649cb98..2456a49dc 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -65,7 +65,7 @@ code sigA sigB sigH endcode code argQ ffA ffAholdmux ffArstmux ffAholdpol ffArstpol sigA clock clock_pol - if (mul->type != \SB_MAC16 || !param(mul, \A_REG, State::S0).as_bool()) { + if (mul->type != \SB_MAC16 || !param(mul, \A_REG).as_bool()) { argQ = sigA; subpattern(in_dffe); if (dff) { @@ -86,7 +86,7 @@ code argQ ffA ffAholdmux ffArstmux ffAholdpol ffArstpol sigA clock clock_pol endcode code argQ ffB ffBholdmux ffBrstmux ffBholdpol ffBrstpol sigB clock clock_pol - if (mul->type != \SB_MAC16 || !param(mul, \B_REG, State::S0).as_bool()) { + if (mul->type != \SB_MAC16 || !param(mul, \B_REG).as_bool()) { argQ = sigB; subpattern(in_dffe); if (dff) { @@ -109,7 +109,7 @@ endcode code argD ffFJKG sigH clock clock_pol if (nusers(sigH) == 2 && (mul->type != \SB_MAC16 || - (!param(mul, \TOP_8x8_MULT_REG, State::S0).as_bool() && !param(mul, \BOT_8x8_MULT_REG, State::S0).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1, State::S0).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1, State::S0).as_bool()))) { + (!param(mul, \TOP_8x8_MULT_REG).as_bool() && !param(mul, \BOT_8x8_MULT_REG).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool() && !param(mul, \PIPELINE_16x16_MULT_REG1).as_bool()))) { argD = sigH; subpattern(out_dffe); if (dff) { @@ -148,7 +148,7 @@ endcode code argD ffH sigH sigO clock clock_pol if (ffFJKG && nusers(sigH) == 2 && - (mul->type != \SB_MAC16 || !param(mul, \PIPELINE_16x16_MULT_REG2, State::S0).as_bool())) { + (mul->type != \SB_MAC16 || !param(mul, \PIPELINE_16x16_MULT_REG2).as_bool())) { argD = sigH; subpattern(out_dffe); if (dff) { @@ -179,7 +179,7 @@ reject_ffH: ; endcode match add - if mul->type != \SB_MAC16 || (param(mul, \TOPOUTPUT_SELECT, State::S0).as_int() == 3 && param(mul, \BOTOUTPUT_SELECT, State::S0).as_int() == 3) + if mul->type != \SB_MAC16 || (param(mul, \TOPOUTPUT_SELECT).as_int() == 3 && param(mul, \BOTOUTPUT_SELECT).as_int() == 3) select add->type.in($add) choice <IdString> AB {\A, \B} @@ -205,7 +205,7 @@ code sigCD sigO cd_signed if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width)) reject; // If accumulator, check adder width and signedness - if (sigCD == sigH && (actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED, State::S0).as_bool() != param(add, \A_SIGNED).as_bool())) + if (sigCD == sigH && (actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(add, \A_SIGNED).as_bool())) reject; sigO = port(add, \Y); @@ -229,7 +229,7 @@ endcode code argD ffO ffOholdmux ffOrstmux ffOholdpol ffOrstpol sigO sigCD clock clock_pol cd_signed o_lo if (mul->type != \SB_MAC16 || // Ensure that register is not already used - ((param(mul, \TOPOUTPUT_SELECT, 0).as_int() != 1 && param(mul, \BOTOUTPUT_SELECT, 0).as_int() != 1) && + ((param(mul, \TOPOUTPUT_SELECT).as_int() != 1 && param(mul, \BOTOUTPUT_SELECT).as_int() != 1) && // Ensure that OLOADTOP/OLOADBOT is unused or zero (port(mul, \OLOADTOP, State::S0).is_fully_zero() && port(mul, \OLOADBOT, State::S0).is_fully_zero()))) { @@ -280,7 +280,7 @@ endcode code argQ ffCD ffCDholdmux ffCDholdpol ffCDrstpol sigCD clock clock_pol if (!sigCD.empty() && sigCD != sigO && - (mul->type != \SB_MAC16 || (!param(mul, \C_REG, State::S0).as_bool() && !param(mul, \D_REG, State::S0).as_bool()))) { + (mul->type != \SB_MAC16 || (!param(mul, \C_REG).as_bool() && !param(mul, \D_REG).as_bool()))) { argQ = sigCD; subpattern(in_dffe); if (dff) { @@ -532,7 +532,7 @@ endcode match ff select ff->type.in($dff) - // DSP48E1 does not support clock inversion + // SB_MAC16 does not support clock inversion select param(ff, \CLK_POLARITY).as_bool() slice offset GetSize(port(ff, \D)) diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg index af47ab111..d40f073c9 100644 --- a/passes/pmgen/xilinx_dsp.pmg +++ b/passes/pmgen/xilinx_dsp.pmg @@ -95,7 +95,7 @@ code sigA sigB sigC sigD sigM clock sigD = port(dsp, \D, SigSpec()); SigSpec P = port(dsp, \P); - if (param(dsp, \USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY") { + if (param(dsp, \USE_MULT).decode_string() == "MULTIPLY") { // Only care about those bits that are used int i; for (i = GetSize(P)-1; i >= 0; i--) @@ -120,7 +120,7 @@ endcode // reset functionality, using a subpattern discussed above) // If matched, treat 'A' input as input of ADREG code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock - if (param(dsp, \ADREG, 1).as_int() == 0) { + if (param(dsp, \ADREG).as_int() == 0) { argQ = sigA; subpattern(in_dffe); if (dff) { @@ -144,7 +144,7 @@ endcode match preAdd if sigD.empty() || sigD.is_fully_zero() // Ensure that preAdder not already used - if param(dsp, \USE_DPORT, Const("FALSE")).decode_string() == "FALSE" + if param(dsp, \USE_DPORT).decode_string() == "FALSE" if port(dsp, \INMODE, Const(0, 5)).is_fully_zero() select preAdd->type.in($add) @@ -176,7 +176,7 @@ code argQ ffAD ffADcemux ffADrstmux ffADcepol ffADrstpol sigA clock ffA2 ffA2cem // Only search for ffA2 if there was a pre-adder // (otherwise ffA2 would have been matched as ffAD) if (preAdd) { - if (param(dsp, \AREG, 1).as_int() == 0) { + if (param(dsp, \AREG).as_int() == 0) { argQ = sigA; subpattern(in_dffe); if (dff) { @@ -237,7 +237,7 @@ endcode // (5) Match 'B' input for B2REG // If B2REG, then match 'B' input for B1REG code argQ ffB2 ffB2cemux ffB2rstmux ffB2cepol ffBrstpol sigB clock ffB1 ffB1cemux ffB1rstmux ffB1cepol - if (param(dsp, \BREG, 1).as_int() == 0) { + if (param(dsp, \BREG).as_int() == 0) { argQ = sigB; subpattern(in_dffe); if (dff) { @@ -287,7 +287,7 @@ endcode // (6) Match 'D' input for DREG code argQ ffD ffDcemux ffDrstmux ffDcepol ffDrstpol sigD clock - if (param(dsp, \DREG, 1).as_int() == 0) { + if (param(dsp, \DREG).as_int() == 0) { argQ = sigD; subpattern(in_dffe); if (dff) { @@ -308,7 +308,7 @@ endcode // (7) Match 'P' output that exclusively drives an MREG code argD ffM ffMcemux ffMrstmux ffMcepol ffMrstpol sigM sigP clock - if (param(dsp, \MREG, 1).as_int() == 0 && nusers(sigM) == 2) { + if (param(dsp, \MREG).as_int() == 0 && nusers(sigM) == 2) { argD = sigM; subpattern(out_dffe); if (dff) { @@ -363,7 +363,7 @@ endcode // (9) Match 'P' output that exclusively drives a PREG code argD ffP ffPcemux ffPrstmux ffPcepol ffPrstpol sigP clock - if (param(dsp, \PREG, 1).as_int() == 0) { + if (param(dsp, \PREG).as_int() == 0) { int users = 2; // If ffMcemux and no postAdd new-value net must have three users: ffMcemux, ffM and ffPcemux if (ffMcemux && !postAdd) users++; @@ -424,7 +424,7 @@ endcode // to implement this function match overflow if ffP - if param(dsp, \USE_PATTERN_DETECT, Const("NO_PATDET")).decode_string() == "NO_PATDET" + if param(dsp, \USE_PATTERN_DETECT).decode_string() == "NO_PATDET" select overflow->type.in($ge) select GetSize(port(overflow, \Y)) <= 48 select port(overflow, \B).is_fully_const() diff --git a/passes/pmgen/xilinx_dsp_CREG.pmg b/passes/pmgen/xilinx_dsp_CREG.pmg index b20e4f458..42d4d1b9b 100644 --- a/passes/pmgen/xilinx_dsp_CREG.pmg +++ b/passes/pmgen/xilinx_dsp_CREG.pmg @@ -42,7 +42,7 @@ udata <bool> dffcepol dffrstpol // and (b) uses the 'C' port match dsp select dsp->type.in(\DSP48A, \DSP48A1, \DSP48E1) - select param(dsp, \CREG, 1).as_int() == 0 + select param(dsp, \CREG).as_int() == 0 select nusers(port(dsp, \C, SigSpec())) > 1 endmatch @@ -61,7 +61,7 @@ code sigC sigP clock SigSpec P = port(dsp, \P); if (!dsp->type.in(\DSP48E1) || - param(dsp, \USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY") { + param(dsp, \USE_MULT).decode_string() == "MULTIPLY") { // Only care about those bits that are used int i; for (i = GetSize(P)-1; i >= 0; i--) diff --git a/passes/pmgen/xilinx_dsp_cascade.pmg b/passes/pmgen/xilinx_dsp_cascade.pmg index b14a1ee0a..8babb88e6 100644 --- a/passes/pmgen/xilinx_dsp_cascade.pmg +++ b/passes/pmgen/xilinx_dsp_cascade.pmg @@ -188,7 +188,7 @@ arg next // driven by the 'P' output of the previous DSP cell, and (c) has its // 'PCIN' port unused match nextP - select !param(nextP, \CREG, State::S1).as_bool() + select !nextP->type.in(\DSP48E1) || !param(nextP, \CREG).as_bool() select (nextP->type.in(\DSP48A, \DSP48A1) && port(nextP, \OPMODE, Const(0, 8)).extract(2,2) == Const::from_string("11")) || (nextP->type.in(\DSP48E1) && port(nextP, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("011")) select nusers(port(nextP, \C, SigSpec())) > 1 select nusers(port(nextP, \PCIN, SigSpec())) == 0 @@ -201,7 +201,7 @@ endmatch match nextP_shift17 if !nextP select nextP_shift17->type.in(\DSP48E1) - select !param(nextP_shift17, \CREG, State::S1).as_bool() + select !param(nextP_shift17, \CREG).as_bool() select port(nextP_shift17, \OPMODE, Const(0, 7)).extract(4,3) == Const::from_string("011") select nusers(port(nextP_shift17, \C, SigSpec())) > 1 select nusers(port(nextP_shift17, \PCIN, SigSpec())) == 0 @@ -242,10 +242,10 @@ code argQ clock AREG if (next && next->type.in(\DSP48E1)) { Cell *prev = std::get<0>(chain.back()); - if (param(next, \A_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && + if (param(next, \A_INPUT).decode_string() == "DIRECT" && port(next, \ACIN, SigSpec()).is_fully_zero() && nusers(port(prev, \ACOUT, SigSpec())) <= 1) { - if (param(prev, \AREG, 2) == 0) { + if (param(prev, \AREG) == 0) { if (port(prev, \A) == port(next, \A)) AREG = 0; } @@ -259,9 +259,9 @@ code argQ clock AREG if (dffrstmux && port(dffrstmux, \S) != port(prev, \RSTA, State::S0)) goto reject_AREG; IdString CEA; - if (param(prev, \AREG, 2) == 1) + if (param(prev, \AREG) == 1) CEA = \CEA2; - else if (param(prev, \AREG, 2) == 2) + else if (param(prev, \AREG) == 2) CEA = \CEA1; else log_abort(); if (!dffcemux && port(prev, CEA, State::S0) != State::S1) @@ -282,11 +282,11 @@ code argQ clock BREG BREG = -1; if (next) { Cell *prev = std::get<0>(chain.back()); - if (param(next, \B_INPUT, Const("DIRECT")).decode_string() == "DIRECT" && + if ((next->type != \DSP48E1 || param(next, \B_INPUT).decode_string() == "DIRECT") && port(next, \BCIN, SigSpec()).is_fully_zero() && nusers(port(prev, \BCOUT, SigSpec())) <= 1) { - if ((next->type.in(\DSP48A, \DSP48A1) && param(prev, \B0REG, 0) == 0 && param(prev, \B1REG, 1) == 0) || - (next->type.in(\DSP48E1) && param(prev, \BREG, 2) == 0)) { + if ((next->type.in(\DSP48A, \DSP48A1) && param(prev, \B0REG) == 0 && param(prev, \B1REG) == 0) || + (next->type.in(\DSP48E1) && param(prev, \BREG) == 0)) { if (port(prev, \B) == port(next, \B)) BREG = 0; } @@ -303,9 +303,9 @@ code argQ clock BREG if (next->type.in(\DSP48A, \DSP48A1)) CEB = \CEB; else if (next->type.in(\DSP48E1)) { - if (param(prev, \BREG, 2) == 1) + if (param(prev, \BREG) == 1) CEB = \CEB2; - else if (param(prev, \BREG, 2) == 2) + else if (param(prev, \BREG) == 2) CEB = \CEB1; else log_abort(); } @@ -315,7 +315,7 @@ code argQ clock BREG if (dffcemux && port(dffcemux, \S) != port(prev, CEB, State::S0)) goto reject_BREG; if (dffD == unextend(port(prev, \B))) { - if (next->type.in(\DSP48A, \DSP48A1) && param(prev, \B0REG, 0) != 0) + if (next->type.in(\DSP48A, \DSP48A1) && param(prev, \B0REG) != 0) goto reject_BREG; BREG = 1; } diff --git a/passes/pmgen/xilinx_srl.cc b/passes/pmgen/xilinx_srl.cc index 24b525b93..b99653fb3 100644 --- a/passes/pmgen/xilinx_srl.cc +++ b/passes/pmgen/xilinx_srl.cc @@ -48,7 +48,7 @@ void run_fixed(xilinx_srl_pm &pm) initval.append(State::Sx); } else if (cell->type.in(ID(FDRE), ID(FDRE_1))) { - if (cell->parameters.at(ID::INIT, State::S0).as_bool()) + if (cell->getParam(ID::INIT).as_bool()) initval.append(State::S1); else initval.append(State::S0); @@ -71,7 +71,7 @@ void run_fixed(xilinx_srl_pm &pm) else if (first_cell->type.in(ID($_DFF_N_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID(FDRE_1))) c->setParam(ID(CLKPOL), 0); else if (first_cell->type.in(ID(FDRE))) { - if (!first_cell->parameters.at(ID(IS_C_INVERTED), State::S0).as_bool()) + if (!first_cell->getParam(ID(IS_C_INVERTED)).as_bool()) c->setParam(ID(CLKPOL), 1); else c->setParam(ID(CLKPOL), 0); diff --git a/passes/pmgen/xilinx_srl.pmg b/passes/pmgen/xilinx_srl.pmg index 535b3dfdc..80f0a27c2 100644 --- a/passes/pmgen/xilinx_srl.pmg +++ b/passes/pmgen/xilinx_srl.pmg @@ -13,8 +13,8 @@ endcode match first select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1) select !first->has_keep_attr() - select !first->type.in(\FDRE) || !param(first, \IS_R_INVERTED, State::S0).as_bool() - select !first->type.in(\FDRE) || !param(first, \IS_D_INVERTED, State::S0).as_bool() + select !first->type.in(\FDRE) || !param(first, \IS_R_INVERTED).as_bool() + select !first->type.in(\FDRE) || !param(first, \IS_D_INVERTED).as_bool() select !first->type.in(\FDRE, \FDRE_1) || port(first, \R, State::S0).is_fully_zero() filter !non_first_cells.count(first) generate @@ -84,8 +84,8 @@ arg en_port match first select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1) select !first->has_keep_attr() - select !first->type.in(\FDRE) || !param(first, \IS_R_INVERTED, State::S0).as_bool() - select !first->type.in(\FDRE) || !param(first, \IS_D_INVERTED, State::S0).as_bool() + select !first->type.in(\FDRE) || !param(first, \IS_R_INVERTED).as_bool() + select !first->type.in(\FDRE) || !param(first, \IS_D_INVERTED).as_bool() select !first->type.in(\FDRE, \FDRE_1) || port(first, \R, State::S0).is_fully_zero() endmatch @@ -111,9 +111,9 @@ match next index <SigBit> port(next, \Q) === port(first, \D) filter port(next, clk_port) == port(first, clk_port) filter en_port == IdString() || port(next, en_port) == port(first, en_port) - filter !first->type.in(\FDRE) || param(next, \IS_C_INVERTED, State::S0).as_bool() == param(first, \IS_C_INVERTED, State::S0).as_bool() - filter !first->type.in(\FDRE) || param(next, \IS_D_INVERTED, State::S0).as_bool() == param(first, \IS_D_INVERTED, State::S0).as_bool() - filter !first->type.in(\FDRE) || param(next, \IS_R_INVERTED, State::S0).as_bool() == param(first, \IS_R_INVERTED, State::S0).as_bool() + filter !first->type.in(\FDRE) || param(next, \IS_C_INVERTED).as_bool() == param(first, \IS_C_INVERTED).as_bool() + filter !first->type.in(\FDRE) || param(next, \IS_D_INVERTED).as_bool() == param(first, \IS_D_INVERTED).as_bool() + filter !first->type.in(\FDRE) || param(next, \IS_R_INVERTED).as_bool() == param(first, \IS_R_INVERTED).as_bool() filter !first->type.in(\FDRE, \FDRE_1) || port(next, \R, State::S0).is_fully_zero() endmatch @@ -138,9 +138,9 @@ match next index <SigBit> port(next, \Q) === port(chain.back(), \D) filter port(next, clk_port) == port(first, clk_port) filter en_port == IdString() || port(next, en_port) == port(first, en_port) - filter !first->type.in(\FDRE) || param(next, \IS_C_INVERTED, State::S0).as_bool() == param(first, \IS_C_INVERTED, State::S0).as_bool() - filter !first->type.in(\FDRE) || param(next, \IS_D_INVERTED, State::S0).as_bool() == param(first, \IS_D_INVERTED, State::S0).as_bool() - filter !first->type.in(\FDRE) || param(next, \IS_R_INVERTED, State::S0).as_bool() == param(first, \IS_R_INVERTED, State::S0).as_bool() + filter !first->type.in(\FDRE) || param(next, \IS_C_INVERTED).as_bool() == param(first, \IS_C_INVERTED).as_bool() + filter !first->type.in(\FDRE) || param(next, \IS_D_INVERTED).as_bool() == param(first, \IS_D_INVERTED).as_bool() + filter !first->type.in(\FDRE) || param(next, \IS_R_INVERTED).as_bool() == param(first, \IS_R_INVERTED).as_bool() filter !first->type.in(\FDRE, \FDRE_1) || port(next, \R, State::S0).is_fully_zero() generate Cell *cell = module->addCell(NEW_ID, chain.back()->type); diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc index a928c57de..7118c1563 100644 --- a/passes/sat/Makefile.inc +++ b/passes/sat/Makefile.inc @@ -13,5 +13,6 @@ OBJS += passes/sat/fmcombine.o OBJS += passes/sat/mutate.o OBJS += passes/sat/cutpoint.o OBJS += passes/sat/fminit.o +ifeq ($(DISABLE_SPAWN),0) OBJS += passes/sat/qbfsat.o - +endif diff --git a/passes/sat/qbfsat.cc b/passes/sat/qbfsat.cc index 981271770..d99ca1b53 100644 --- a/passes/sat/qbfsat.cc +++ b/passes/sat/qbfsat.cc @@ -49,15 +49,15 @@ struct QbfSolutionType { }; struct QbfSolveOptions { - bool specialize, specialize_from_file, write_solution, nocleanup, dump_final_smt2, assume_outputs; + bool specialize, specialize_from_file, write_solution, nocleanup, dump_final_smt2, assume_outputs, assume_neg; bool sat, unsat, show_smtbmc; std::string specialize_soln_file; std::string write_soln_soln_file; std::string dump_final_smt2_file; size_t argidx; QbfSolveOptions() : specialize(false), specialize_from_file(false), write_solution(false), - nocleanup(false), dump_final_smt2(false), assume_outputs(false), sat(false), unsat(false), - show_smtbmc(false), argidx(0) {}; + nocleanup(false), dump_final_smt2(false), assume_outputs(false), assume_neg(false), + sat(false), unsat(false), show_smtbmc(false), argidx(0) {}; }; void recover_solution(QbfSolutionType &sol) { @@ -98,11 +98,8 @@ dict<std::string, std::string> get_hole_loc_name_map(RTLIL::Module *module, cons for (auto cell : module->cells()) { std::string cell_src = cell->get_src_attribute(); auto pos = sol.hole_to_value.find(cell_src); - if (pos != sol.hole_to_value.end()) { -#ifndef NDEBUG - log_assert(cell->type.in("$anyconst", "$anyseq")); - log_assert(cell->getPort(ID::Y).is_wire()); -#endif + if (pos != sol.hole_to_value.end() && cell->type.in("$anyconst", "$anyseq")) { + log_assert(hole_loc_to_name.find(pos->first) == hole_loc_to_name.end()); hole_loc_to_name[pos->first] = cell->getPort(ID::Y).as_wire()->name.str(); } } @@ -242,7 +239,7 @@ void allconstify_inputs(RTLIL::Module *module, const pool<std::string> &input_wi module->fixup_ports(); } -void assume_miter_outputs(RTLIL::Module *module) { +void assume_miter_outputs(RTLIL::Module *module, const QbfSolveOptions &opt) { std::vector<RTLIL::Wire *> wires_to_assume; for (auto w : module->wires()) if (w->port_output && w->width == 1) @@ -257,7 +254,14 @@ void assume_miter_outputs(RTLIL::Module *module) { log("\n"); } - for(auto i = 0; wires_to_assume.size() > 1; ++i) { + if (opt.assume_neg) { + for (unsigned int i = 0; i < wires_to_assume.size(); ++i) { + RTLIL::SigSpec n_wire = module->LogicNot(wires_to_assume[i]->name.str() + "__n__qbfsat", wires_to_assume[i], false, wires_to_assume[i]->get_src_attribute()); + wires_to_assume[i] = n_wire.as_wire(); + } + } + + for (auto i = 0; wires_to_assume.size() > 1; ++i) { std::vector<RTLIL::Wire *> buf; for (auto j = 0; j + 1 < GetSize(wires_to_assume); j += 2) { std::stringstream strstr; strstr << i << "_" << j; @@ -371,6 +375,10 @@ QbfSolveOptions parse_args(const std::vector<std::string> &args) { opt.assume_outputs = true; continue; } + else if (args[opt.argidx] == "-assume-negative-polarity") { + opt.assume_neg = true; + continue; + } else if (args[opt.argidx] == "-sat") { opt.sat = true; continue; @@ -464,6 +472,11 @@ struct QbfSatPass : public Pass { log(" -assume-outputs\n"); log(" Add an $assume cell for the conjunction of all one-bit module output wires.\n"); log("\n"); + log(" -assume-negative-polarity\n"); + log(" When adding $assume cells for one-bit module output wires, assume they are\n"); + log(" negative polarity signals and should always be low, for example like the\n"); + log(" miters created with the `miter` command.\n"); + log("\n"); log(" -sat\n"); log(" Generate an error if the solver does not return \"sat\".\n"); log("\n"); @@ -512,7 +525,7 @@ struct QbfSatPass : public Pass { pool<std::string> input_wires = validate_design_and_get_inputs(module, opt); allconstify_inputs(module, input_wires); if (opt.assume_outputs) - assume_miter_outputs(module); + assume_miter_outputs(module, opt); QbfSolutionType ret = qbf_solve(module, opt); Pass::call(design, "design -pop"); diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index 766b954df..1802ba0de 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -57,7 +57,7 @@ passes/techmap/techmap.inc: techlibs/common/techmap.v passes/techmap/techmap.o: passes/techmap/techmap.inc -ifneq ($(CONFIG),emcc) +ifeq ($(DISABLE_SPAWN),0) TARGETS += $(PROGRAM_PREFIX)yosys-filterlib$(EXE) EXTRA_OBJS += passes/techmap/filterlib.o diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index aff0baa44..fae8b2426 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -771,7 +771,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin if (abc_script[i] == ';' && abc_script[i+1] == ' ') abc_script[i+1] = '\n'; - FILE *f = fopen(stringf("%s/abc.script", tempdir_name.c_str()).c_str(), "wt"); + std::string buffer = stringf("%s/abc.script", tempdir_name.c_str()); + FILE *f = fopen(buffer.c_str(), "wt"); + if (f == nullptr) + log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno)); fprintf(f, "%s\n", abc_script.c_str()); fclose(f); @@ -807,7 +810,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin handle_loops(); - std::string buffer = stringf("%s/input.blif", tempdir_name.c_str()); + buffer = stringf("%s/input.blif", tempdir_name.c_str()); f = fopen(buffer.c_str(), "wt"); if (f == nullptr) log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno)); @@ -1541,11 +1544,15 @@ struct AbcPass : public Pass { size_t argidx, g_argidx; bool g_arg_from_cmd = false; +#if defined(__wasm) + const char *pwd = "."; +#else char pwd [PATH_MAX]; if (!getcwd(pwd, sizeof(pwd))) { log_cmd_error("getcwd failed: %s\n", strerror(errno)); log_abort(); } +#endif for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; if (arg == "-exe" && argidx+1 < args.size()) { diff --git a/passes/techmap/abc9_exe.cc b/passes/techmap/abc9_exe.cc index 18618ff91..0bf547921 100644 --- a/passes/techmap/abc9_exe.cc +++ b/passes/techmap/abc9_exe.cc @@ -219,6 +219,17 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe for (size_t pos = abc9_script.find("{R}"); pos != std::string::npos; pos = abc9_script.find("{R}", pos)) abc9_script = abc9_script.substr(0, pos) + R + abc9_script.substr(pos+3); + if (design->scratchpad_get_bool("abc9.nomfs")) + for (size_t pos = abc9_script.find("&mfs"); pos != std::string::npos; pos = abc9_script.find("&mfs", pos)) + abc9_script = abc9_script.erase(pos, strlen("&mfs")); + else { + auto s = stringf("&write -n %s/output.aig; ", tempdir_name.c_str()); + for (size_t pos = abc9_script.find("&mfs"); pos != std::string::npos; pos = abc9_script.find("&mfs", pos)) { + abc9_script = abc9_script.insert(pos, s); + pos += GetSize(s) + strlen("&mfs"); + } + } + abc9_script += stringf("; &ps -l; &write -n %s/output.aig", tempdir_name.c_str()); if (design->scratchpad_get_bool("abc9.verify")) { if (dff_mode) @@ -272,8 +283,12 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe free(abc9_argv[2]); free(abc9_argv[3]); #endif - if (ret != 0) - log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret); + if (ret != 0) { + if (check_file_exists(stringf("%s/output.aig", tempdir_name.c_str()))) + log_warning("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret); + else + log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret); + } } struct Abc9ExePass : public Pass { @@ -405,11 +420,15 @@ struct Abc9ExePass : public Pass { } size_t argidx; +#if defined(__wasm) + const char *pwd = "."; +#else char pwd [PATH_MAX]; if (!getcwd(pwd, sizeof(pwd))) { log_cmd_error("getcwd failed: %s\n", strerror(errno)); log_abort(); } +#endif for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; if (arg == "-exe" && argidx+1 < args.size()) { diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 78c902866..1345188a4 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -741,8 +741,10 @@ void reintegrate(RTLIL::Module *module) if (mapped_mod == NULL) log_error("ABC output file does not contain a module `%s$abc'.\n", log_id(module)); - for (auto w : mapped_mod->wires()) - module->addWire(remap_name(w->name), GetSize(w)); + for (auto w : mapped_mod->wires()) { + auto nw = module->addWire(remap_name(w->name), GetSize(w)); + nw->start_offset = w->start_offset; + } dict<IdString,std::vector<IdString>> box_ports; @@ -989,7 +991,7 @@ void reintegrate(RTLIL::Module *module) wire->attributes.erase(ID::abc9_scc); RTLIL::Wire *remap_wire = module->wire(remap_name(port)); - RTLIL::SigSpec signal(wire, 0, GetSize(remap_wire)); + RTLIL::SigSpec signal(wire, remap_wire->start_offset-wire->start_offset, GetSize(remap_wire)); log_assert(GetSize(signal) >= GetSize(remap_wire)); RTLIL::SigSig conn; diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc index e4ee4991f..217151e96 100644 --- a/techlibs/ecp5/Makefile.inc +++ b/techlibs/ecp5/Makefile.inc @@ -2,6 +2,15 @@ OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_ffinit.o \ techlibs/ecp5/ecp5_gsr.o +GENFILES += techlibs/ecp5/bram_init_1_2_4.vh +GENFILES += techlibs/ecp5/bram_init_9_18_36.vh +GENFILES += techlibs/ecp5/bram_conn_1.vh +GENFILES += techlibs/ecp5/bram_conn_2.vh +GENFILES += techlibs/ecp5/bram_conn_4.vh +GENFILES += techlibs/ecp5/bram_conn_9.vh +GENFILES += techlibs/ecp5/bram_conn_18.vh +GENFILES += techlibs/ecp5/bram_conn_36.vh + $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_ff.vh)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_io.vh)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v)) diff --git a/techlibs/ecp5/ecp5_ffinit.cc b/techlibs/ecp5/ecp5_ffinit.cc index e85bee64e..ba72bd0c6 100644 --- a/techlibs/ecp5/ecp5_ffinit.cc +++ b/techlibs/ecp5/ecp5_ffinit.cc @@ -106,9 +106,7 @@ struct Ecp5FfinitPass : public Pass { SigBit bit_d = sigmap(sig_d[0]); SigBit bit_q = sigmap(sig_q[0]); - std::string regset = "RESET"; - if (cell->hasParam(ID(REGSET))) - regset = cell->getParam(ID(REGSET)).decode_string(); + std::string regset = cell->getParam(ID(REGSET)).decode_string(); State resetState; if (regset == "SET") resetState = State::S1; @@ -135,9 +133,7 @@ struct Ecp5FfinitPass : public Pass { } if (GetSize(sig_lsr) >= 1 && sig_lsr[0] != State::S0) { - std::string srmode = "LSR_OVER_CE"; - if (cell->hasParam(ID(SRMODE))) - srmode = cell->getParam(ID(SRMODE)).decode_string(); + std::string srmode = cell->getParam(ID(SRMODE)).decode_string(); if (srmode == "ASYNC") { log("Async reset value %c for FF cell %s inconsistent with init value %c.\n", resetState != State::S0 ? '1' : '0', log_id(cell), val != State::S0 ? '1' : '0'); @@ -154,9 +150,7 @@ struct Ecp5FfinitPass : public Pass { cell->setPort(ID(LSR), State::S0); if(cell->hasPort(ID(CE))) { - std::string cemux = "CE"; - if (cell->hasParam(ID(CEMUX))) - cemux = cell->getParam(ID(CEMUX)).decode_string(); + std::string cemux = cell->getParam(ID(CEMUX)).decode_string(); SigSpec sig_ce = cell->getPort(ID(CE)); if (GetSize(sig_ce) >= 1) { SigBit bit_ce = sigmap(sig_ce[0]); diff --git a/techlibs/ecp5/ecp5_gsr.cc b/techlibs/ecp5/ecp5_gsr.cc index d1503f71f..3d3f8e1c1 100644 --- a/techlibs/ecp5/ecp5_gsr.cc +++ b/techlibs/ecp5/ecp5_gsr.cc @@ -114,9 +114,9 @@ struct Ecp5GsrPass : public Pass { { if (cell->type != ID(TRELLIS_FF)) continue; - if (!cell->hasParam(ID(GSR)) || cell->getParam(ID(GSR)).decode_string() != "ENABLED") + if (cell->getParam(ID(GSR)).decode_string() != "ENABLED") continue; - if (!cell->hasParam(ID(SRMODE)) || cell->getParam(ID(SRMODE)).decode_string() != "ASYNC") + if (cell->getParam(ID(SRMODE)).decode_string() != "ASYNC") continue; SigSpec sig_lsr = cell->getPort(ID(LSR)); if (GetSize(sig_lsr) < 1) diff --git a/techlibs/gowin/Makefile.inc b/techlibs/gowin/Makefile.inc index fe5d9d6e6..0756e3bcf 100644 --- a/techlibs/gowin/Makefile.inc +++ b/techlibs/gowin/Makefile.inc @@ -2,6 +2,7 @@ OBJS += techlibs/gowin/synth_gowin.o OBJS += techlibs/gowin/determine_init.o +GENFILES += techlibs/gowin/bram_init_16.vh $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_map.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_sim.v)) @@ -11,8 +12,6 @@ $(eval $(call add_share_file,share/gowin,techlibs/gowin/brams.txt)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/lutrams_map.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/lutrams.txt)) - - $(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_init3.vh)) EXTRA_OBJS += techlibs/gowin/brams_init.mk diff --git a/techlibs/intel_alm/Makefile.inc b/techlibs/intel_alm/Makefile.inc index 66204c8fc..bbf233aeb 100644 --- a/techlibs/intel_alm/Makefile.inc +++ b/techlibs/intel_alm/Makefile.inc @@ -15,9 +15,6 @@ $(foreach bramtype, $(bramtypes), $(eval $(call add_share_file,share/intel_alm/c $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/lutram_mlab.txt)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/lutram_mlab_map.v)) -families := cyclonev cyclone10gx - # Miscellaneous $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/megafunction_bb.v)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/quartus_rename.v)) -$(foreach family, $(families), $(eval $(call add_share_file,share/intel_alm/$(family),techlibs/intel_alm/$(family)/quartus_rename.v))) diff --git a/techlibs/intel_alm/common/quartus_rename.v b/techlibs/intel_alm/common/quartus_rename.v index d9961c174..ac0fe12aa 100644 --- a/techlibs/intel_alm/common/quartus_rename.v +++ b/techlibs/intel_alm/common/quartus_rename.v @@ -1,3 +1,10 @@ +`ifdef cyclonev +`define LCELL cyclonev_lcell_comb +`endif +`ifdef cyclone10gx +`define LCELL cyclone10gx_lcell_comb +`endif + module __MISTRAL_VCC(output Q); MISTRAL_ALUT2 #(.LUT(4'b1111)) _TECHMAP_REPLACE_ (.A(1'b1), .B(1'b1), .Q(Q)); @@ -17,3 +24,59 @@ module MISTRAL_FF(input DATAIN, CLK, ACLR, ENA, SCLR, SLOAD, SDATA, output reg Q dffeas #(.power_up("low"), .is_wysiwyg("true")) _TECHMAP_REPLACE_ (.d(DATAIN), .clk(CLK), .clrn(ACLR), .ena(ENA), .sclr(SCLR), .sload(SLOAD), .asdata(SDATA), .q(Q)); endmodule + + +module MISTRAL_ALUT6(input A, B, C, D, E, F, output Q); +parameter [63:0] LUT = 64'h0000_0000_0000_0000; + +`LCELL #(.lut_mask(LUT)) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .datae(E), .dataf(F), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT5(input A, B, C, D, E, output Q); +parameter [31:0] LUT = 32'h0000_0000; + +`LCELL #(.lut_mask({2{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .datae(E), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT4(input A, B, C, D, output Q); +parameter [15:0] LUT = 16'h0000; + +`LCELL #(.lut_mask({4{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT3(input A, B, C, output Q); +parameter [7:0] LUT = 8'h00; + +`LCELL #(.lut_mask({8{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .combout(Q)); + +endmodule + + +module MISTRAL_ALUT2(input A, B, output Q); +parameter [3:0] LUT = 4'h0; + +`LCELL #(.lut_mask({16{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .combout(Q)); + +endmodule + + +module MISTRAL_NOT(input A, output Q); + +NOT _TECHMAP_REPLACE_ (.IN(A), .OUT(Q)); + +endmodule + + +module MISTRAL_ALUT_ARITH(input A, B, C, D0, D1, CI, output SO, CO); +parameter LUT0 = 16'h0000; +parameter LUT1 = 16'h0000; + +`LCELL #(.lut_mask({16'h0, LUT1, 16'h0, LUT0})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D0), .dataf(D1), .cin(CI), .sumout(SO), .cout(CO)); + +endmodule diff --git a/techlibs/intel_alm/cyclone10gx/quartus_rename.v b/techlibs/intel_alm/cyclone10gx/quartus_rename.v deleted file mode 100644 index 3fbc508ed..000000000 --- a/techlibs/intel_alm/cyclone10gx/quartus_rename.v +++ /dev/null @@ -1,54 +0,0 @@ -module MISTRAL_ALUT6(input A, B, C, D, E, F, output Q); -parameter LUT = 64'h0000_0000_0000_0000; - -cyclone10gx_lcell_comb #(.lut_mask(LUT)) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .datae(E), .dataf(F), .combout(Q)); - -endmodule - - -module MISTRAL_ALUT5(input A, B, C, D, E, output Q); -parameter LUT = 32'h0000_0000; - -cyclone10gx_lcell_comb #(.lut_mask({2{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .datae(E), .combout(Q)); - -endmodule - - -module MISTRAL_ALUT4(input A, B, C, D, output Q); -parameter LUT = 16'h0000; - -cyclone10gx_lcell_comb #(.lut_mask({4{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .combout(Q)); - -endmodule - - -module MISTRAL_ALUT3(input A, B, C, output Q); -parameter LUT = 8'h00; - -cyclone10gx_lcell_comb #(.lut_mask({8{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .combout(Q)); - -endmodule - - -module MISTRAL_ALUT2(input A, B, output Q); -parameter LUT = 4'h0; - -cyclone10gx_lcell_comb #(.lut_mask({16{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .combout(Q)); - -endmodule - - -module MISTRAL_NOT(input A, output Q); - -NOT _TECHMAP_REPLACE_ (.IN(A), .OUT(Q)); - -endmodule - - -module MISTRAL_ALUT_ARITH(input A, B, C, D0, D1, CI, output SO, CO); -parameter LUT0 = 16'h0000; -parameter LUT1 = 16'h0000; - -cyclone10gx_lcell_comb #(.lut_mask({16'h0, LUT1, 16'h0, LUT0})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D0), .dataf(D1), .cin(CI), .sumout(SO), .cout(CO)); - -endmodule diff --git a/techlibs/intel_alm/cyclonev/quartus_rename.v b/techlibs/intel_alm/cyclonev/quartus_rename.v deleted file mode 100644 index 6eff375e1..000000000 --- a/techlibs/intel_alm/cyclonev/quartus_rename.v +++ /dev/null @@ -1,54 +0,0 @@ -module MISTRAL_ALUT6(input A, B, C, D, E, F, output Q); -parameter LUT = 64'h0000_0000_0000_0000; - -cyclonev_lcell_comb #(.lut_mask(LUT)) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .datae(E), .dataf(F), .combout(Q)); - -endmodule - - -module MISTRAL_ALUT5(input A, B, C, D, E, output Q); -parameter LUT = 32'h0000_0000; - -cyclonev_lcell_comb #(.lut_mask({2{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .datae(E), .combout(Q)); - -endmodule - - -module MISTRAL_ALUT4(input A, B, C, D, output Q); -parameter LUT = 16'h0000; - -cyclonev_lcell_comb #(.lut_mask({4{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D), .combout(Q)); - -endmodule - - -module MISTRAL_ALUT3(input A, B, C, output Q); -parameter LUT = 8'h00; - -cyclonev_lcell_comb #(.lut_mask({8{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .combout(Q)); - -endmodule - - -module MISTRAL_ALUT2(input A, B, output Q); -parameter LUT = 4'h0; - -cyclonev_lcell_comb #(.lut_mask({16{LUT}})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .combout(Q)); - -endmodule - - -module MISTRAL_NOT(input A, output Q); - -NOT _TECHMAP_REPLACE_ (.IN(A), .OUT(Q)); - -endmodule - - -module MISTRAL_ALUT_ARITH(input A, B, C, D0, D1, CI, output SO, CO); -parameter LUT0 = 16'h0000; -parameter LUT1 = 16'h0000; - -cyclonev_lcell_comb #(.lut_mask({16'h0, LUT1, 16'h0, LUT0})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D0), .dataf(D1), .cin(CI), .sumout(SO), .cout(CO)); - -endmodule diff --git a/techlibs/intel_alm/synth_intel_alm.cc b/techlibs/intel_alm/synth_intel_alm.cc index 47aa11500..200b0cdd1 100644 --- a/techlibs/intel_alm/synth_intel_alm.cc +++ b/techlibs/intel_alm/synth_intel_alm.cc @@ -200,6 +200,8 @@ struct SynthIntelALMPass : public ScriptPass { if (check_label("map_ffs")) { run("dff2dffe -direct-match $_DFF_*"); + // As mentioned in common/dff_sim.v, Intel flops power up to zero, + // so use `zinit` to add inverters where needed. run("zinit"); run("techmap -map +/techmap.v -map +/intel_alm/common/dff_map.v"); run("opt -full -undriven -mux_undef"); @@ -223,10 +225,17 @@ struct SynthIntelALMPass : public ScriptPass { if (check_label("quartus")) { if (quartus || help_mode) { + // Quartus ICEs if you have a wire which has `[]` in its name, + // which Yosys produces when building memories out of flops. + run("rename -hide w:*[* w:*]*"); + // VQM mode does not support 'x, so replace those with zero. run("setundef -zero"); + // VQM mode does not support multi-bit constant assignments + // (e.g. 2'b00 is an error), so as a workaround use references + // to constant driver cells, which Quartus accepts. run("hilomap -singleton -hicell __MISTRAL_VCC Q -locell __MISTRAL_GND Q"); - run("techmap -map +/intel_alm/common/quartus_rename.v"); - run(stringf("techmap -map +/intel_alm/%s/quartus_rename.v", family_opt.c_str())); + // Rename from Yosys-internal MISTRAL_* cells to Quartus cells. + run(stringf("techmap -D %s -map +/intel_alm/common/quartus_rename.v", family_opt.c_str())); } } diff --git a/techlibs/xilinx/xilinx_dffopt.cc b/techlibs/xilinx/xilinx_dffopt.cc index c608db883..c9d63c9f7 100644 --- a/techlibs/xilinx/xilinx_dffopt.cc +++ b/techlibs/xilinx/xilinx_dffopt.cc @@ -292,18 +292,21 @@ unmap: LutData final_lut; if (worthy_post_r) { final_lut = lut_d_post_r; - log(" Merging R LUT for %s/%s (%d -> %d)\n", log_id(cell), log_id(sig_Q.wire), GetSize(lut_d.second), GetSize(final_lut.second)); } else if (worthy_post_s) { final_lut = lut_d_post_s; - log(" Merging S LUT for %s/%s (%d -> %d)\n", log_id(cell), log_id(sig_Q.wire), GetSize(lut_d.second), GetSize(final_lut.second)); } else if (worthy_post_ce) { final_lut = lut_d_post_ce; - log(" Merging CE LUT for %s/%s (%d -> %d)\n", log_id(cell), log_id(sig_Q.wire), GetSize(lut_d.second), GetSize(final_lut.second)); } else { // Nothing to do here. continue; } + std::string ports; + if (worthy_post_r) ports += " + R"; + if (worthy_post_s) ports += " + S"; + if (worthy_post_ce) ports += " + CE"; + log(" Merging D%s LUTs for %s/%s (%d -> %d)\n", ports.c_str(), log_id(cell), log_id(sig_Q.wire), GetSize(lut_d.second), GetSize(final_lut.second)); + // Okay, we're doing it. Unmap ports. if (worthy_post_r) { cell->unsetParam(ID(IS_R_INVERTED)); diff --git a/tests/aiger/neg.ys b/tests/aiger/neg.ys new file mode 100644 index 000000000..4c1edd8a4 --- /dev/null +++ b/tests/aiger/neg.ys @@ -0,0 +1,36 @@ +read_verilog <<EOT +module top(input [31:-32] a, input [-65:-128] b, output [128:65] c); +assign c = a & b; +endmodule +EOT +select -assert-count 1 i:a +select -assert-count 1 i:b +select -assert-count 1 o:c +select -assert-count 3 x:* s:64 %i +design -save read + +!rm -rf neg.out +!mkdir neg.out +simplemap +write_aiger -map neg.out/neg.map neg.out/neg.aig + +design -reset +read_aiger -wideports -map neg.out/neg.map neg.out/neg.aig +select -assert-count 1 i:a +select -assert-count 1 i:b +select -assert-count 1 o:c +select -assert-count 3 x:* s:64 %i + + +design -load read +!rm -rf neg.out +!mkdir neg.out +simplemap +write_xaiger -map neg.out/neg.map neg.out/neg.aig + +design -reset +read_aiger -wideports -map neg.out/neg.map neg.out/neg.aig +select -assert-count 1 i:a +select -assert-count 1 i:b +select -assert-count 1 o:c +select -assert-count 3 x:* s:64 %i diff --git a/tests/aiger/run-test.sh b/tests/aiger/run-test.sh index 8e932b091..de7bc68cf 100755 --- a/tests/aiger/run-test.sh +++ b/tests/aiger/run-test.sh @@ -52,3 +52,8 @@ miter -equiv -flatten -make_assert -make_outputs gold gate miter sat -verify -prove-asserts -show-ports -seq 16 miter " -l ${aig}.log done + +for y in *.ys; do + echo "Running $y." + ../../yosys $y -ql ${y%.*}.log +done diff --git a/tests/arch/ice40/ice40_dsp.ys b/tests/arch/ice40/ice40_dsp.ys index 250273859..b13e525fd 100644 --- a/tests/arch/ice40/ice40_dsp.ys +++ b/tests/arch/ice40/ice40_dsp.ys @@ -8,4 +8,5 @@ assign o4 = a * b; SB_MAC16 m3 (.A(a), .B(b), .O(o5)); endmodule EOT +read_verilog -lib +/ice40/cells_sim.v ice40_dsp diff --git a/tests/arch/intel_alm/quartus_ice.ys b/tests/arch/intel_alm/quartus_ice.ys new file mode 100644 index 000000000..4b9b54d10 --- /dev/null +++ b/tests/arch/intel_alm/quartus_ice.ys @@ -0,0 +1,12 @@ +read_verilog <<EOT +// Verilog has syntax for raw identifiers, where you start it with \ and end it with a space. +// This test crashes Quartus due to it parsing \a[10] as a wire slice and not a raw identifier. +module top(); + (* keep *) wire [31:0] \a[10] ; + (* keep *) wire b; + assign b = \a[10] [31]; +endmodule +EOT + +synth_intel_alm -family cyclonev -quartus +select -assert-none w:*[* w:*]* diff --git a/tests/arch/xilinx/xilinx_dffopt.ys b/tests/arch/xilinx/xilinx_dffopt.ys index dc036acfd..2c729832e 100644 --- a/tests/arch/xilinx/xilinx_dffopt.ys +++ b/tests/arch/xilinx/xilinx_dffopt.ys @@ -18,17 +18,17 @@ FDRE ff (.D(tmp[0]), .CE(tmp[1]), .R(tmp[2]), .Q(o[0])); endmodule EOT - +read_verilog -lib +/xilinx/cells_sim.v design -save t0 equiv_opt -blacklist xilinx_dffopt_blacklist.txt -assert -map +/xilinx/cells_sim.v xilinx_dffopt design -load postopt clean +cd t0 select -assert-count 1 t:FDRE select -assert-count 1 t:LUT6 -select -assert-count 3 t:LUT2 -select -assert-none t:FDRE t:LUT6 t:LUT2 %% t:* %D +select -assert-none t:FDRE t:LUT6 %% t:* %D design -load t0 @@ -36,9 +36,10 @@ equiv_opt -blacklist xilinx_dffopt_blacklist.txt -assert -map +/xilinx/cells_sim design -load postopt clean +cd t0 select -assert-count 1 t:FDRE select -assert-count 1 t:LUT4 -select -assert-count 3 t:LUT2 +select -assert-count 1 t:LUT2 select -assert-none t:FDRE t:LUT4 t:LUT2 %% t:* %D design -reset @@ -65,16 +66,17 @@ endmodule EOT +read_verilog -lib +/xilinx/cells_sim.v design -save t0 equiv_opt -blacklist xilinx_dffopt_blacklist.txt -assert -map +/xilinx/cells_sim.v xilinx_dffopt design -load postopt clean +cd t0 select -assert-count 1 t:FDSE select -assert-count 1 t:LUT6 -select -assert-count 3 t:LUT2 -select -assert-none t:FDSE t:LUT6 t:LUT2 %% t:* %D +select -assert-none t:FDSE t:LUT6 %% t:* %D design -load t0 @@ -82,9 +84,10 @@ equiv_opt -blacklist xilinx_dffopt_blacklist.txt -assert -map +/xilinx/cells_sim design -load postopt clean +cd t0 select -assert-count 1 t:FDSE select -assert-count 1 t:LUT4 -select -assert-count 3 t:LUT2 +select -assert-count 1 t:LUT2 select -assert-none t:FDSE t:LUT4 t:LUT2 %% t:* %D design -reset @@ -111,15 +114,17 @@ endmodule EOT +read_verilog -lib +/xilinx/cells_sim.v design -save t0 equiv_opt -async2sync -blacklist xilinx_dffopt_blacklist.txt -assert -map +/xilinx/cells_sim.v xilinx_dffopt design -load postopt clean +cd t0 select -assert-count 1 t:FDCE select -assert-count 1 t:LUT4 -select -assert-count 3 t:LUT2 +select -assert-count 1 t:LUT2 select -assert-none t:FDCE t:LUT4 t:LUT2 %% t:* %D design -reset @@ -145,16 +150,17 @@ endmodule EOT +read_verilog -lib +/xilinx/cells_sim.v design -save t0 equiv_opt -blacklist xilinx_dffopt_blacklist.txt -assert -map +/xilinx/cells_sim.v xilinx_dffopt design -load postopt clean +cd t0 select -assert-count 1 t:FDSE select -assert-count 1 t:LUT5 -select -assert-count 2 t:LUT2 -select -assert-none t:FDSE t:LUT5 t:LUT2 %% t:* %D +select -assert-none t:FDSE t:LUT5 %% t:* %D design -load t0 @@ -162,6 +168,7 @@ equiv_opt -blacklist xilinx_dffopt_blacklist.txt -assert -map +/xilinx/cells_sim design -load postopt clean +cd t0 select -assert-count 1 t:FDSE select -assert-count 2 t:LUT2 select -assert-none t:FDSE t:LUT2 %% t:* %D @@ -191,16 +198,17 @@ endmodule EOT +read_verilog -lib +/xilinx/cells_sim.v design -save t0 equiv_opt -blacklist xilinx_dffopt_blacklist.txt -assert -map +/xilinx/cells_sim.v xilinx_dffopt design -load postopt clean +cd t0 select -assert-count 1 t:FDRSE select -assert-count 1 t:LUT6 -select -assert-count 4 t:LUT2 -select -assert-none t:FDRSE t:LUT6 t:LUT2 %% t:* %D +select -assert-none t:FDRSE t:LUT6 %% t:* %D design -load t0 @@ -208,9 +216,10 @@ equiv_opt -blacklist xilinx_dffopt_blacklist.txt -assert -map +/xilinx/cells_sim design -load postopt clean +cd t0 select -assert-count 1 t:FDRSE select -assert-count 1 t:LUT4 -select -assert-count 4 t:LUT2 +select -assert-count 1 t:LUT2 select -assert-none t:FDRSE t:LUT4 t:LUT2 %% t:* %D design -reset diff --git a/tests/arch/xilinx/xilinx_dsp.ys b/tests/arch/xilinx/xilinx_dsp.ys index 3b9f52930..59d8296ab 100644 --- a/tests/arch/xilinx/xilinx_dsp.ys +++ b/tests/arch/xilinx/xilinx_dsp.ys @@ -8,4 +8,5 @@ assign o4 = a * b; DSP48E1 m3 (.A(a), .B(b), .P(o5)); endmodule EOT +read_verilog -lib +/xilinx/cells_sim.v xilinx_dsp diff --git a/tests/opt/bug2010.ys b/tests/opt/bug2010.ys new file mode 100644 index 000000000..cef820867 --- /dev/null +++ b/tests/opt/bug2010.ys @@ -0,0 +1,10 @@ +read_verilog <<EOT +module test ( + input signed [1:0] n, + output [3:0] dout +); + assign dout = n + 4'sd 4; +endmodule +EOT + +equiv_opt -assert opt -fine diff --git a/tests/select/blackboxes.ys b/tests/select/blackboxes.ys new file mode 100644 index 000000000..9bfe92c6b --- /dev/null +++ b/tests/select/blackboxes.ys @@ -0,0 +1,28 @@ +read_verilog -specify <<EOT +module top(input a, b, output o); +assign o = a & b; +endmodule + +(* blackbox *) +module bb(input a, b, output o); +assign o = a | b; +specify + (a => o) = 1; +endspecify +endmodule + +(* whitebox *) +module wb(input a, b, output o); +assign o = a ^ b; +endmodule +EOT +clean + +select -assert-count 1 c:* +select -assert-none t:* t:$and %d +select -assert-count 3 w:* +select -assert-count 4 * + +select -assert-count 3 =c:* +select -assert-count 10 =w:* +select -assert-count 13 =* diff --git a/tests/various/bug2014.ys b/tests/various/bug2014.ys new file mode 100644 index 000000000..10131fc43 --- /dev/null +++ b/tests/various/bug2014.ys @@ -0,0 +1,12 @@ +read_verilog <<EOT +module test ( + input signed [1:0] n, + output [3:0] dout +); + assign dout = n + 4'sd 4; +endmodule +EOT + +alumacc +select -assert-count 1 t:$alu +equiv_opt -assert opt -fine |