diff options
79 files changed, 1338 insertions, 522 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 @@ -79,7 +82,6 @@ YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST))) VPATH := $(YOSYS_SRC) CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -D_YOSYS_ -fPIC -I$(PREFIX)/include -LDFLAGS := $(LDFLAGS) -L$(LIBDIR) LDLIBS := $(LDLIBS) -lstdc++ -lm PLUGIN_LDFLAGS := @@ -133,9 +135,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 = fd2c9b1 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 +255,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 +278,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++ @@ -337,7 +370,7 @@ BOOST_PYTHON_LIB ?= $(shell \ endif ifeq ($(BOOST_PYTHON_LIB),) -$(error BOOST_PYTHON_LIB could not be detected. Please define manualy) +$(error BOOST_PYTHON_LIB could not be detected. Please define manually) endif ifeq ($(OS), Darwin) @@ -396,6 +429,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 +621,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 +634,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 @@ -684,7 +721,7 @@ ifneq ($(ABCREV),default) test $(ABCPULL) -ne 0 || { echo 'REEBE: NOP abg hc gb qngr naq NOPCHYY frg gb 0 va Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; exit 1; }; \ echo "Pulling ABC from $(ABCURL):"; set -x; \ test -d abc || git clone $(ABCURL) abc; \ - cd abc && $(MAKE) DEP= clean && git fetch origin master && git checkout $(ABCREV); \ + cd abc && $(MAKE) DEP= clean && git fetch $(ABCURL) && git checkout $(ABCREV); \ fi endif $(Q) rm -f abc/abc-[0-9a-f]* @@ -743,6 +780,7 @@ test: $(TARGETS) $(EXTRA_TARGETS) +cd tests/arch/intel_alm && bash run-test.sh $(SEEDOPT) +cd tests/rpc && bash run-test.sh +cd tests/memfile && bash run-test.sh + +cd tests/verilog && bash run-test.sh @echo "" @echo " Passed \"make test\"." @echo "" @@ -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 =============== @@ -274,6 +281,9 @@ Verilog Attributes and non-standard features temporary variable within an always block. This is mostly used internally by Yosys to synthesize Verilog functions and access arrays. +- The ``nowrshmsk`` attribute on a register prohibits the generation of + shift-and-mask type circuits for writing to bit slices of that register. + - The ``onehot`` attribute on wires mark them as one-hot state register. This is used for example for memory port sharing and set by the fsm_map pass. @@ -388,7 +398,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..f3ed3f623 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); @@ -1942,13 +1943,13 @@ struct CxxrtlWorker { case RTLIL::STa: break; + case RTLIL::STg: + log_cmd_error("Global clock is not supported.\n"); + // Handling of init-type sync rules is delegated to the `proc_init` pass, so we can use the wire // attribute regardless of input. case RTLIL::STi: log_assert(false); - - case RTLIL::STg: - log_cmd_error("Global clock is not supported.\n"); } } @@ -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"); @@ -2345,16 +2346,22 @@ struct CxxrtlBackend : public Backend { case 6: worker.max_opt_level = true; worker.run_proc_flatten = true; + YS_FALLTHROUGH case 5: worker.run_opt_clean_purge = true; + YS_FALLTHROUGH case 4: worker.localize_public = true; + YS_FALLTHROUGH case 3: worker.elide_public = true; + YS_FALLTHROUGH case 2: worker.localize_internal = true; + YS_FALLTHROUGH case 1: worker.elide_internal = true; + YS_FALLTHROUGH case 0: break; default: diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index 40d05a036..f6dae1d8c 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -343,7 +343,7 @@ struct FirrtlWorker switch (dir) { case FD_INOUT: log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second)); - /* FALLTHRU */ + YS_FALLTHROUGH case FD_OUT: sourceExpr = firstName; sinkExpr = secondExpr; @@ -351,7 +351,7 @@ struct FirrtlWorker break; case FD_NODIRECTION: log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second)); - /* FALLTHRU */ + YS_FALLTHROUGH case FD_IN: sourceExpr = secondExpr; sinkExpr = firstName; 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..689fa9fb4 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -94,6 +94,7 @@ std::string AST::type2str(AstNodeType type) X(AST_TO_BITS) X(AST_TO_SIGNED) X(AST_TO_UNSIGNED) + X(AST_SELFSZ) X(AST_CONCAT) X(AST_REPLICATE) X(AST_BIT_NOT) @@ -110,6 +111,8 @@ std::string AST::type2str(AstNodeType type) X(AST_SHIFT_RIGHT) X(AST_SHIFT_SLEFT) X(AST_SHIFT_SRIGHT) + X(AST_SHIFTX) + X(AST_SHIFT) X(AST_LT) X(AST_LE) X(AST_EQ) @@ -615,6 +618,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const if (0) { case AST_POS: txt = "+"; } if (0) { case AST_NEG: txt = "-"; } if (0) { case AST_LOGIC_NOT: txt = "!"; } + if (0) { case AST_SELFSZ: txt = "@selfsz@"; } fprintf(f, "%s(", txt.c_str()); children[0]->dumpVlog(f, ""); fprintf(f, ")"); @@ -628,6 +632,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const if (0) { case AST_SHIFT_RIGHT: txt = ">>"; } if (0) { case AST_SHIFT_SLEFT: txt = "<<<"; } if (0) { case AST_SHIFT_SRIGHT: txt = ">>>"; } + if (0) { case AST_SHIFTX: txt = "@shiftx@"; } + if (0) { case AST_SHIFT: txt = "@shift@"; } if (0) { case AST_LT: txt = "<"; } if (0) { case AST_LE: txt = "<="; } if (0) { case AST_EQ: txt = "=="; } @@ -946,6 +952,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 +1124,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 +1237,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/ast/ast.h b/frontends/ast/ast.h index 3f6329112..8932108e3 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -75,6 +75,7 @@ namespace AST AST_TO_BITS, AST_TO_SIGNED, AST_TO_UNSIGNED, + AST_SELFSZ, AST_CONCAT, AST_REPLICATE, AST_BIT_NOT, @@ -91,6 +92,8 @@ namespace AST AST_SHIFT_RIGHT, AST_SHIFT_SLEFT, AST_SHIFT_SRIGHT, + AST_SHIFTX, + AST_SHIFT, AST_LT, AST_LE, AST_EQ, diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index d35335747..d4e9baa5f 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -43,12 +43,12 @@ using namespace AST_INTERNAL; // helper function for creating RTLIL code for unary operations static RTLIL::SigSpec uniop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &arg, bool gen_attributes = true) { - IdString name = stringf("%s$%s:%d$%d", type.c_str(), that->filename.c_str(), that->location.first_line, autoidx++); + IdString name = stringf("%s$%s:%d$%d", type.c_str(), that->filename.c_str(), that->location.first_line, autoidx++); RTLIL::Cell *cell = current_module->addCell(name, type); - cell->attributes[ID::src] = stringf("%s:%d", that->filename.c_str(), that->location.first_line); + cell->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", that->filename.c_str(), that->location.first_line, that->location.first_column, that->location.last_line, that->location.last_column); RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_Y", result_width); - wire->attributes[ID::src] = stringf("%s:%d", that->filename.c_str(), that->location.first_line); + wire->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", that->filename.c_str(), that->location.first_line, that->location.first_column, that->location.last_line, that->location.last_column); if (gen_attributes) for (auto &attr : that->attributes) { @@ -74,12 +74,12 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s return; } - IdString name = stringf("$extend$%s:%d$%d", that->filename.c_str(), that->location.first_line, autoidx++); + IdString name = stringf("$extend$%s:%d$%d", that->filename.c_str(), that->location.first_line, autoidx++); RTLIL::Cell *cell = current_module->addCell(name, ID($pos)); - cell->attributes[ID::src] = stringf("%s:%d", that->filename.c_str(), that->location.first_line); + cell->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", that->filename.c_str(), that->location.first_line, that->location.first_column, that->location.last_line, that->location.last_column); RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_Y", width); - wire->attributes[ID::src] = stringf("%s:%d", that->filename.c_str(), that->location.first_line); + wire->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", that->filename.c_str(), that->location.first_line, that->location.first_column, that->location.last_line, that->location.last_column); if (that != NULL) for (auto &attr : that->attributes) { @@ -100,12 +100,12 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s // helper function for creating RTLIL code for binary operations static RTLIL::SigSpec binop2rtlil(AstNode *that, IdString type, int result_width, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right) { - IdString name = stringf("%s$%s:%d$%d", type.c_str(), that->filename.c_str(), that->location.first_line, autoidx++); + IdString name = stringf("%s$%s:%d$%d", type.c_str(), that->filename.c_str(), that->location.first_line, autoidx++); RTLIL::Cell *cell = current_module->addCell(name, type); - cell->attributes[ID::src] = stringf("%s:%d", that->filename.c_str(), that->location.first_line); + cell->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", that->filename.c_str(), that->location.first_line, that->location.first_column, that->location.last_line, that->location.last_column); RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_Y", result_width); - wire->attributes[ID::src] = stringf("%s:%d", that->filename.c_str(), that->location.first_line); + wire->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", that->filename.c_str(), that->location.first_line, that->location.first_column, that->location.last_line, that->location.last_column); for (auto &attr : that->attributes) { if (attr.second->type != AST_CONSTANT) @@ -136,10 +136,10 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const sstr << "$ternary$" << that->filename << ":" << that->location.first_line << "$" << (autoidx++); RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($mux)); - cell->attributes[ID::src] = stringf("%s:%d", that->filename.c_str(), that->location.first_line); + cell->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", that->filename.c_str(), that->location.first_line, that->location.first_column, that->location.last_line, that->location.last_column); RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_Y", left.size()); - wire->attributes[ID::src] = stringf("%s:%d", that->filename.c_str(), that->location.first_line); + wire->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", that->filename.c_str(), that->location.first_line, that->location.first_column, that->location.last_line, that->location.last_column); for (auto &attr : that->attributes) { if (attr.second->type != AST_CONSTANT) @@ -171,7 +171,7 @@ struct AST_INTERNAL::LookaheadRewriter for (auto c : node->id2ast->children) wire->children.push_back(c->clone()); wire->str = stringf("$lookahead%s$%d", node->str.c_str(), autoidx++); - wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false); + wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); wire->is_logic = true; while (wire->simplify(true, false, false, 1, -1, false, false)) { } current_ast_mod->children.push_back(wire); @@ -809,6 +809,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun sign_hint = false; break; + case AST_SELFSZ: + sub_width_hint = 0; + children.at(0)->detectSignWidthWorker(sub_width_hint, sign_hint); + break; + case AST_CONCAT: for (auto child : children) { sub_width_hint = 0; @@ -856,6 +861,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_SHIFT_RIGHT: case AST_SHIFT_SLEFT: case AST_SHIFT_SRIGHT: + case AST_SHIFTX: + case AST_SHIFT: case AST_POW: children[0]->detectSignWidthWorker(width_hint, sign_hint, found_real); break; @@ -923,7 +930,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun } break; } - /* fall through */ + YS_FALLTHROUGH // everything should have been handled above -> print error if not. default: @@ -1019,7 +1026,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (GetSize(children) >= 1 && children[0]->type == AST_CONSTANT) { current_module->parameter_default_values[str] = children[0]->asParaConst(); } - /* fall through */ + YS_FALLTHROUGH case AST_LOCALPARAM: if (flag_pwires) { @@ -1205,13 +1212,18 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : children[0]->children[0]->clone()); fake_ast->children[0]->delete_children(); - RTLIL::SigSpec shift_val = fake_ast->children[1]->genRTLIL(); + + int fake_ast_width = 0; + bool fake_ast_sign = true; + fake_ast->children[1]->detectSignWidth(fake_ast_width, fake_ast_sign); + RTLIL::SigSpec shift_val = fake_ast->children[1]->genRTLIL(fake_ast_width, fake_ast_sign); + if (id2ast->range_right != 0) { - shift_val = current_module->Sub(NEW_ID, shift_val, id2ast->range_right, fake_ast->children[1]->is_signed); + shift_val = current_module->Sub(NEW_ID, shift_val, id2ast->range_right, fake_ast_sign); fake_ast->children[1]->is_signed = true; } if (id2ast->range_swapped) { - shift_val = current_module->Sub(NEW_ID, RTLIL::SigSpec(source_width - width), shift_val, fake_ast->children[1]->is_signed); + shift_val = current_module->Sub(NEW_ID, RTLIL::SigSpec(source_width - width), shift_val, fake_ast_sign); fake_ast->children[1]->is_signed = true; } if (GetSize(shift_val) >= 32) @@ -1265,7 +1277,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // just pass thru the signal. the parent will evaluate the is_signed property and interpret the SigSpec accordingly case AST_TO_SIGNED: - case AST_TO_UNSIGNED: { + case AST_TO_UNSIGNED: + case AST_SELFSZ: { RTLIL::SigSpec sig = children[0]->genRTLIL(); if (sig.size() < width_hint) sig.extend_u0(width_hint, sign_hint); @@ -1356,6 +1369,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (0) { case AST_SHIFT_RIGHT: type_name = ID($shr); } if (0) { case AST_SHIFT_SLEFT: type_name = ID($sshl); } if (0) { case AST_SHIFT_SRIGHT: type_name = ID($sshr); } + if (0) { case AST_SHIFTX: type_name = ID($shiftx); } + if (0) { case AST_SHIFT: type_name = ID($shift); } { if (width_hint < 0) detectSignWidth(width_hint, sign_hint); @@ -1500,10 +1515,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) sstr << "$memrd$" << str << "$" << filename << ":" << location.first_line << "$" << (autoidx++); RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($memrd)); - cell->attributes[ID::src] = stringf("%s:%d", filename.c_str(), location.first_line); + cell->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column); RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_DATA", current_module->memories[str]->width); - wire->attributes[ID::src] = stringf("%s:%d", filename.c_str(), location.first_line); + wire->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column); int mem_width, mem_size, addr_bits; is_signed = id2ast->is_signed; @@ -1807,7 +1822,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) is_signed = sign_hint; return SigSpec(wire); } - } /* fall through */ + } + YS_FALLTHROUGH // everything should have been handled above -> print error if not. default: diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 837c14ad7..f629df387 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -91,7 +91,7 @@ std::string AstNode::process_format_str(const std::string &sformat, int next_arg case 'D': if (got_len) goto unsupported_format; - /* fall through */ + YS_FALLTHROUGH case 'x': case 'X': if (next_arg >= GetSize(children)) @@ -608,6 +608,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, case AST_TO_BITS: case AST_TO_SIGNED: case AST_TO_UNSIGNED: + case AST_SELFSZ: case AST_CONCAT: case AST_REPLICATE: case AST_REDUCE_AND: @@ -920,11 +921,11 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, range_swapped = templ->range_swapped; range_left = templ->range_left; range_right = templ->range_right; - attributes["\\wiretype"] = mkconst_str(resolved_type->str); + attributes[ID::wiretype] = mkconst_str(resolved_type->str); //check if enum - if (templ->attributes.count("\\enum_type")){ + if (templ->attributes.count(ID::enum_type)){ //get reference to enum node: - std::string enum_type = templ->attributes["\\enum_type"]->str.c_str(); + const std::string &enum_type = templ->attributes[ID::enum_type]->str; // log("enum_type=%s (count=%lu)\n", enum_type.c_str(), current_scope.count(enum_type)); // log("current scope:\n"); // for (auto &it : current_scope) @@ -972,7 +973,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, RTLIL::Const val = enum_item->children[0]->bitsAsConst(width, is_signed); enum_item_str.append(val.as_string()); //set attribute for available val to enum item name mappings - attributes[enum_item_str.c_str()] = mkconst_str(enum_item->str); + attributes[enum_item_str] = mkconst_str(enum_item->str); } } @@ -1021,7 +1022,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, range_swapped = templ->range_swapped; range_left = templ->range_left; range_right = templ->range_right; - attributes["\\wiretype"] = mkconst_str(resolved_type->str); + attributes[ID::wiretype] = mkconst_str(resolved_type->str); for (auto template_child : templ->children) children.push_back(template_child->clone()); did_something = true; @@ -1079,7 +1080,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } if (old_range_valid != range_valid) did_something = true; - if (range_valid && range_left >= 0 && range_right > range_left) { + if (range_valid && range_right > range_left) { int tmp = range_right; range_right = range_left; range_left = tmp; @@ -1739,8 +1740,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, AstNode *node = children_list[1]; if (op_type != AST_POS) - for (size_t i = 2; i < children_list.size(); i++) + for (size_t i = 2; i < children_list.size(); i++) { node = new AstNode(op_type, node, children_list[i]); + node->location = location; + } if (invert_results) node = new AstNode(AST_BIT_NOT, node); @@ -1786,7 +1789,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; } - if (0) + bool use_case_method = false; + + if (children[0]->id2ast->attributes.count(ID::nowrshmsk)) { + AstNode *node = children[0]->id2ast->attributes.at(ID::nowrshmsk); + while (node->simplify(true, false, false, stage, -1, false, false)) { } + if (node->type != AST_CONSTANT) + log_file_error(filename, location.first_line, "Non-constant value for `nowrshmsk' attribute on `%s'!\n", children[0]->id2ast->str.c_str()); + if (node->asAttrConst().as_bool()) + use_case_method = true; + } + + if (use_case_method) { // big case block @@ -1794,10 +1808,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, newNode = new AstNode(AST_CASE, shift_expr); for (int i = 0; i < source_width; i++) { int start_bit = children[0]->id2ast->range_right + i; + int end_bit = std::min(start_bit+result_width,source_width) - 1; AstNode *cond = new AstNode(AST_COND, mkconst_int(start_bit, true)); AstNode *lvalue = children[0]->clone(); lvalue->delete_children(); - int end_bit = std::min(start_bit+result_width,source_width) - 1; lvalue->children.push_back(new AstNode(AST_RANGE, mkconst_int(end_bit, true), mkconst_int(start_bit, true))); cond->children.push_back(new AstNode(AST_BLOCK, new AstNode(type, lvalue, children[1]->clone()))); @@ -1810,14 +1824,14 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, AstNode *wire_mask = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true))); wire_mask->str = stringf("$bitselwrite$mask$%s:%d$%d", filename.c_str(), location.first_line, autoidx++); - wire_mask->attributes["\\nosync"] = AstNode::mkconst_int(1, false); + wire_mask->attributes[ID::nosync] = AstNode::mkconst_int(1, false); wire_mask->is_logic = true; while (wire_mask->simplify(true, false, false, 1, -1, false, false)) { } current_ast_mod->children.push_back(wire_mask); AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true))); wire_data->str = stringf("$bitselwrite$data$%s:%d$%d", filename.c_str(), location.first_line, autoidx++); - wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false); + wire_data->attributes[ID::nosync] = AstNode::mkconst_int(1, false); wire_data->is_logic = true; while (wire_data->simplify(true, false, false, 1, -1, false, false)) { } current_ast_mod->children.push_back(wire_data); @@ -1844,11 +1858,40 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, AstNode *shamt = shift_expr; - newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, ref_mask->clone(), - new AstNode(AST_SHIFT_LEFT, mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), shamt->clone()))); - newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, ref_data->clone(), - new AstNode(AST_SHIFT_LEFT, new AstNode(AST_BIT_AND, mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), children[1]->clone()), shamt))); - newNode->children.push_back(new AstNode(type, lvalue, new AstNode(AST_BIT_OR, new AstNode(AST_BIT_AND, old_data, new AstNode(AST_BIT_NOT, ref_mask)), ref_data))); + int shamt_width_hint = 0; + bool shamt_sign_hint = true; + shamt->detectSignWidth(shamt_width_hint, shamt_sign_hint); + + int start_bit = children[0]->id2ast->range_right; + bool use_shift = shamt_sign_hint; + + if (start_bit != 0) { + shamt = new AstNode(AST_SUB, shamt, mkconst_int(start_bit, true)); + use_shift = true; + } + + AstNode *t; + + t = mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false); + if (use_shift) + t = new AstNode(AST_SHIFT, t, new AstNode(AST_NEG, shamt->clone())); + else + t = new AstNode(AST_SHIFT_LEFT, t, shamt->clone()); + t = new AstNode(AST_ASSIGN_EQ, ref_mask->clone(), t); + newNode->children.push_back(t); + + t = new AstNode(AST_BIT_AND, mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), children[1]->clone()); + if (use_shift) + t = new AstNode(AST_SHIFT, t, new AstNode(AST_NEG, shamt)); + else + t = new AstNode(AST_SHIFT_LEFT, t, shamt); + t = new AstNode(AST_ASSIGN_EQ, ref_data->clone(), t); + newNode->children.push_back(t); + + t = new AstNode(AST_BIT_AND, old_data, new AstNode(AST_BIT_NOT, ref_mask)); + t = new AstNode(AST_BIT_OR, t, ref_data); + t = new AstNode(type, lvalue, t); + newNode->children.push_back(t); } goto apply_newNode; @@ -2637,7 +2680,7 @@ skip_dynamic_range_lvalue_expansion:; bool recommend_const_eval = false; bool require_const_eval = in_param ? false : has_const_only_constructs(recommend_const_eval); - if ((in_param || recommend_const_eval || require_const_eval) && !decl->attributes.count("\\via_celltype")) + if ((in_param || recommend_const_eval || require_const_eval) && !decl->attributes.count(ID::via_celltype)) { bool all_args_const = true; for (auto child : children) { @@ -2696,9 +2739,9 @@ skip_dynamic_range_lvalue_expansion:; goto replace_fcall_with_id; } - if (decl->attributes.count("\\via_celltype")) + if (decl->attributes.count(ID::via_celltype)) { - std::string celltype = decl->attributes.at("\\via_celltype")->asAttrConst().decode_string(); + std::string celltype = decl->attributes.at(ID::via_celltype)->asAttrConst().decode_string(); std::string outport = str; if (celltype.find(' ') != std::string::npos) { @@ -2792,7 +2835,7 @@ skip_dynamic_range_lvalue_expansion:; wire->is_reg = true; wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); if (child->type == AST_ENUM_ITEM) - wire->attributes["\\enum_base_type"] = child->attributes["\\enum_base_type"]; + wire->attributes[ID::enum_base_type] = child->attributes[ID::enum_base_type]; wire_cache[child->str] = wire; @@ -3024,6 +3067,7 @@ replace_fcall_later:; } } break; + if (0) { case AST_SELFSZ: const_func = RTLIL::const_pos; } if (0) { case AST_POS: const_func = RTLIL::const_pos; } if (0) { case AST_NEG: const_func = RTLIL::const_neg; } if (children[0]->type == AST_CONSTANT) { @@ -3032,10 +3076,10 @@ replace_fcall_later:; } else if (children[0]->isConst()) { newNode = new AstNode(AST_REALVALUE); - if (type == AST_POS) - newNode->realvalue = +children[0]->asReal(sign_hint); - else + if (type == AST_NEG) newNode->realvalue = -children[0]->asReal(sign_hint); + else + newNode->realvalue = +children[0]->asReal(sign_hint); } break; case AST_TERNARY: @@ -4092,7 +4136,7 @@ void AstNode::allocateDefaultEnumValues() int last_enum_int = -1; for (auto node : children) { log_assert(node->type==AST_ENUM_ITEM); - node->attributes["\\enum_base_type"] = mkconst_str(str); + node->attributes[ID::enum_base_type] = mkconst_str(str); for (size_t i = 0; i < node->children.size(); i++) { switch (node->children[i]->type) { case AST_NONE: diff --git a/frontends/ilang/ilang_parser.y b/frontends/ilang/ilang_parser.y index 8e21fb176..118f13de9 100644 --- a/frontends/ilang/ilang_parser.y +++ b/frontends/ilang/ilang_parser.y @@ -107,16 +107,16 @@ module: delete_current_module = false; if (current_design->has($2)) { RTLIL::Module *existing_mod = current_design->module($2); - if (!flag_overwrite && (flag_lib || (attrbuf.count("\\blackbox") && attrbuf.at("\\blackbox").as_bool()))) { + if (!flag_overwrite && (flag_lib || (attrbuf.count(ID::blackbox) && attrbuf.at(ID::blackbox).as_bool()))) { log("Ignoring blackbox re-definition of module %s.\n", $2); delete_current_module = true; - } else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) { + } else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute(ID::blackbox)) { rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of module %s.", $2).c_str()); } else if (flag_nooverwrite) { log("Ignoring re-definition of module %s.\n", $2); delete_current_module = true; } else { - log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute("\\blackbox") ? " blackbox" : "", $2); + log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute(ID::blackbox) ? " blackbox" : "", $2); current_design->remove(existing_mod); } } 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 ae7fcefa7..5f8a78e48 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; @@ -1153,26 +1215,6 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se for (auto net : anyseq_nets) module->connect(net_map_at(net), module->Anyseq(new_verific_id(net))); - char *id_name; - TypeRange *type_range; - FOREACH_MAP_ITEM(nl->GetTypeRangeTable(), mi, &id_name, &type_range) - { - if (!type_range) - continue; - if (!type_range->IsTypeEnum()) - continue; - auto wire = module->wire(RTLIL::escape_id(id_name)); - log_assert(wire); - wire->set_string_attribute(ID(wiretype), type_range->GetTypeName()); - - MapIter mj; - char *k, *v; - FOREACH_MAP_ITEM(type_range->GetEnumIdMap(), mj, &k, &v) { - IdString key = stringf("\\enum_value_%s", v); - wire->set_string_attribute(key, k); - } - } - pool<Instance*, hash_ptr_ops> sva_asserts; pool<Instance*, hash_ptr_ops> sva_assumes; pool<Instance*, hash_ptr_ops> sva_covers; @@ -1223,7 +1265,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se int numchunks = int(inst->OutputSize()) / memory->width; int chunksbits = ceil_log2(numchunks); - if ((numchunks * memory->width) != int(inst->OutputSize()) || (numchunks & (numchunks - 1)) != 0) + if ((numchunks * memory->width) != int(inst->OutputSize())) log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name()); for (int i = 0; i < numchunks; i++) @@ -1231,6 +1273,11 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)}; RTLIL::SigSpec data = operatorOutput(inst).extract(i * memory->width, memory->width); + if ((numchunks & (numchunks - 1)) != 0) { + addr = module->Mul(NEW_ID, operatorInput1(inst), RTLIL::Const(numchunks)); + addr = module->Add(NEW_ID, addr, RTLIL::Const(i)); + } + RTLIL::Cell *cell = module->addCell(numchunks == 1 ? inst_name : RTLIL::IdString(stringf("%s_%d", inst_name.c_str(), i)), ID($memrd)); cell->parameters[ID::MEMID] = memory->name.str(); @@ -1253,7 +1300,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se int numchunks = int(inst->Input2Size()) / memory->width; int chunksbits = ceil_log2(numchunks); - if ((numchunks * memory->width) != int(inst->Input2Size()) || (numchunks & (numchunks - 1)) != 0) + if ((numchunks * memory->width) != int(inst->Input2Size())) log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetOutput()->Name()); for (int i = 0; i < numchunks; i++) @@ -1261,6 +1308,11 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)}; RTLIL::SigSpec data = operatorInput2(inst).extract(i * memory->width, memory->width); + if ((numchunks & (numchunks - 1)) != 0) { + addr = module->Mul(NEW_ID, operatorInput1(inst), RTLIL::Const(numchunks)); + addr = module->Add(NEW_ID, addr, RTLIL::Const(i)); + } + RTLIL::Cell *cell = module->addCell(numchunks == 1 ? inst_name : RTLIL::IdString(stringf("%s_%d", inst_name.c_str(), i)), ID($memwr)); cell->parameters[ID::MEMID] = memory->name.str(); 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/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index 6879e0943..26abe49b5 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -48,7 +48,7 @@ static void error_on_dpi_function(AST::AstNode *node) error_on_dpi_function(child); } -static void add_package_types(std::map<std::string, AST::AstNode *> &user_types, std::vector<AST::AstNode *> &package_list) +static void add_package_types(dict<std::string, AST::AstNode *> &user_types, std::vector<AST::AstNode *> &package_list) { // prime the parser's user type lookup table with the package qualified names // of typedefed names in the packages seen so far. diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index 444cc7297..aa7881038 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -50,7 +50,7 @@ namespace VERILOG_FRONTEND extern std::vector<UserTypeMap *> user_type_stack; // names of package typedef'ed types - extern std::map<std::string, AST::AstNode*> pkg_user_types; + extern dict<std::string, AST::AstNode*> pkg_user_types; // state of `default_nettype extern bool default_nettype_wire; diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 4a5aba79e..f250d7685 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -50,12 +50,12 @@ using namespace VERILOG_FRONTEND; YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { int port_counter; - std::map<std::string, int> port_stubs; - std::map<std::string, AstNode*> *attr_list, default_attr_list; - std::stack<std::map<std::string, AstNode*> *> attr_list_stack; - std::map<std::string, AstNode*> *albuf; + dict<std::string, int> port_stubs; + dict<IdString, AstNode*> *attr_list, default_attr_list; + std::stack<dict<IdString, AstNode*> *> attr_list_stack; + dict<IdString, AstNode*> *albuf; std::vector<UserTypeMap*> user_type_stack; - std::map<std::string, AstNode*> pkg_user_types; + dict<std::string, AstNode*> pkg_user_types; std::vector<AstNode*> ast_stack; struct AstNode *astbuf1, *astbuf2, *astbuf3; struct AstNode *current_function_or_task; @@ -87,7 +87,7 @@ YOSYS_NAMESPACE_END int frontend_verilog_yylex(YYSTYPE *yylval_param, YYLTYPE *yyloc_param); -static void append_attr(AstNode *ast, std::map<std::string, AstNode*> *al) +static void append_attr(AstNode *ast, dict<IdString, AstNode*> *al) { for (auto &it : *al) { if (ast->attributes.count(it.first) > 0) @@ -97,7 +97,7 @@ static void append_attr(AstNode *ast, std::map<std::string, AstNode*> *al) delete al; } -static void append_attr_clone(AstNode *ast, std::map<std::string, AstNode*> *al) +static void append_attr_clone(AstNode *ast, dict<IdString, AstNode*> *al) { for (auto &it : *al) { if (ast->attributes.count(it.first) > 0) @@ -106,7 +106,7 @@ static void append_attr_clone(AstNode *ast, std::map<std::string, AstNode*> *al) } } -static void free_attr(std::map<std::string, AstNode*> *al) +static void free_attr(dict<IdString, AstNode*> *al) { for (auto &it : *al) delete it.second; @@ -192,7 +192,7 @@ static void addRange(AstNode *parent, int msb = 31, int lsb = 0, bool isSigned = %union { std::string *string; struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast; - std::map<std::string, YOSYS_NAMESPACE_PREFIX AST::AstNode*> *al; + YOSYS_NAMESPACE_PREFIX dict<YOSYS_NAMESPACE_PREFIX RTLIL::IdString, YOSYS_NAMESPACE_PREFIX AST::AstNode*> *al; struct specify_target *specify_target_ptr; struct specify_triple *specify_triple_ptr; struct specify_rise_fall *specify_rise_fall_ptr; @@ -289,7 +289,7 @@ attr: { if (attr_list != nullptr) attr_list_stack.push(attr_list); - attr_list = new std::map<std::string, AstNode*>; + attr_list = new dict<IdString, AstNode*>; for (auto &it : default_attr_list) (*attr_list)[it.first] = it.second->clone(); } attr_opt { @@ -311,7 +311,7 @@ defattr: DEFATTR_BEGIN { if (attr_list != nullptr) attr_list_stack.push(attr_list); - attr_list = new std::map<std::string, AstNode*>; + attr_list = new dict<IdString, AstNode*>; for (auto &it : default_attr_list) delete it.second; default_attr_list.clear(); @@ -645,13 +645,13 @@ non_opt_range: } | '[' expr TOK_POS_INDEXED expr ']' { $$ = new AstNode(AST_RANGE); - AstNode *expr = new AstNode(AST_CONCAT, $2); + AstNode *expr = new AstNode(AST_SELFSZ, $2); $$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, expr->clone(), $4), AstNode::mkconst_int(1, true))); $$->children.push_back(new AstNode(AST_ADD, expr, AstNode::mkconst_int(0, true))); } | '[' expr TOK_NEG_INDEXED expr ']' { $$ = new AstNode(AST_RANGE); - AstNode *expr = new AstNode(AST_CONCAT, $2); + AstNode *expr = new AstNode(AST_SELFSZ, $2); $$->children.push_back(new AstNode(AST_ADD, expr, AstNode::mkconst_int(0, true))); $$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, expr->clone(), AstNode::mkconst_int(1, true)), $4)); } | @@ -853,7 +853,19 @@ task_func_port: } if (astbuf2 && astbuf2->children.size() != 2) frontend_verilog_yyerror("task/function argument range must be of the form: [<expr>:<expr>], [<expr>+:<expr>], or [<expr>-:<expr>]"); - } wire_name | wire_name; + } wire_name | + { + if (!astbuf1) { + if (!sv_mode) + frontend_verilog_yyerror("task/function argument direction missing"); + albuf = new dict<IdString, AstNode*>; + astbuf1 = new AstNode(AST_WIRE); + current_wire_rand = false; + current_wire_const = false; + astbuf1->is_input = true; + astbuf2 = NULL; + } + } wire_name; task_func_body: task_func_body behavioral_stmt | @@ -885,6 +897,7 @@ specify_item: cell->str = stringf("$specify$%d", autoidx++); cell->children.push_back(new AstNode(AST_CELLTYPE)); cell->children.back()->str = target->dat ? "$specify3" : "$specify2"; + SET_AST_NODE_LOC(cell, en_expr ? @1 : @2, @10); char oper_polarity = 0; char oper_type = oper->at(0); @@ -973,6 +986,7 @@ specify_item: cell->str = stringf("$specify$%d", autoidx++); cell->children.push_back(new AstNode(AST_CELLTYPE)); cell->children.back()->str = "$specrule"; + SET_AST_NODE_LOC(cell, @1, @14); cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_str(*$1))); cell->children.back()->str = "\\TYPE"; @@ -1099,8 +1113,8 @@ specify_rise_fall: $$->fall = *$4; delete $2; delete $4; - delete $6; - log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + delete $6; + log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); } | '(' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ')' { $$ = new specify_rise_fall; @@ -1108,11 +1122,11 @@ specify_rise_fall: $$->fall = *$4; delete $2; delete $4; - delete $6; - delete $8; - delete $10; - delete $12; - log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + delete $6; + delete $8; + delete $10; + delete $12; + log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); } | '(' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ')' { $$ = new specify_rise_fall; @@ -1120,17 +1134,17 @@ specify_rise_fall: $$->fall = *$4; delete $2; delete $4; - delete $6; - delete $8; - delete $10; - delete $12; - delete $14; - delete $16; - delete $18; - delete $20; - delete $22; - delete $24; - log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + delete $6; + delete $8; + delete $10; + delete $12; + delete $14; + delete $16; + delete $18; + delete $20; + delete $22; + delete $24; + log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); } specify_triple: @@ -1388,7 +1402,7 @@ enum_type: TOK_ENUM { delete astbuf1; astbuf1 = tnode; tnode->type = AST_WIRE; - tnode->attributes["\\enum_type"] = AstNode::mkconst_str(astbuf2->str); + tnode->attributes[ID::enum_type] = AstNode::mkconst_str(astbuf2->str); // drop constant but keep any range delete tnode->children[0]; tnode->children.erase(tnode->children.begin()); } @@ -1747,7 +1761,9 @@ single_prim: /* no name */ { astbuf2 = astbuf1->clone(); ast_stack.back()->children.push_back(astbuf2); - } '(' cell_port_list ')'; + } '(' cell_port_list ')' { + SET_AST_NODE_LOC(astbuf2, @1, @$); + } cell_parameter_list_opt: '#' '(' cell_parameter_list ')' | /* empty */; @@ -2341,7 +2357,7 @@ unique_case_attr: case_attr: attr unique_case_attr { - if ($2) (*$1)["\\parallel_case"] = AstNode::mkconst_int(1, false); + if ($2) (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false); $$ = $1; }; @@ -2533,7 +2549,12 @@ gen_stmt: ast_stack.back()->children.push_back(node); ast_stack.push_back(node); ast_stack.back()->children.push_back($3); - } gen_stmt_block opt_gen_else { + AstNode *block = new AstNode(AST_GENBLOCK); + ast_stack.back()->children.push_back(block); + ast_stack.push_back(block); + } gen_stmt_or_null { + ast_stack.pop_back(); + } opt_gen_else { SET_AST_NODE_LOC(ast_stack.back(), @1, @7); ast_stack.pop_back(); } | diff --git a/kernel/constids.inc b/kernel/constids.inc index 68a5782fd..6b40a5908 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) @@ -73,6 +74,8 @@ X(EN) X(EN_DST) X(EN_POLARITY) X(EN_SRC) +X(enum_base_type) +X(enum_type) X(equiv_merged) X(equiv_region) X(extract_order) @@ -122,6 +125,7 @@ X(nomem2init) X(nomem2reg) X(nomeminit) X(nosync) +X(nowrshmsk) X(O) X(OFFSET) X(onehot) @@ -195,10 +199,12 @@ X(U) X(unique) X(unused_bits) X(V) +X(via_celltype) 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/log.cc b/kernel/log.cc index d84a4381e..a21ba480a 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -354,6 +354,9 @@ static void logv_error_with_prefix(const char *prefix, if (check_expected_logs) log_check_expected(); + + YS_DEBUGTRAP_IF_DEBUGGING; + #ifdef EMSCRIPTEN log_files = backup_log_files; throw 0; @@ -673,7 +676,7 @@ void log_check_expected() } if (item.second.current_count != item.second.expected_count) { log_warn_regexes.clear(); - log_error("Expected warning pattern '%s' found %d time(s), instead of %d time(s) !\n", + log_error("Expected warning pattern '%s' found %d time(s), instead of %d time(s) !\n", item.second.pattern.c_str(), item.second.current_count, item.second.expected_count); } } @@ -700,7 +703,7 @@ void log_check_expected() _exit(0); #else _Exit(0); - #endif + #endif } else { display_error_log_msg = false; log_warn_regexes.clear(); diff --git a/kernel/log.h b/kernel/log.h index 5478482ac..dee5d44d7 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -50,9 +50,12 @@ std::regex_constants::egrep) #endif -#ifndef _WIN32 +#if defined(_WIN32) +# include <intrin.h> +#else # include <sys/time.h> # include <sys/resource.h> +# include <signal.h> #endif #if defined(_MSC_VER) @@ -69,6 +72,41 @@ YOSYS_NAMESPACE_BEGIN #define S__LINE__sub1(x) S__LINE__sub2(x) #define S__LINE__ S__LINE__sub1(__LINE__) +// YS_DEBUGTRAP is a macro that is functionally equivalent to a breakpoint +// if the platform provides such functionality, and does nothing otherwise. +// If no debugger is attached, it starts a just-in-time debugger if available, +// and crashes the process otherwise. +#if defined(_WIN32) +# define YS_DEBUGTRAP __debugbreak() +#else +# ifndef __has_builtin +// __has_builtin is a GCC/Clang extension; on a different compiler (or old enough GCC/Clang) +// that does not have it, using __has_builtin(...) is a syntax error. +# define __has_builtin(x) 0 +# endif +# if __has_builtin(__builtin_debugtrap) +# define YS_DEBUGTRAP __builtin_debugtrap() +# elif defined(__unix__) +# define YS_DEBUGTRAP raise(SIGTRAP) +# else +# define YS_DEBUGTRAP do {} while(0) +# endif +#endif + +// YS_DEBUGTRAP_IF_DEBUGGING is a macro that is functionally equivalent to a breakpoint +// if a debugger is attached, and does nothing otherwise. +#if defined(_WIN32) +# define YS_DEBUGTRAP_IF_DEBUGGING do { if (IsDebuggerPresent()) DebugBreak(); } while(0) +#elif defined(__unix__) +// There is no reliable (or portable) *nix equivalent of IsDebuggerPresent(). However, +// debuggers will stop when SIGTRAP is raised, even if the action is set to ignore. +# define YS_DEBUGTRAP_IF_DEBUGGING do { \ + sighandler_t old = signal(SIGTRAP, SIG_IGN); raise(SIGTRAP); signal(SIGTRAP, old); \ + } while(0) +#else +# define YS_DEBUGTRAP_IF_DEBUGGING do {} while(0) +#endif + struct log_cmd_error_exception { }; extern std::vector<FILE*> log_files; 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/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..c922faf26 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -155,6 +155,16 @@ extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *p # define YS_NORETURN #endif +#if __cplusplus >= 201703L +# define YS_FALLTHROUGH [[fallthrough]]; +#elif defined(__clang__) +# define YS_FALLTHROUGH [[clang::fallthrough]]; +#elif defined(__GNUC__) +# define YS_FALLTHROUGH [[gnu::fallthrough]]; +#else +# define YS_FALLTHROUGH +#endif + YOSYS_NAMESPACE_BEGIN // Note: All headers included in hashlib.h must be included @@ -264,7 +274,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/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_clean.cc b/passes/opt/opt_clean.cc index 6271376f1..f7de02164 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -412,7 +412,7 @@ bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos return !del_wires_queue.empty(); } -bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) +bool rmunused_module_init(RTLIL::Module *module, bool verbose) { bool did_something = false; CellTypes fftypes; @@ -445,9 +445,6 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) for (auto wire : module->wires()) { - if (!purge_mode && wire->name[0] == '\\') - continue; - if (wire->attributes.count(ID::init) == 0) continue; @@ -464,11 +461,22 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) if (wire_bit == mapped_wire_bit) goto next_wire; - if (qbits.count(sigmap(SigBit(wire, i))) == 0) - goto next_wire; + if (mapped_wire_bit.wire) { + if (qbits.count(mapped_wire_bit) == 0) + goto next_wire; - if (qbits.at(sigmap(SigBit(wire, i))) != init[i]) - goto next_wire; + if (qbits.at(mapped_wire_bit) != init[i]) + goto next_wire; + } + else { + if (mapped_wire_bit == State::Sx || mapped_wire_bit == State::Sz) + goto next_wire; + + if (mapped_wire_bit != init[i]) { + log_warning("Initial value conflict for %s resolving to %s but with init %s.\n", log_signal(wire_bit), log_signal(mapped_wire_bit), log_signal(init[i])); + goto next_wire; + } + } } if (verbose) @@ -512,7 +520,7 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool rmunused_module_cells(module, verbose); while (rmunused_module_signals(module, purge_mode, verbose)) { } - if (rminit && rmunused_module_init(module, purge_mode, verbose)) + if (rminit && rmunused_module_init(module, verbose)) while (rmunused_module_signals(module, purge_mode, verbose)) { } } @@ -611,8 +619,7 @@ struct CleanPass : public Pass { } break; } - if (argidx < args.size()) - extra_args(args, argidx, design); + extra_args(args, argidx, design); keep_cache.reset(design); @@ -627,7 +634,7 @@ struct CleanPass : public Pass { for (auto module : design->selected_whole_modules()) { if (module->has_processes()) continue; - rmunused_module(module, purge_mode, ys_debug(), false); + rmunused_module(module, purge_mode, ys_debug(), true); } log_suppressed(); diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index b484b9776..63811c1a1 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -765,25 +765,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; @@ -799,6 +811,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; @@ -808,16 +821,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); @@ -827,8 +844,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/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/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 bad91a224..0bf547921 100644 --- a/passes/techmap/abc9_exe.cc +++ b/passes/techmap/abc9_exe.cc @@ -420,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/passes/tests/test_autotb.cc b/passes/tests/test_autotb.cc index 42e8a61ea..19f21493d 100644 --- a/passes/tests/test_autotb.cc +++ b/passes/tests/test_autotb.cc @@ -81,6 +81,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter, int s f << stringf("integer i;\n"); f << stringf("integer file;\n\n"); + f << stringf("reg [1023:0] filename;\n\n"); f << stringf("reg [31:0] xorshift128_x = 123456789;\n"); f << stringf("reg [31:0] xorshift128_y = 362436069;\n"); @@ -305,9 +306,15 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter, int s } f << stringf("initial begin\n"); - f << stringf("\t// $dumpfile(\"testbench.vcd\");\n"); - f << stringf("\t// $dumpvars(0, testbench);\n"); - f << stringf("\tfile = $fopen(`outfile);\n"); + f << stringf("\tif ($value$plusargs(\"VCD=%%s\", filename)) begin\n"); + f << stringf("\t\t$dumpfile(filename);\n"); + f << stringf("\t\t$dumpvars(0, testbench);\n"); + f << stringf("\tend\n"); + f << stringf("\tif ($value$plusargs(\"OUT=%%s\", filename)) begin\n"); + f << stringf("\t\tfile = $fopen(filename);\n"); + f << stringf("\tend else begin\n"); + f << stringf("\t\tfile = $fopen(`outfile);\n"); + f << stringf("\tend\n"); for (auto module : design->modules()) if (!module->get_bool_attribute(ID::gentb_skip)) f << stringf("\t%s;\n", idy(module->name.str(), "test").c_str()); diff --git a/techlibs/common/cmp2lcu.v b/techlibs/common/cmp2lcu.v index b6f4aeed6..e42f346d1 100644 --- a/techlibs/common/cmp2lcu.v +++ b/techlibs/common/cmp2lcu.v @@ -108,8 +108,12 @@ generate // Generate if any comparisons call for it wire [LCU_WIDTH-1:0] G_ = {G[LCU_WIDTH-1:1], G[0] | GG}; end - $__CMP2LCU #(.AB_WIDTH(AB_WIDTH-1), .AB_SIGNED(1'b0), .LCU_WIDTH(LCU_WIDTH), .BUDGET(BUDGET-COST), .CI(CI)) - _TECHMAP_REPLACE_ (.A(A[AB_WIDTH-2:0]), .B(B[AB_WIDTH-2:0]), .P(P_), .G(G_), .Y(Y)); + if (AB_WIDTH == 1) + $__CMP2LCU #(.AB_WIDTH(AB_WIDTH-1), .AB_SIGNED(1'b0), .LCU_WIDTH(LCU_WIDTH), .BUDGET(BUDGET-COST), .CI(CI)) + _TECHMAP_REPLACE_ (.A(), .B(), .P(P_), .G(G_), .Y(Y)); + else + $__CMP2LCU #(.AB_WIDTH(AB_WIDTH-1), .AB_SIGNED(1'b0), .LCU_WIDTH(LCU_WIDTH), .BUDGET(BUDGET-COST), .CI(CI)) + _TECHMAP_REPLACE_ (.A(A[AB_WIDTH-2:0]), .B(B[AB_WIDTH-2:0]), .P(P_), .G(G_), .Y(Y)); end end endgenerate diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v index ecf4d5dc5..225cff449 100644 --- a/techlibs/common/techmap.v +++ b/techlibs/common/techmap.v @@ -285,13 +285,32 @@ module _90_alu (A, B, CI, BI, X, Y, CO); input CI, BI; output [Y_WIDTH-1:0] CO; - wire [Y_WIDTH-1:0] A_buf, B_buf; - \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); - \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); - - wire [Y_WIDTH-1:0] AA = A_buf; + wire [Y_WIDTH-1:0] AA, BB; wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; + if (A_WIDTH == 0) begin + wire [Y_WIDTH-1:0] B_buf; + \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + + assign AA = {Y_WIDTH{1'b0}}; + assign BB = BI ? ~B_buf : B_buf; + end + else if (B_WIDTH == 0) begin + wire [Y_WIDTH-1:0] A_buf; + \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); + + assign AA = A_buf; + assign BB = {Y_WIDTH{BI ? 1'b0 : 1'b1}}; + end + else begin + wire [Y_WIDTH-1:0] A_buf, B_buf; + \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); + \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + + assign AA = A_buf; + assign BB = BI ? ~B_buf : B_buf; + end + \$lcu #(.WIDTH(Y_WIDTH)) lcu (.P(X), .G(AA & BB), .CI(CI), .CO(CO)); assign X = AA ^ BB; 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/cells_bb.v b/techlibs/ecp5/cells_bb.v index ae124e7a3..756f05366 100644 --- a/techlibs/ecp5/cells_bb.v +++ b/techlibs/ecp5/cells_bb.v @@ -652,6 +652,10 @@ module DCUA( parameter CH1_PROTOCOL = "8B10B"; parameter CH0_CDR_MAX_RATE = "2.5"; parameter CH1_CDR_MAX_RATE = "2.5"; + parameter CH0_TXDEPRE = "DISABLED"; + parameter CH1_TXDEPRE = "DISABLED"; + parameter CH0_TXDEPOST = "DISABLED"; + parameter CH1_TXDEPOST = "DISABLED"; endmodule (* blackbox *) diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index ab740ea0d..b9b236a0c 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -30,6 +30,11 @@ struct SynthEcp5Pass : public ScriptPass { SynthEcp5Pass() : ScriptPass("synth_ecp5", "synthesis for ECP5 FPGAs") { } + void on_register() YS_OVERRIDE + { + RTLIL::constpad["synth_ecp5.abc9.W"] = "300"; + } + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -324,6 +329,14 @@ struct SynthEcp5Pass : public ScriptPass if (abc9) { run("read_verilog -icells -lib -specify +/abc9_model.v +/ecp5/abc9_model.v"); + std::string abc9_opts; + if (nowidelut) + abc9_opts += " -maxlut 4"; + std::string k = "synth_ecp5.abc9.W"; + if (active_design && active_design->scratchpad.count(k)) + abc9_opts += stringf(" -W %s", active_design->scratchpad_get_string(k).c_str()); + else + abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k).c_str()); if (nowidelut) run("abc9 -maxlut 4 -W 200"); else 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/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v index 6a0e3031e..5d107989d 100644 --- a/techlibs/ice40/cells_sim.v +++ b/techlibs/ice40/cells_sim.v @@ -1908,7 +1908,7 @@ module ICESTORM_LC ( o_reg <= SR_pd ? SET_NORESET : lut_o; reg o_reg_async = 1'b0; - always @(posedge polarized_clk, posedge SR) + always @(posedge polarized_clk, posedge SR_pd) if (SR_pd) o_reg_async <= SET_NORESET; else if (CEN_pu) diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 9724b7dd5..6e05ab0b2 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -29,6 +29,13 @@ struct SynthIce40Pass : public ScriptPass { SynthIce40Pass() : ScriptPass("synth_ice40", "synthesis for iCE40 FPGAs") { } + void on_register() YS_OVERRIDE + { + RTLIL::constpad["synth_ice40.abc9.hx.W"] = "250"; + RTLIL::constpad["synth_ice40.abc9.lp.W"] = "400"; + RTLIL::constpad["synth_ice40.abc9.u.W"] = "750"; + } + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -218,10 +225,10 @@ struct SynthIce40Pass : public ScriptPass device_opt = args[++argidx]; continue; } - if (args[argidx] == "-flowmap") { - flowmap = true; - continue; - } + if (args[argidx] == "-flowmap") { + flowmap = true; + continue; + } break; } extra_args(args, argidx, design); @@ -233,13 +240,12 @@ struct SynthIce40Pass : public ScriptPass if (abc9 && retime) log_cmd_error("-retime option not currently compatible with -abc9!\n"); - - if (abc9 && noabc) - log_cmd_error("-abc9 is incompatible with -noabc!\n"); - if (abc9 && flowmap) - log_cmd_error("-abc9 is incompatible with -flowmap!\n"); - if (flowmap && noabc) - log_cmd_error("-flowmap is incompatible with -noabc!\n"); + if (abc9 && noabc) + log_cmd_error("-abc9 is incompatible with -noabc!\n"); + if (abc9 && flowmap) + log_cmd_error("-abc9 is incompatible with -flowmap!\n"); + if (flowmap && noabc) + log_cmd_error("-flowmap is incompatible with -noabc!\n"); log_header(design, "Executing SYNTH_ICE40 pass.\n"); log_push(); @@ -365,22 +371,23 @@ struct SynthIce40Pass : public ScriptPass run("techmap -map +/ice40/latches_map.v"); if (noabc || flowmap || help_mode) { run("simplemap", " (if -noabc or -flowmap)"); - if (noabc || help_mode) - run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)"); - if (flowmap || help_mode) - run("flowmap -maxlut 4", "(only if -flowmap)"); + if (noabc || help_mode) + run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)"); + if (flowmap || help_mode) + run("flowmap -maxlut 4", "(only if -flowmap)"); } if (!noabc) { if (abc9) { run("read_verilog " + define + " -icells -lib -specify +/abc9_model.v +/ice40/abc9_model.v"); - int wire_delay; - if (device_opt == "lp") - wire_delay = 400; - else if (device_opt == "u") - wire_delay = 750; - else - wire_delay = 250; - run(stringf("abc9 -W %d", wire_delay)); + std::string abc9_opts; + std::string k = "synth_ice40.abc9.W"; + if (active_design && active_design->scratchpad.count(k)) + abc9_opts += stringf(" -W %s", active_design->scratchpad_get_string(k).c_str()); + else { + k = stringf("synth_ice40.abc9.%s.W", device_opt.c_str()); + abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k).c_str()); + } + run("abc9 " + abc9_opts); } else run("abc -dress -lut 4", "(skip if -noabc)"); diff --git a/techlibs/intel_alm/Makefile.inc b/techlibs/intel_alm/Makefile.inc index 66204c8fc..ed6c4510b 100644 --- a/techlibs/intel_alm/Makefile.inc +++ b/techlibs/intel_alm/Makefile.inc @@ -7,17 +7,14 @@ $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/al $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/arith_alm_map.v)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/dff_map.v)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/dff_sim.v)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/mem_sim.v)) # RAM bramtypes := m10k m20k $(foreach bramtype, $(bramtypes), $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_$(bramtype).txt))) $(foreach bramtype, $(bramtypes), $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_$(bramtype)_map.v))) $(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/bram_m10k_map.v b/techlibs/intel_alm/common/bram_m10k_map.v index e5566010d..061463c3e 100644 --- a/techlibs/intel_alm/common/bram_m10k_map.v +++ b/techlibs/intel_alm/common/bram_m10k_map.v @@ -28,4 +28,4 @@ altsyncram #( .clock1(CLK1)
);
-endmodule +endmodule
diff --git a/techlibs/intel_alm/common/lutram_mlab.txt b/techlibs/intel_alm/common/lutram_mlab.txt index 1d6174d85..3cc69399d 100644 --- a/techlibs/intel_alm/common/lutram_mlab.txt +++ b/techlibs/intel_alm/common/lutram_mlab.txt @@ -1,20 +1,18 @@ -bram __MISTRAL_MLAB
- init 0 # TODO: Re-enable when I figure out how LUTRAM init works
- abits 5
- dbits 16 @D32x16
- dbits 18 @D32x18
- dbits 20 @D32x20
- groups 2
- ports 1 1
- wrmode 1 0
- # read enable
- enable 1 0
- transp 1 0
- clocks 1 2
- clkpol 1 1
-endbram
-
-match __MISTRAL_MLAB
- min efficiency 5
- make_outreg
-endmatch
+bram MISTRAL_MLAB + init 0 # TODO: Re-enable when Yosys remembers the original filename. + abits 5 + dbits 1 + groups 2 + ports 1 1 + wrmode 1 0 + # write enable + enable 1 0 + transp 0 0 + clocks 1 0 + clkpol 1 1 +endbram + +match MISTRAL_MLAB + min efficiency 5 + make_outreg +endmatch
\ No newline at end of file diff --git a/techlibs/intel_alm/common/lutram_mlab_map.v b/techlibs/intel_alm/common/lutram_mlab_map.v deleted file mode 100644 index 3a9c8590e..000000000 --- a/techlibs/intel_alm/common/lutram_mlab_map.v +++ /dev/null @@ -1,29 +0,0 @@ -module __MISTRAL_MLAB(CLK1, CLK2, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA);
-
-parameter CFG_ABITS = 5;
-parameter CFG_DBITS = 20;
-
-input CLK1, CLK2;
-input [CFG_ABITS-1:0] A1ADDR, B1ADDR;
-input [CFG_DBITS-1:0] A1DATA;
-input A1EN;
-output [CFG_DBITS-1:0] B1DATA;
-
-altsyncram #(
- .operation_mode("dual_port"),
- .ram_block_type("mlab"),
- .widthad_a(CFG_ABITS),
- .width_a(CFG_DBITS),
- .widthad_b(CFG_ABITS),
- .width_b(CFG_DBITS),
-) _TECHMAP_REPLACE_ (
- .address_a(A1ADDR),
- .data_a(A1DATA),
- .wren_a(A1EN),
- .address_b(B1ADDR),
- .q_b(B1DATA),
- .clock0(CLK1),
- .clock1(CLK1),
-);
-
-endmodule
diff --git a/techlibs/intel_alm/common/megafunction_bb.v b/techlibs/intel_alm/common/megafunction_bb.v index 21ba73a09..c749fa70b 100644 --- a/techlibs/intel_alm/common/megafunction_bb.v +++ b/techlibs/intel_alm/common/megafunction_bb.v @@ -106,3 +106,26 @@ input aclr1; output eccstatus; endmodule + +(* blackbox *) +module cyclonev_mlab_cell(portaaddr, portadatain, portbaddr, portbdataout, ena0, clk0, clk1); + +parameter logical_ram_name = ""; +parameter logical_ram_depth = 32; +parameter logical_ram_width = 20; +parameter mixed_port_feed_through_mode = "new"; +parameter first_bit_number = 0; +parameter first_address = 0; +parameter last_address = 31; +parameter address_width = 5; +parameter data_width = 1; +parameter byte_enable_mask_width = 1; +parameter port_b_data_out_clock = "NONE"; +parameter [639:0] mem_init0 = 640'b0; + +input [address_width-1:0] portaaddr, portbaddr; +input [data_width-1:0] portadatain; +output [data_width-1:0] portbdataout; +input ena0, clk0, clk1; + +endmodule diff --git a/techlibs/intel_alm/common/mem_sim.v b/techlibs/intel_alm/common/mem_sim.v new file mode 100644 index 000000000..ae79b19a4 --- /dev/null +++ b/techlibs/intel_alm/common/mem_sim.v @@ -0,0 +1,60 @@ +// The MLAB +// -------- +// In addition to Logic Array Blocks (LABs) that contain ten Adaptive Logic +// Modules (ALMs, see alm_sim.v), the Cyclone V/10GX also contain +// Memory/Logic Array Blocks (MLABs) that can act as either ten ALMs, or utilise +// the memory the ALM uses to store the look-up table data for general usage, +// producing a 32 address by 20-bit block of memory. MLABs are spread out +// around the chip, so they can be placed near where they are needed, rather than +// being comparatively limited in placement for a deep but narrow memory such as +// the M10K memory block. +// +// MLABs are used mainly for shallow but wide memories, such as CPU register +// files (which have perhaps 32 registers that are comparatively wide (16/32-bit)) +// or shift registers (by using the output of the Nth bit as input for the N+1th +// bit). +// +// Oddly, instead of providing a block 32 address by 20-bit cell, Quartus asks +// synthesis tools to build MLABs out of 32 address by 1-bit cells, and tries +// to put these cells in the same MLAB during cell placement. Because of this +// a MISTRAL_MLAB cell represents one of these 32 address by 1-bit cells, and +// 20 of them represent a physical MLAB. +// +// How the MLAB works +// ------------------ +// MLABs are poorly documented, so the following information is based mainly +// on the simulation model and my knowledge of how memories like these work. +// Additionally, note that the ports of MISTRAL_MLAB are the ones auto-generated +// by the Yosys `memory_bram` pass, and it doesn't make sense to me to use +// `techmap` just for the sake of renaming the cell ports. +// +// The MLAB can be initialised to any value, but unfortunately Quartus only +// allows memory initialisation from a file. Since Yosys doesn't preserve input +// file information, or write the contents of an `initial` block to a file, +// Yosys can't currently initialise the MLAB in a way Quartus will accept. +// +// The MLAB takes in data from A1DATA at the rising edge of CLK1, and if A1EN +// is high, writes it to the address in A1ADDR. A1EN can therefore be used to +// conditionally write data to the MLAB. +// +// Simultaneously, the MLAB reads data from B1ADDR, and outputs it to B1DATA, +// asynchronous to CLK1 and ignoring A1EN. If a synchronous read is needed +// then the output can be fed to embedded flops. Presently, Yosys assumes +// Quartus will pack external flops into the MLAB, but this is an assumption +// that needs testing. + +// The vendor sim model outputs 'x for a very short period (a few +// combinational delta cycles) after each write. This has been omitted from +// the following model because it's very difficult to trigger this in practice +// as clock cycles will be much longer than any potential blip of 'x, so the +// model can be treated as always returning a defined result. +module MISTRAL_MLAB(input [4:0] A1ADDR, input A1DATA, A1EN, CLK1, input [4:0] B1ADDR, output B1DATA); + +reg [31:0] mem = 32'b0; + +always @(posedge CLK1) + if (A1EN) mem[A1ADDR] <= A1DATA; + +assign B1DATA = mem[B1ADDR]; + +endmodule diff --git a/techlibs/intel_alm/common/quartus_rename.v b/techlibs/intel_alm/common/quartus_rename.v index d9961c174..c40a4e02d 100644 --- a/techlibs/intel_alm/common/quartus_rename.v +++ b/techlibs/intel_alm/common/quartus_rename.v @@ -1,3 +1,12 @@ +`ifdef cyclonev +`define LCELL cyclonev_lcell_comb +`define MLAB cyclonev_mlab_cell +`endif +`ifdef cyclone10gx +`define LCELL cyclone10gx_lcell_comb +`define MLAB cyclone10gx_mlab_cell +`endif + module __MISTRAL_VCC(output Q); MISTRAL_ALUT2 #(.LUT(4'b1111)) _TECHMAP_REPLACE_ (.A(1'b1), .B(1'b1), .Q(Q)); @@ -17,3 +26,96 @@ 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 + + +module MISTRAL_MLAB(input [4:0] A1ADDR, input A1DATA, A1EN, CLK1, input [4:0] B1ADDR, output B1DATA); + +// Here we get to an unfortunate situation. The cell has a mem_init0 parameter, +// which takes in a hexadecimal string that could be used to initialise RAM. +// In the vendor simulation models, this appears to work fine, but Quartus, +// either intentionally or not, forgets about this parameter and initialises the +// RAM to zero. +// +// Because of this, RAM initialisation is presently disabled, but the source +// used to generate mem_init0 is kept (commented out) in case this gets fixed +// or an undocumented way to get Quartus to initialise from mem_init0 is found. + +`MLAB #( + .logical_ram_name("MISTRAL_MLAB"), + .logical_ram_depth(32), + .logical_ram_width(1), + .mixed_port_feed_through_mode("Dont Care"), + .first_bit_number(0), + .first_address(0), + .last_address(31), + .address_width(5), + .data_width(1), + .byte_enable_mask_width(1), + .port_b_data_out_clock("NONE"), + // .mem_init0($sformatf("%08x", INIT)) +) _TECHMAP_REPLACE_ ( + .portaaddr(A1ADDR), + .portadatain(A1DATA), + .portbaddr(B1ADDR), + .portbdataout(B1DATA), + .ena0(A1EN), + .clk0(CLK1) +); + +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 5d4c78d74..bf9e746b8 100644 --- a/techlibs/intel_alm/synth_intel_alm.cc +++ b/techlibs/intel_alm/synth_intel_alm.cc @@ -164,6 +164,7 @@ struct SynthIntelALMPass : public ScriptPass { run(stringf("read_verilog -sv -lib +/intel/%s/cells_sim.v", family_opt.c_str())); run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/alm_sim.v", family_opt.c_str())); run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/dff_sim.v", family_opt.c_str())); + run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/mem_sim.v", family_opt.c_str())); // Misc and common cells run("read_verilog -lib +/intel/common/altpll_bb.v"); @@ -190,7 +191,6 @@ struct SynthIntelALMPass : public ScriptPass { if (!nolutram && check_label("map_lutram", "(skip if -nolutram)")) { run("memory_bram -rules +/intel_alm/common/lutram_mlab.txt", "(for Cyclone V / Cyclone 10GX)"); - run("techmap -map +/intel_alm/common/lutram_mlab_map.v", "(for Cyclone V / Cyclone 10GX)"); } if (check_label("map_ffram")) { @@ -235,8 +235,7 @@ struct SynthIntelALMPass : public ScriptPass { // to constant driver cells, which Quartus accepts. run("hilomap -singleton -hicell __MISTRAL_VCC Q -locell __MISTRAL_GND Q"); // Rename from Yosys-internal MISTRAL_* cells to Quartus cells. - run("techmap -map +/intel_alm/common/quartus_rename.v"); - run(stringf("techmap -map +/intel_alm/%s/quartus_rename.v", family_opt.c_str())); + run(stringf("techmap -D %s -map +/intel_alm/common/quartus_rename.v", family_opt.c_str())); } } diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 1c190d37e..229ffcb3d 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -619,11 +619,13 @@ struct SynthXilinxPass : public ScriptPass run("techmap " + techmap_args); run("read_verilog -icells -lib -specify +/abc9_model.v +/xilinx/abc9_model.v"); std::string abc9_opts; - auto k = stringf("synth_xilinx.abc9.%s.W", family.c_str()); - if (active_design->scratchpad.count(k)) + std::string k = "synth_xilinx.abc9.W"; + if (active_design && active_design->scratchpad.count(k)) abc9_opts += stringf(" -W %s", active_design->scratchpad_get_string(k).c_str()); - else + else { + k = stringf("synth_xilinx.abc9.%s.W", family.c_str()); abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k, RTLIL::constpad.at("synth_xilinx.abc9.xc7.W")).c_str()); + } if (nowidelut) abc9_opts += stringf(" -maxlut %d", lut_size); if (dff_mode) 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/intel_alm/lutram.ys b/tests/arch/intel_alm/lutram.ys new file mode 100644 index 000000000..6f997b67b --- /dev/null +++ b/tests/arch/intel_alm/lutram.ys @@ -0,0 +1,20 @@ +read_verilog ../common/lutram.v +hierarchy -top lutram_1w1r +proc +memory -nomap +equiv_opt -run :prove -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v -map +/intel_alm/common/mem_sim.v synth_intel_alm -family cyclonev -nobram +memory +opt -full + +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter + +design -load postopt +cd lutram_1w1r +select -assert-count 16 t:MISTRAL_MLAB +select -assert-count 1 t:MISTRAL_NOT +select -assert-count 2 t:MISTRAL_ALUT2 +select -assert-count 8 t:MISTRAL_ALUT3 +select -assert-count 17 t:MISTRAL_FF +select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_FF t:MISTRAL_MLAB %% t:* %D + 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/opt/opt_clean_init.ys b/tests/opt/opt_clean_init.ys new file mode 100644 index 000000000..0d567608d --- /dev/null +++ b/tests/opt/opt_clean_init.ys @@ -0,0 +1,13 @@ +logger -expect warning "Initial value conflict for \\y resolving to 1'0 but with init 1'1" 1 +logger -expect-no-warnings +read_verilog <<EOT +module top; +(* init=1'b0 *) wire w = 1'b0; +(* init=1'bx *) wire x = 1'b0; +(* init=1'b1 *) wire y = 1'b0; +(* init=1'b0 *) wire z = 1'bx; +endmodule +EOT +clean +select -assert-count 1 a:init +select -assert-count 1 w:y a:init %i diff --git a/tests/simple/partsel.v b/tests/simple/partsel.v index 83493fcb0..5e9730d6b 100644 --- a/tests/simple/partsel.v +++ b/tests/simple/partsel.v @@ -64,3 +64,49 @@ endmodule module partsel_test003(input [2:0] a, b, input [31:0] din, output [3:0] dout); assign dout = din[a*b +: 2]; endmodule + +module partsel_test004 ( + input [31:0] din, + input signed [4:0] n, + output reg [31:0] dout +); + always @(*) begin + dout = 0; + dout[n+1 +: 2] = din[n +: 2]; + end +endmodule + + +module partsel_test005 ( + input [31:0] din, + input signed [4:0] n, + output reg [31:0] dout +); + always @(*) begin + dout = 0; + dout[n+1] = din[n]; + end +endmodule + +module partsel_test006 ( + input [31:-32] din, + input signed [4:0] n, + output reg [31:-32] dout +); + always @(*) begin + dout = 0; + dout[n+1 +: 2] = din[n +: 2]; + end +endmodule + + +module partsel_test007 ( + input [31:-32] din, + input signed [4:0] n, + output reg [31:-32] dout +); + always @(*) begin + dout = 0; + dout[n+1] = din[n]; + end +endmodule 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 diff --git a/tests/various/gen_if_null.v b/tests/various/gen_if_null.v new file mode 100644 index 000000000..a12ac6288 --- /dev/null +++ b/tests/various/gen_if_null.v @@ -0,0 +1,13 @@ +module test(x, y, z); + localparam OFF = 0; + generate + if (OFF) ; + else input x; + if (!OFF) input y; + else ; + if (OFF) ; + else ; + if (OFF) ; + input z; + endgenerate +endmodule diff --git a/tests/various/gen_if_null.ys b/tests/various/gen_if_null.ys new file mode 100644 index 000000000..31dfc444b --- /dev/null +++ b/tests/various/gen_if_null.ys @@ -0,0 +1,4 @@ +read_verilog gen_if_null.v +select -assert-count 1 test/x +select -assert-count 1 test/y +select -assert-count 1 test/z diff --git a/tests/various/primitives.ys b/tests/various/primitives.ys new file mode 100644 index 000000000..9307ca50f --- /dev/null +++ b/tests/various/primitives.ys @@ -0,0 +1,16 @@ +read_verilog <<EOT +module top(input a, b, output [5:0] y); +and (y[0], a, b); +nand (y[1], a, b); +or (y[2], a, b); +nor (y[3], a, b); +xor (y[4], a, b); +xnor (y[5], a, b); +endmodule +EOT +select -assert-count 1 t:$and a:src=<<EOT:2.4-2.17 %i +select -assert-count 1 t:$and a:src=<<EOT:3.5-3.18 %i +select -assert-count 1 t:$or a:src=<<EOT:4.3-4.16 %i +select -assert-count 1 t:$or a:src=<<EOT:5.4-5.17 %i +select -assert-count 1 t:$xor a:src=<<EOT:6.4-6.17 %i +select -assert-count 1 t:$xor a:src=<<EOT:7.5-7.18 %i diff --git a/tests/various/specify.ys b/tests/various/specify.ys index 9d55b8eb5..d7260d524 100644 --- a/tests/various/specify.ys +++ b/tests/various/specify.ys @@ -4,10 +4,16 @@ cd test select t:$specify2 -assert-count 0 select t:$specify3 -assert-count 1 select t:$specrule -assert-count 2 +select t:$specify3 a:src=specify.v:10.3-10.49 %i -assert-count 1 +select t:$specrule a:src=specify.v:11.3-11.36 %i -assert-count 1 +select t:$specrule a:src=specify.v:12.3-12.35 %i -assert-count 1 cd test2 select t:$specify2 -assert-count 2 select t:$specify3 -assert-count 0 select t:$specrule -assert-count 0 +select t:$specify2 a:src=specify.v:26.3-26.20 %i -assert-count 1 + # ^^ Note use of macro +select t:$specify2 a:src=specify.v:28.3-28.18 %i -assert-count 1 cd write_verilog specify.out design -stash gold diff --git a/tests/verilog/.gitignore b/tests/verilog/.gitignore new file mode 100644 index 000000000..b48f808a1 --- /dev/null +++ b/tests/verilog/.gitignore @@ -0,0 +1,3 @@ +/*.log +/*.out +/run-test.mk diff --git a/tests/verilog/bug2042-sv.ys b/tests/verilog/bug2042-sv.ys new file mode 100644 index 000000000..e815d7fc5 --- /dev/null +++ b/tests/verilog/bug2042-sv.ys @@ -0,0 +1,59 @@ +read_verilog -sv <<EOT +module Task_Test_Top +( +input a, +output b +); + + task SomeTaskName(a); + b = ~a; + endtask + + always @* + SomeTaskName(a); + + assert property (b == ~a); + +endmodule +EOT +proc +sat -verify -prove-asserts + + +design -reset +read_verilog -sv <<EOT +module Task_Test_Top +( +input a, +output b, c +); + + task SomeTaskName(x, output y, z); + y = ~x; + z = x; + endtask + + always @* + SomeTaskName(a, b, c); + + assert property (b == ~a); + assert property (c == a); + +endmodule +EOT +proc +sat -verify -prove-asserts + + +design -reset +logger -expect error "syntax error, unexpected TOK_ENDTASK, expecting ';'" 1 +read_verilog -sv <<EOT +module Task_Test_Top +( +); + + task SomeTaskName(a) + endtask + +endmodule +EOT diff --git a/tests/verilog/bug2042.ys b/tests/verilog/bug2042.ys new file mode 100644 index 000000000..f9d8e2837 --- /dev/null +++ b/tests/verilog/bug2042.ys @@ -0,0 +1,11 @@ +logger -expect error "task/function argument direction missing" 1 +read_verilog <<EOT +module Task_Test_Top +( +); + + task SomeTaskName(a) + endtask + +endmodule +EOT diff --git a/tests/verilog/run-test.sh b/tests/verilog/run-test.sh new file mode 100755 index 000000000..ea56b70f0 --- /dev/null +++ b/tests/verilog/run-test.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -e +{ +echo "all::" +for x in *.ys; do + echo "all:: run-$x" + echo "run-$x:" + echo " @echo 'Running $x..'" + echo " @../../yosys -ql ${x%.ys}.log $x" +done +for s in *.sh; do + if [ "$s" != "run-test.sh" ]; then + echo "all:: run-$s" + echo "run-$s:" + echo " @echo 'Running $s..'" + echo " @bash $s" + fi +done +} > run-test.mk +exec ${MAKE:-make} -f run-test.mk diff --git a/tests/verilog/upto.ys b/tests/verilog/upto.ys new file mode 100644 index 000000000..2f3394761 --- /dev/null +++ b/tests/verilog/upto.ys @@ -0,0 +1,4 @@ +read_verilog <<EOT +module top(input [-128:-65] a); +endmodule +EOT |