diff --git a/.travis.yml b/.travis.yml index 957735f1d..4102f05fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,6 +36,7 @@ matrix: - libboost-system-dev - libboost-python-dev - libboost-filesystem-dev + - zlib1g-dev env: - MATRIX_EVAL="CONFIG=gcc && CC=gcc-4.8 && CXX=g++-4.8" @@ -64,6 +65,7 @@ matrix: - libboost-system-dev - libboost-python-dev - libboost-filesystem-dev + - zlib1g-dev env: - MATRIX_EVAL="CONFIG=gcc && CC=gcc-6 && CXX=g++-6" @@ -92,6 +94,7 @@ matrix: - libboost-system-dev - libboost-python-dev - libboost-filesystem-dev + - zlib1g-dev env: - MATRIX_EVAL="CONFIG=gcc && CC=gcc-7 && CXX=g++-7" @@ -121,6 +124,7 @@ matrix: - libboost-system-dev - libboost-python-dev - libboost-filesystem-dev + - zlib1g-dev env: - MATRIX_EVAL="CONFIG=clang && CC=clang-3.8 && CXX=clang++-3.8" @@ -149,6 +153,7 @@ matrix: - libboost-system-dev - libboost-python-dev - libboost-filesystem-dev + - zlib1g-dev env: - MATRIX_EVAL="CONFIG=clang && CC=clang-5.0 && CXX=clang++-5.0" diff --git a/CHANGELOG b/CHANGELOG index 44d83c1bf..638c36121 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,7 +14,11 @@ Yosys 0.9 .. Yosys 0.9-dev - Added "synth -abc9" (experimental) - Added "script -scriptwire - "synth_xilinx" to now infer wide multiplexers (-widemux to enable) - + - Added automatic gzip decompression for frontends + - Added $_NMUX_ cell type + - Added automatic gzip compression (based on filename extension) for backends + - Improve attribute and parameter encoding in JSON to avoid ambiguities between + bit vectors and strings containing [01xz]* Yosys 0.8 .. Yosys 0.8-dev -------------------------- diff --git a/Makefile b/Makefile index d33f27b63..a697e9844 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,7 @@ ENABLE_VERIFIC := 0 ENABLE_COVER := 1 ENABLE_LIBYOSYS := 0 ENABLE_PROTOBUF := 0 +ENABLE_ZLIB := 1 # python wrappers ENABLE_PYOSYS := 0 @@ -122,7 +123,7 @@ OBJS = kernel/version_$(GIT_REV).o # is just a symlink to your actual ABC working directory, as 'make mrproper' # will remove the 'abc' directory and you do not want to accidentally # delete your work on ABC.. -ABCREV = 62487de +ABCREV = 5776ad0 ABCPULL = 1 ABCURL ?= https://github.com/berkeley-abc/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 @@ -260,7 +261,8 @@ CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s LDLIBS := $(filter-out -lrt,$(LDLIBS)) ABCMKARGS += ARCHFLAGS="-DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w" -ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=1 CC="/usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc" +# TODO: Try to solve pthread linking issue in more appropriate way +ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" LDFLAGS="-Wl,--allow-multiple-definition" ABC_USE_NO_READLINE=1 CC="/usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc" EXE = .exe else ifeq ($(CONFIG),msys2) @@ -384,6 +386,12 @@ ifeq ($(ENABLE_GLOB),1) CXXFLAGS += -DYOSYS_ENABLE_GLOB endif +ifeq ($(ENABLE_ZLIB),1) +CXXFLAGS += -DYOSYS_ENABLE_ZLIB +LDLIBS += -lz +endif + + ifeq ($(ENABLE_TCL),1) TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')") ifeq ($(OS), FreeBSD) @@ -394,7 +402,7 @@ endif ifeq ($(CONFIG),mxe) CXXFLAGS += -DYOSYS_ENABLE_TCL -LDLIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 -lz +LDLIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 -lz -luserenv else CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags tcl || echo -I$(TCL_INCLUDE)) -DYOSYS_ENABLE_TCL ifeq ($(OS), FreeBSD) @@ -862,9 +870,11 @@ config-mxe: clean config-msys2: clean echo 'CONFIG := msys2' > Makefile.conf + echo 'ENABLE_PLUGINS := 0' >> Makefile.conf config-msys2-64: clean echo 'CONFIG := msys2-64' > Makefile.conf + echo 'ENABLE_PLUGINS := 0' >> Makefile.conf config-cygwin: clean echo 'CONFIG := cygwin' > Makefile.conf diff --git a/README.md b/README.md index 9e221be38..d9989eb29 100644 --- a/README.md +++ b/README.md @@ -67,13 +67,13 @@ prerequisites for building yosys: $ sudo apt-get install build-essential clang bison flex \ libreadline-dev gawk tcl-dev libffi-dev git \ graphviz xdot pkg-config python3 libboost-system-dev \ - libboost-python-dev libboost-filesystem-dev + libboost-python-dev libboost-filesystem-dev zlib1g-dev Similarily, on Mac OS X MacPorts or Homebrew can be used to install dependencies: $ brew tap Homebrew/bundle && brew bundle $ sudo port install bison flex readline gawk libffi \ - git graphviz pkgconfig python36 boost + git graphviz pkgconfig python36 boost zlib On FreeBSD use the following command to install all prerequisites: @@ -85,7 +85,7 @@ On FreeBSD system use gmake instead of make. To run tests use: For Cygwin use the following command to install all prerequisites, or select these additional packages: - setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel,boost-build + setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel,boost-build,zlib-devel There are also pre-compiled Yosys binary packages for Ubuntu and Win32 as well as a source distribution for Visual Studio. Visit the Yosys download page for @@ -130,18 +130,15 @@ commands and ``help `` to print details on the specified command: yosys> help help -reading the design using the Verilog frontend: +reading and elaborating the design using the Verilog frontend: - yosys> read_verilog tests/simple/fiedler-cooley.v + yosys> read -sv tests/simple/fiedler-cooley.v + yosys> hierarchy -top up3down5 writing the design to the console in Yosys's internal format: yosys> write_ilang -elaborate design hierarchy: - - yosys> hierarchy - convert processes (``always`` blocks) to netlist elements and perform some simple optimizations: @@ -163,51 +160,26 @@ write design netlist to a new Verilog file: yosys> write_verilog synth.v -a similar synthesis can be performed using yosys command line options only: - - $ ./yosys -o synth.v -p hierarchy -p proc -p opt \ - -p techmap -p opt tests/simple/fiedler-cooley.v - or using a simple synthesis script: $ cat synth.ys - read_verilog tests/simple/fiedler-cooley.v - hierarchy; proc; opt; techmap; opt + read -sv tests/simple/fiedler-cooley.v + hierarchy -top up3down5 + proc; opt; techmap; opt write_verilog synth.v $ ./yosys synth.ys -It is also possible to only have the synthesis commands but not the read/write -commands in the synthesis script: - - $ cat synth.ys - hierarchy; proc; opt; techmap; opt - - $ ./yosys -o synth.v tests/simple/fiedler-cooley.v synth.ys - -The following very basic synthesis script should work well with all designs: - - # check design hierarchy - hierarchy - - # translate processes (always blocks) - proc; opt - - # detect and optimize FSM encodings - fsm; opt - - # implement memories (arrays) - memory; opt - - # convert to gate logic - techmap; opt - If ABC is enabled in the Yosys build configuration and a cell library is given in the liberty file ``mycells.lib``, the following synthesis script will synthesize for the given cell library: + # read design + read -sv tests/simple/fiedler-cooley.v + hierarchy -top up3down5 + # the high-level stuff - hierarchy; proc; fsm; opt; memory; opt + proc; fsm; opt; memory; opt # mapping to internal cell library techmap; opt @@ -222,7 +194,8 @@ synthesize for the given cell library: clean If you do not have a liberty file but want to test this synthesis script, -you can use the file ``examples/cmos/cmos_cells.lib`` from the yosys sources. +you can use the file ``examples/cmos/cmos_cells.lib`` from the yosys sources +as simple example. Liberty file downloads for and information about free and open ASIC standard cell libraries can be found here: @@ -231,20 +204,18 @@ cell libraries can be found here: - http://www.vlsitechnology.org/synopsys/vsclib013.lib The command ``synth`` provides a good default synthesis script (see -``help synth``). If possible a synthesis script should borrow from ``synth``. -For example: +``help synth``): - # the high-level stuff - hierarchy - synth -run coarse + read -sv tests/simple/fiedler-cooley.v + synth -top up3down5 - # mapping to internal cells - techmap; opt -fast + # mapping to target cells dfflibmap -liberty mycells.lib abc -liberty mycells.lib clean -Yosys is under construction. A more detailed documentation will follow. +The command ``prep`` provides a good default word-level synthesis script, as +used in SMT-based formal verification. Unsupported Verilog-2005 Features diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 69f63486c..a3a753912 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -53,7 +53,7 @@ PRIVATE_NAMESPACE_BEGIN inline int32_t to_big_endian(int32_t i32) { #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - return __builtin_bswap32(i32); + return bswap32(i32); #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ return i32; #else @@ -610,15 +610,15 @@ struct XAigerWriter std::stringstream h_buffer; auto write_h_buffer = std::bind(write_buffer, std::ref(h_buffer), std::placeholders::_1); write_h_buffer(1); - log_debug("ciNum = %zu\n", input_bits.size() + ci_bits.size()); + log_debug("ciNum = %d\n", GetSize(input_bits) + GetSize(ci_bits)); write_h_buffer(input_bits.size() + ci_bits.size()); - log_debug("coNum = %zu\n", output_bits.size() + co_bits.size()); + log_debug("coNum = %d\n", GetSize(output_bits) + GetSize(co_bits)); write_h_buffer(output_bits.size() + co_bits.size()); - log_debug("piNum = %zu\n", input_bits.size()); + log_debug("piNum = %d\n", GetSize(input_bits)); write_h_buffer(input_bits.size()); - log_debug("poNum = %zu\n", output_bits.size()); + log_debug("poNum = %d\n", GetSize(output_bits)); write_h_buffer(output_bits.size()); - log_debug("boxNum = %zu\n", box_list.size()); + log_debug("boxNum = %d\n", GetSize(box_list)); write_h_buffer(box_list.size()); RTLIL::Module *holes_module = nullptr; @@ -772,7 +772,7 @@ struct XAigerWriter if (output_bits.count(b)) { int o = ordered_outputs.at(b); - output_lines[o] += stringf("output %lu %d %s\n", o - co_bits.size(), i, log_id(wire)); + output_lines[o] += stringf("output %d %d %s\n", o - GetSize(co_bits), i, log_id(wire)); continue; } diff --git a/backends/blif/blif.cc b/backends/blif/blif.cc index a1761b662..f32b0f533 100644 --- a/backends/blif/blif.cc +++ b/backends/blif/blif.cc @@ -327,6 +327,13 @@ struct BlifDumper goto internal_cell; } + if (!config->icells_mode && cell->type == "$_NMUX_") { + f << stringf(".names %s %s %s %s\n0-0 1\n-01 1\n", + cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), + cstr(cell->getPort("\\S")), cstr(cell->getPort("\\Y"))); + goto internal_cell; + } + if (!config->icells_mode && cell->type == "$_FF_") { f << stringf(".latch %s %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")), cstr_init(cell->getPort("\\Q"))); diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index a507b120b..7bacce2af 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -496,7 +496,7 @@ struct BtorWorker goto okay; } - if (cell->type.in("$mux", "$_MUX_")) + if (cell->type.in("$mux", "$_MUX_", "$_NMUX_")) { SigSpec sig_a = sigmap(cell->getPort("\\A")); SigSpec sig_b = sigmap(cell->getPort("\\B")); @@ -511,6 +511,12 @@ struct BtorWorker int nid = next_nid++; btorf("%d ite %d %d %d %d\n", nid, sid, nid_s, nid_b, nid_a); + if (cell->type == "$_NMUX_") { + int tmp = nid; + nid = next_nid++; + btorf("%d not %d %d\n", nid, sid, tmp); + } + add_nid_sig(nid, sig_y); goto okay; } diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index b7a798b85..ad4b37353 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -381,10 +381,10 @@ struct FirrtlWorker // Given an expression for a shift amount, and a maximum width, // generate the FIRRTL expression for equivalent dynamic shift taking into account FIRRTL shift semantics. - std::string gen_dshl(const string b_expr, const int b_padded_width) + std::string gen_dshl(const string b_expr, const int b_width) { string result = b_expr; - if (b_padded_width >= FIRRTL_MAX_DSH_WIDTH_ERROR) { + if (b_width >= FIRRTL_MAX_DSH_WIDTH_ERROR) { int max_shift_width_bits = FIRRTL_MAX_DSH_WIDTH_ERROR - 1; string max_shift_string = stringf("UInt<%d>(%d)", max_shift_width_bits, (1<cells()) { - bool extract_y_bits = false; // Assume no extraction of final bits will be required. + static Const ndef(0, 0); + // Is this cell is a module instance? if (cell->type[0] != '$') { process_instance(cell, wire_exprs); continue; } + // Not a module instance. Set up cell properties + bool extract_y_bits = false; // Assume no extraction of final bits will be required. + int a_width = cell->parameters.at("\\A_WIDTH", ndef).as_int(); // The width of "A" + int b_width = cell->parameters.at("\\B_WIDTH", ndef).as_int(); // The width of "A" + const int y_width = cell->parameters.at("\\Y_WIDTH", ndef).as_int(); // The width of the result + const bool a_signed = cell->parameters.at("\\A_SIGNED", ndef).as_bool(); + const bool b_signed = cell->parameters.at("\\B_SIGNED", ndef).as_bool(); + bool firrtl_is_signed = a_signed; // The result is signed (subsequent code may change this). + int firrtl_width = 0; + string primop; + bool always_uint = false; + string y_id = make_id(cell->name); + if (cell->type.in("$not", "$logic_not", "$neg", "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_bool", "$reduce_xnor")) { - string y_id = make_id(cell->name); - bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool(); - int y_width = cell->parameters.at("\\Y_WIDTH").as_int(); string a_expr = make_expr(cell->getPort("\\A")); wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); - if (cell->parameters.at("\\A_SIGNED").as_bool()) { + if (a_signed) { a_expr = "asSInt(" + a_expr + ")"; } @@ -446,12 +457,13 @@ struct FirrtlWorker a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); } - string primop; - bool always_uint = false; + // Assume the FIRRTL width is a single bit. + firrtl_width = 1; if (cell->type == "$not") primop = "not"; else if (cell->type == "$neg") { primop = "neg"; - is_signed = true; // Result of "neg" is signed (an SInt). + firrtl_is_signed = true; // Result of "neg" is signed (an SInt). + firrtl_width = a_width; } else if (cell->type == "$logic_not") { primop = "eq"; a_expr = stringf("%s, UInt(0)", a_expr.c_str()); @@ -466,14 +478,12 @@ struct FirrtlWorker else if (cell->type == "$reduce_bool") { primop = "neq"; // Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand. - bool a_signed = cell->parameters.at("\\A_SIGNED").as_bool(); - int a_width = cell->parameters.at("\\A_WIDTH").as_int(); a_expr = stringf("%s, %cInt<%d>(0)", a_expr.c_str(), a_signed ? 'S' : 'U', a_width); } string expr = stringf("%s(%s)", primop.c_str(), a_expr.c_str()); - if ((is_signed && !always_uint)) + if ((firrtl_is_signed && !always_uint)) expr = stringf("asUInt(%s)", expr.c_str()); cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str())); @@ -481,81 +491,121 @@ struct FirrtlWorker continue; } - if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$and", "$or", "$eq", "$eqx", + if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$xnor", "$and", "$or", "$eq", "$eqx", "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl", - "$logic_and", "$logic_or")) + "$logic_and", "$logic_or", "$pow")) { - string y_id = make_id(cell->name); - bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool(); - int y_width = cell->parameters.at("\\Y_WIDTH").as_int(); string a_expr = make_expr(cell->getPort("\\A")); string b_expr = make_expr(cell->getPort("\\B")); - int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int(); wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); - if (cell->parameters.at("\\A_SIGNED").as_bool()) { + if (a_signed) { a_expr = "asSInt(" + a_expr + ")"; - } - // Shift amount is always unsigned, and needn't be padded to result width. - if (!cell->type.in("$shr", "$sshr", "$shl", "$sshl")) { - if (cell->parameters.at("\\B_SIGNED").as_bool()) { - b_expr = "asSInt(" + b_expr + ")"; + // Expand the "A" operand to the result width + if (a_width < y_width) { + a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); + a_width = y_width; } - if (b_padded_width < y_width) { - auto b_sig = cell->getPort("\\B"); - b_padded_width = y_width; + } + // Shift amount is always unsigned, and needn't be padded to result width, + // otherwise, we need to cast the b_expr appropriately + if (b_signed && !cell->type.in("$shr", "$sshr", "$shl", "$sshl", "$pow")) { + b_expr = "asSInt(" + b_expr + ")"; + // Expand the "B" operand to the result width + if (b_width < y_width) { + b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width); + b_width = y_width; } } + // For the arithmetic ops, expand operand widths to result widths befor performing the operation. + // This corresponds (according to iverilog) to what verilog compilers implement. + if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$xnor", "$and", "$or")) + { + if (a_width < y_width) { + a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); + a_width = y_width; + } + if (b_width < y_width) { + b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width); + b_width = y_width; + } + } + // Assume the FIRRTL width is the width of "A" + firrtl_width = a_width; auto a_sig = cell->getPort("\\A"); - if (cell->parameters.at("\\A_SIGNED").as_bool() & (cell->type == "$shr")) { - a_expr = "asUInt(" + a_expr + ")"; + if (cell->type == "$add") { + primop = "add"; + firrtl_is_signed = a_signed | b_signed; + firrtl_width = max(a_width, b_width); + } else if (cell->type == "$sub") { + primop = "sub"; + firrtl_is_signed = true; + int a_widthInc = (!a_signed && b_signed) ? 2 : (a_signed && !b_signed) ? 1 : 0; + int b_widthInc = (a_signed && !b_signed) ? 2 : (!a_signed && b_signed) ? 1 : 0; + firrtl_width = max(a_width + a_widthInc, b_width + b_widthInc); + } else if (cell->type == "$mul") { + primop = "mul"; + firrtl_is_signed = a_signed | b_signed; + firrtl_width = a_width + b_width; + } else if (cell->type == "$div") { + primop = "div"; + firrtl_is_signed = a_signed | b_signed; + firrtl_width = a_width; + } else if (cell->type == "$mod") { + primop = "rem"; + firrtl_width = min(a_width, b_width); + } else if (cell->type == "$and") { + primop = "and"; + always_uint = true; + firrtl_width = max(a_width, b_width); } - - string primop; - bool always_uint = false; - if (cell->type == "$add") primop = "add"; - else if (cell->type == "$sub") primop = "sub"; - else if (cell->type == "$mul") primop = "mul"; - else if (cell->type == "$div") primop = "div"; - else if (cell->type == "$mod") primop = "rem"; - else if (cell->type == "$and") { - primop = "and"; - always_uint = true; - } else if (cell->type == "$or" ) { - primop = "or"; - always_uint = true; - } + primop = "or"; + always_uint = true; + firrtl_width = max(a_width, b_width); + } else if (cell->type == "$xor") { - primop = "xor"; - always_uint = true; - } + primop = "xor"; + always_uint = true; + firrtl_width = max(a_width, b_width); + } + else if (cell->type == "$xnor") { + primop = "xnor"; + always_uint = true; + firrtl_width = max(a_width, b_width); + } else if ((cell->type == "$eq") | (cell->type == "$eqx")) { - primop = "eq"; - always_uint = true; - } + primop = "eq"; + always_uint = true; + firrtl_width = 1; + } else if ((cell->type == "$ne") | (cell->type == "$nex")) { - primop = "neq"; - always_uint = true; - } + primop = "neq"; + always_uint = true; + firrtl_width = 1; + } else if (cell->type == "$gt") { - primop = "gt"; - always_uint = true; - } + primop = "gt"; + always_uint = true; + firrtl_width = 1; + } else if (cell->type == "$ge") { - primop = "geq"; - always_uint = true; - } + primop = "geq"; + always_uint = true; + firrtl_width = 1; + } else if (cell->type == "$lt") { - primop = "lt"; - always_uint = true; - } + primop = "lt"; + always_uint = true; + firrtl_width = 1; + } else if (cell->type == "$le") { - primop = "leq"; - always_uint = true; - } + primop = "leq"; + always_uint = true; + firrtl_width = 1; + } else if ((cell->type == "$shl") | (cell->type == "$sshl")) { // FIRRTL will widen the result (y) by the amount of the shift. // We'll need to offset this by extracting the un-widened portion as Verilog would do. @@ -564,11 +614,14 @@ struct FirrtlWorker auto b_sig = cell->getPort("\\B"); if (b_sig.is_fully_const()) { primop = "shl"; - b_expr = std::to_string(b_sig.as_int()); + int shift_amount = b_sig.as_int(); + b_expr = std::to_string(shift_amount); + firrtl_width = a_width + shift_amount; } else { primop = "dshl"; // Convert from FIRRTL left shift semantics. - b_expr = gen_dshl(b_expr, b_padded_width); + b_expr = gen_dshl(b_expr, b_width); + firrtl_width = a_width + (1 << b_width) - 1; } } else if ((cell->type == "$shr") | (cell->type == "$sshr")) { @@ -578,36 +631,86 @@ struct FirrtlWorker auto b_sig = cell->getPort("\\B"); if (b_sig.is_fully_const()) { primop = "shr"; - b_expr = std::to_string(b_sig.as_int()); + int shift_amount = b_sig.as_int(); + b_expr = std::to_string(shift_amount); + firrtl_width = max(1, a_width - shift_amount); } else { primop = "dshr"; + firrtl_width = a_width; + } + // We'll need to do some special fixups if the source (and thus result) is signed. + if (firrtl_is_signed) { + // If this is a "logical" shift right, pretend the source is unsigned. + if (cell->type == "$shr") { + a_expr = "asUInt(" + a_expr + ")"; + } } } else if ((cell->type == "$logic_and")) { - primop = "and"; - a_expr = "neq(" + a_expr + ", UInt(0))"; - b_expr = "neq(" + b_expr + ", UInt(0))"; - always_uint = true; - } + primop = "and"; + a_expr = "neq(" + a_expr + ", UInt(0))"; + b_expr = "neq(" + b_expr + ", UInt(0))"; + always_uint = true; + firrtl_width = 1; + } else if ((cell->type == "$logic_or")) { - primop = "or"; - a_expr = "neq(" + a_expr + ", UInt(0))"; - b_expr = "neq(" + b_expr + ", UInt(0))"; - always_uint = true; - } + primop = "or"; + a_expr = "neq(" + a_expr + ", UInt(0))"; + b_expr = "neq(" + b_expr + ", UInt(0))"; + always_uint = true; + firrtl_width = 1; + } + else if ((cell->type == "$pow")) { + if (a_sig.is_fully_const() && a_sig.as_int() == 2) { + // We'll convert this to a shift. To simplify things, change the a_expr to "1" + // so we can use b_expr directly as a shift amount. + // Only support 2 ** N (i.e., shift left) + // FIRRTL will widen the result (y) by the amount of the shift. + // We'll need to offset this by extracting the un-widened portion as Verilog would do. + a_expr = firrtl_is_signed ? "SInt(1)" : "UInt(1)"; + extract_y_bits = true; + // Is the shift amount constant? + auto b_sig = cell->getPort("\\B"); + if (b_sig.is_fully_const()) { + primop = "shl"; + int shiftAmount = b_sig.as_int(); + if (shiftAmount < 0) { + log_error("Negative power exponent - %d: %s.%s\n", shiftAmount, log_id(module), log_id(cell)); + } + b_expr = std::to_string(shiftAmount); + firrtl_width = a_width + shiftAmount; + } else { + primop = "dshl"; + // Convert from FIRRTL left shift semantics. + b_expr = gen_dshl(b_expr, b_width); + firrtl_width = a_width + (1 << b_width) - 1; + } + } else { + log_error("Non power 2: %s.%s\n", log_id(module), log_id(cell)); + } + } if (!cell->parameters.at("\\B_SIGNED").as_bool()) { b_expr = "asUInt(" + b_expr + ")"; } - string expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str()); - - // Deal with FIRRTL's "shift widens" semantics - if (extract_y_bits) { - expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1); + string expr; + // Deal with $xnor == ~^ (not xor) + if (primop == "xnor") { + expr = stringf("not(xor(%s, %s))", a_expr.c_str(), b_expr.c_str()); + } else { + expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str()); } - if ((is_signed && !always_uint) || cell->type.in("$sub")) + // Deal with FIRRTL's "shift widens" semantics, or the need to widen the FIRRTL result. + // If the operation is signed, the FIRRTL width will be 1 one bit larger. + if (extract_y_bits) { + expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1); + } else if (firrtl_is_signed && (firrtl_width + 1) < y_width) { + expr = stringf("pad(%s, %d)", expr.c_str(), y_width); + } + + if ((firrtl_is_signed && !always_uint)) expr = stringf("asUInt(%s)", expr.c_str()); cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str())); @@ -618,7 +721,6 @@ struct FirrtlWorker if (cell->type.in("$mux")) { - string y_id = make_id(cell->name); int width = cell->parameters.at("\\WIDTH").as_int(); string a_expr = make_expr(cell->getPort("\\A")); string b_expr = make_expr(cell->getPort("\\B")); @@ -762,15 +864,14 @@ struct FirrtlWorker if (clkpol == false) log_error("Negative edge clock on FF %s.%s.\n", log_id(module), log_id(cell)); - string q_id = make_id(cell->name); int width = cell->parameters.at("\\WIDTH").as_int(); string expr = make_expr(cell->getPort("\\D")); string clk_expr = "asClock(" + make_expr(cell->getPort("\\CLK")) + ")"; - wire_decls.push_back(stringf(" reg %s: UInt<%d>, %s\n", q_id.c_str(), width, clk_expr.c_str())); + wire_decls.push_back(stringf(" reg %s: UInt<%d>, %s\n", y_id.c_str(), width, clk_expr.c_str())); - cell_exprs.push_back(stringf(" %s <= %s\n", q_id.c_str(), expr.c_str())); - register_reverse_wire_map(q_id, cell->getPort("\\Q")); + cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str())); + register_reverse_wire_map(y_id, cell->getPort("\\Q")); continue; } @@ -785,8 +886,6 @@ struct FirrtlWorker // assign y = a[b +: y_width]; // We'll extract the correct bits as part of the primop. - string y_id = make_id(cell->name); - int y_width = cell->parameters.at("\\Y_WIDTH").as_int(); string a_expr = make_expr(cell->getPort("\\A")); // Get the initial bit selector string b_expr = make_expr(cell->getPort("\\B")); @@ -808,18 +907,15 @@ struct FirrtlWorker // assign y = a >> b; // where b may be negative - string y_id = make_id(cell->name); - int y_width = cell->parameters.at("\\Y_WIDTH").as_int(); string a_expr = make_expr(cell->getPort("\\A")); string b_expr = make_expr(cell->getPort("\\B")); auto b_string = b_expr.c_str(); - int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int(); string expr; wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); if (cell->getParam("\\B_SIGNED").as_bool()) { // We generate a left or right shift based on the sign of b. - std::string dshl = stringf("bits(dshl(%s, %s), 0, %d)", a_expr.c_str(), gen_dshl(b_expr, b_padded_width).c_str(), y_width); + std::string dshl = stringf("bits(dshl(%s, %s), 0, %d)", a_expr.c_str(), gen_dshl(b_expr, b_width).c_str(), y_width); std::string dshr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string); expr = stringf("mux(%s < 0, %s, %s)", b_string, @@ -833,6 +929,20 @@ struct FirrtlWorker register_reverse_wire_map(y_id, cell->getPort("\\Y")); continue; } + if (cell->type == "$pos") { + // assign y = a; +// printCell(cell); + string a_expr = make_expr(cell->getPort("\\A")); + // Verilog appears to treat the result as signed, so if the result is wider than "A", + // we need to pad. + if (a_width < y_width) { + a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); + } + wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); + cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), a_expr.c_str())); + register_reverse_wire_map(y_id, cell->getPort("\\Y")); + continue; + } log_error("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell)); } diff --git a/backends/json/json.cc b/backends/json/json.cc index dda4dfedd..107009ee4 100644 --- a/backends/json/json.cc +++ b/backends/json/json.cc @@ -83,20 +83,43 @@ struct JsonWriter return str + " ]"; } + void write_parameter_value(const Const &value) + { + if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0) { + string str = value.decode_string(); + int state = 0; + for (char c : str) { + if (state == 0) { + if (c == '0' || c == '1' || c == 'x' || c == 'z') + state = 0; + else if (c == ' ') + state = 1; + else + state = 2; + } else if (state == 1 && c != ' ') + state = 2; + } + if (state < 2) + str += " "; + f << get_string(str); + } else + if (GetSize(value) == 32 && value.is_fully_def()) { + if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0) + f << stringf("%d", value.as_int()); + else + f << stringf("%u", value.as_int()); + } else { + f << get_string(value.as_string()); + } + } + void write_parameters(const dict ¶meters, bool for_module=false) { bool first = true; for (auto ¶m : parameters) { f << stringf("%s\n", first ? "" : ","); f << stringf(" %s%s: ", for_module ? "" : " ", get_name(param.first).c_str()); - if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0) - f << get_string(param.second.decode_string()); - else if (GetSize(param.second.bits) > 32) - f << get_string(param.second.as_string()); - else if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0) - f << stringf("%d", param.second.as_int()); - else - f << stringf("%u", param.second.as_int()); + write_parameter_value(param.second); first = false; } } @@ -342,12 +365,13 @@ struct JsonBackend : public Backend { log("Module and cell ports and nets can be single bit wide or vectors of multiple\n"); log("bits. Each individual signal bit is assigned a unique integer. The \n"); log("values referenced above are vectors of this integers. Signal bits that are\n"); - log("connected to a constant driver are denoted as string \"0\" or \"1\" instead of\n"); - log("a number.\n"); + log("connected to a constant driver are denoted as string \"0\", \"1\", \"x\", or\n"); + log("\"z\" instead of a number.\n"); log("\n"); - log("Numeric parameter and attribute values up to 32 bits are written as decimal\n"); - log("values. Numbers larger than that are written as string holding the binary\n"); - log("representation of the value.\n"); + log("Numeric 32-bit parameter and attribute values are written as decimal values.\n"); + log("Bit verctors of different sizes, or ones containing 'x' or 'z' bits, are written\n"); + log("as string holding the binary representation of the value. Strings are written\n"); + log("as strings, with an appended blank in cases of strings of the form /[01xz]* */.\n"); log("\n"); log("For example the following Verilog code:\n"); log("\n"); diff --git a/backends/simplec/simplec.cc b/backends/simplec/simplec.cc index 6f2ccbe20..54dbb84af 100644 --- a/backends/simplec/simplec.cc +++ b/backends/simplec/simplec.cc @@ -472,7 +472,7 @@ struct SimplecWorker return; } - if (cell->type == "$_MUX_") + if (cell->type.in("$_MUX_", "$_NMUX_")) { SigBit a = sigmaps.at(work->module)(cell->getPort("\\A")); SigBit b = sigmaps.at(work->module)(cell->getPort("\\B")); @@ -484,7 +484,9 @@ struct SimplecWorker string s_expr = s.wire ? util_get_bit(work->prefix + cid(s.wire->name), s.wire->width, s.offset) : s.data ? "1" : "0"; // casts to bool are a workaround for CBMC bug (https://github.com/diffblue/cbmc/issues/933) - string expr = stringf("%s ? (bool)%s : (bool)%s", s_expr.c_str(), b_expr.c_str(), a_expr.c_str()); + string expr = stringf("%s ? %s(bool)%s : %s(bool)%s", s_expr.c_str(), + cell->type == "$_NMUX_" ? "!" : "", b_expr.c_str(), + cell->type == "$_NMUX_" ? "!" : "", a_expr.c_str()); log_assert(y.wire); funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) + diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index e318a4051..ddd680782 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -510,6 +510,7 @@ struct Smt2Worker if (cell->type == "$_ANDNOT_") return export_gate(cell, "(and A (not B))"); if (cell->type == "$_ORNOT_") return export_gate(cell, "(or A (not B))"); if (cell->type == "$_MUX_") return export_gate(cell, "(ite S B A)"); + if (cell->type == "$_NMUX_") return export_gate(cell, "(not (ite S B A))"); if (cell->type == "$_AOI3_") return export_gate(cell, "(not (or (and A B) C))"); if (cell->type == "$_OAI3_") return export_gate(cell, "(not (and (or A B) C))"); if (cell->type == "$_AOI4_") return export_gate(cell, "(not (or (and A B) (and C D)))"); diff --git a/backends/smv/smv.cc b/backends/smv/smv.cc index d75456c1b..e9586fae0 100644 --- a/backends/smv/smv.cc +++ b/backends/smv/smv.cc @@ -537,6 +537,13 @@ struct SmvWorker continue; } + if (cell->type == "$_NMUX_") + { + definitions.push_back(stringf("%s := !(bool(%s) ? %s : %s);", lvalue(cell->getPort("\\Y")), + rvalue(cell->getPort("\\S")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\A")))); + continue; + } + if (cell->type == "$_AOI3_") { definitions.push_back(stringf("%s := !((%s & %s) | %s);", lvalue(cell->getPort("\\Y")), diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index e0b3a6f80..776f4eacb 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -558,6 +558,20 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) return true; } + if (cell->type == "$_NMUX_") { + f << stringf("%s" "assign ", indent.c_str()); + dump_sigspec(f, cell->getPort("\\Y")); + f << stringf(" = !("); + dump_cell_expr_port(f, cell, "S", false); + f << stringf(" ? "); + dump_attributes(f, "", cell->attributes, ' '); + dump_cell_expr_port(f, cell, "B", false); + f << stringf(" : "); + dump_cell_expr_port(f, cell, "A", false); + f << stringf(");\n"); + return true; + } + if (cell->type.in("$_AOI3_", "$_OAI3_")) { f << stringf("%s" "assign ", indent.c_str()); dump_sigspec(f, cell->getPort("\\Y")); diff --git a/examples/mimas2/README b/examples/mimas2/README new file mode 100644 index 000000000..b12875cbc --- /dev/null +++ b/examples/mimas2/README @@ -0,0 +1,8 @@ +A simple example design, based on the Numato Labs Mimas V2 board +================================================================ + +This example uses Yosys for synthesis and Xilinx ISE +for place&route and bit-stream creation. + +To synthesize: + bash run.sh diff --git a/examples/mimas2/example.ucf b/examples/mimas2/example.ucf new file mode 100644 index 000000000..4e31b74ab --- /dev/null +++ b/examples/mimas2/example.ucf @@ -0,0 +1,13 @@ +CONFIG VCCAUX = "3.3" ; + + +NET "CLK" LOC = D9 | IOSTANDARD = LVCMOS33 | PERIOD = 12MHz ; + +NET "LED[7]" LOC = P15 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; +NET "LED[6]" LOC = P16 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; +NET "LED[5]" LOC = N15 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; +NET "LED[4]" LOC = N16 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; +NET "LED[3]" LOC = U17 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; +NET "LED[2]" LOC = U18 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; +NET "LED[1]" LOC = T17 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; +NET "LED[0]" LOC = T18 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; diff --git a/examples/mimas2/example.v b/examples/mimas2/example.v new file mode 100644 index 000000000..2a9117393 --- /dev/null +++ b/examples/mimas2/example.v @@ -0,0 +1,14 @@ +module example( + input wire CLK, + output wire [7:0] LED +); + +reg [27:0] ctr; +initial ctr = 0; + +always @(posedge CLK) + ctr <= ctr + 1; + +assign LED = ctr[27:20]; + +endmodule diff --git a/examples/mimas2/run.sh b/examples/mimas2/run.sh new file mode 100644 index 000000000..aafde78ed --- /dev/null +++ b/examples/mimas2/run.sh @@ -0,0 +1,8 @@ +#!/bin/sh +set -e +yosys run_yosys.ys +edif2ngd example.edif +ngdbuild example -uc example.ucf -p xc6slx9csg324-3 +map -w example +par -w example.ncd example_par.ncd +bitgen -w example_par.ncd -g StartupClk:JTAGClk diff --git a/examples/mimas2/run_yosys.ys b/examples/mimas2/run_yosys.ys new file mode 100644 index 000000000..b3204b1ca --- /dev/null +++ b/examples/mimas2/run_yosys.ys @@ -0,0 +1,4 @@ +read_verilog example.v +synth_xilinx -top example -family xc6s +iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I +write_edif -pvector bra example.edif diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index 03c541b7c..bb97c5703 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -301,7 +301,11 @@ static uint32_t parse_xaiger_literal(std::istream &f) uint32_t l; f.read(reinterpret_cast(&l), sizeof(l)); if (f.gcount() != sizeof(l)) +#if defined(_WIN32) && defined(__MINGW32__) + log_error("Offset %I64d: unable to read literal!\n", static_cast(f.tellg())); +#else log_error("Offset %" PRId64 ": unable to read literal!\n", static_cast(f.tellg())); +#endif return from_big_endian(l); } diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index e947125bf..6fb94d80b 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -3439,19 +3439,11 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) { std::map backup_scope; std::map variables; - bool delete_temp_block = false; - AstNode *block = NULL; + AstNode *block = new AstNode(AST_BLOCK); size_t argidx = 0; for (auto child : children) { - if (child->type == AST_BLOCK) - { - log_assert(block == NULL); - block = child; - continue; - } - if (child->type == AST_WIRE) { while (child->simplify(true, false, false, 1, -1, false, true)) { } @@ -3468,13 +3460,9 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) continue; } - log_assert(block == NULL); - delete_temp_block = true; - block = new AstNode(AST_BLOCK); block->children.push_back(child->clone()); } - log_assert(block != NULL); log_assert(variables.count(str) != 0); while (!block->children.empty()) @@ -3642,8 +3630,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) log_abort(); } - if (delete_temp_block) - delete block; + delete block; for (auto &it : backup_scope) if (it.second == NULL) diff --git a/frontends/json/jsonparse.cc b/frontends/json/jsonparse.cc index f5ae8eb72..7aceffbfc 100644 --- a/frontends/json/jsonparse.cc +++ b/frontends/json/jsonparse.cc @@ -25,7 +25,7 @@ struct JsonNode { char type; // S=String, N=Number, A=Array, D=Dict string data_string; - int data_number; + int64_t data_number; vector data_array; dict data_dict; vector data_dict_keys; @@ -206,6 +206,38 @@ struct JsonNode } }; +Const json_parse_attr_param_value(JsonNode *node) +{ + Const value; + + if (node->type == 'S') { + string &s = node->data_string; + size_t cursor = s.find_first_not_of("01xz"); + if (cursor == string::npos) { + value = Const::from_string(s); + } else if (s.find_first_not_of(' ', cursor) == string::npos) { + value = Const(s.substr(0, GetSize(s)-1)); + } else { + value = Const(s); + } + } else + if (node->type == 'N') { + value = Const(node->data_number, 32); + if (node->data_number < 0) + value.flags |= RTLIL::CONST_FLAG_SIGNED; + } else + if (node->type == 'A') { + log_error("JSON attribute or parameter value is an array.\n"); + } else + if (node->type == 'D') { + log_error("JSON attribute or parameter value is a dict.\n"); + } else { + log_abort(); + } + + return value; +} + void json_parse_attr_param(dict &results, JsonNode *node) { if (node->type != 'D') @@ -214,28 +246,7 @@ void json_parse_attr_param(dict &results, JsonNode *node) for (auto it : node->data_dict) { IdString key = RTLIL::escape_id(it.first.c_str()); - JsonNode *value_node = it.second; - Const value; - - if (value_node->type == 'S') { - string &s = value_node->data_string; - if (s.find_first_not_of("01xz") == string::npos) - value = Const::from_string(s); - else - value = Const(s); - } else - if (value_node->type == 'N') { - value = Const(value_node->data_number, 32); - } else - if (value_node->type == 'A') { - log_error("JSON attribute or parameter value is an array.\n"); - } else - if (value_node->type == 'D') { - log_error("JSON attribute or parameter value is a dict.\n"); - } else { - log_abort(); - } - + Const value = json_parse_attr_param_value(it.second); results[key] = value; } } diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 2bf99e58e..06d58a44a 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -2484,7 +2484,7 @@ struct ReadPass : public Pass { args[0] = "verific"; } else { args[0] = "read_verilog"; - args.erase(args.begin()+1, args.begin()+2); + args[1] = "-defer"; } Pass::call(design, args); return; @@ -2498,6 +2498,7 @@ struct ReadPass : public Pass { if (args[1] == "-formal") args.insert(args.begin()+1, std::string()); args[1] = "-sv"; + args.insert(args.begin()+1, "-defer"); } Pass::call(design, args); return; diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 951d9c66f..57e55b1f4 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -70,6 +70,9 @@ YOSYS_NAMESPACE_END #define YY_INPUT(buf,result,max_size) \ result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size) +#undef YY_BUF_SIZE +#define YY_BUF_SIZE 65536 + %} %option yylineno diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc index 26c625f89..fbc6d045e 100644 --- a/kernel/cellaigs.cc +++ b/kernel/cellaigs.cc @@ -325,6 +325,8 @@ Aig::Aig(Cell *cell) int A = mk.inport("\\A", i); int B = mk.inport("\\B", i); int Y = mk.mux_gate(A, B, S); + if (cell->type == "$_NMUX_") + Y = mk.not_gate(Y); mk.outport(Y, "\\Y", i); } goto optimize; diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 758661c02..d2594bc46 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -193,6 +193,7 @@ struct CellTypes setup_type("$_ANDNOT_", {A, B}, {Y}, true); setup_type("$_ORNOT_", {A, B}, {Y}, true); setup_type("$_MUX_", {A, B, S}, {Y}, true); + setup_type("$_NMUX_", {A, B, S}, {Y}, true); setup_type("$_MUX4_", {A, B, C, D, S, T}, {Y}, true); setup_type("$_MUX8_", {A, B, C, D, E, F, G, H, S, T, U}, {Y}, true); setup_type("$_MUX16_", {A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V}, {Y}, true); diff --git a/kernel/consteval.h b/kernel/consteval.h index 154373a8d..f70dfa0fb 100644 --- a/kernel/consteval.h +++ b/kernel/consteval.h @@ -145,7 +145,7 @@ struct ConstEval if (cell->hasPort("\\B")) sig_b = cell->getPort("\\B"); - if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$_MUX_") + if (cell->type.in("$mux", "$pmux", "$_MUX_", "$_NMUX_")) { std::vector y_candidates; int count_maybe_set_s_bits = 0; @@ -175,7 +175,10 @@ struct ConstEval for (auto &yc : y_candidates) { if (!eval(yc, undef, cell)) return false; - y_values.push_back(yc.as_const()); + if (cell->type == "$_NMUX_") + y_values.push_back(RTLIL::const_not(yc.as_const(), Const(), false, false, GetSize(yc))); + else + y_values.push_back(yc.as_const()); } if (y_values.size() > 1) diff --git a/kernel/cost.h b/kernel/cost.h index 41a09eb63..10fa50fb3 100644 --- a/kernel/cost.h +++ b/kernel/cost.h @@ -24,62 +24,92 @@ YOSYS_NAMESPACE_BEGIN -int get_cell_cost(RTLIL::Cell *cell, dict *mod_cost_cache = nullptr); - -inline int get_cell_cost(RTLIL::IdString type, const dict ¶meters = dict(), - RTLIL::Design *design = nullptr, dict *mod_cost_cache = nullptr) +struct CellCosts { - static dict gate_cost = { - { "$_BUF_", 1 }, - { "$_NOT_", 2 }, - { "$_AND_", 4 }, - { "$_NAND_", 4 }, - { "$_OR_", 4 }, - { "$_NOR_", 4 }, - { "$_ANDNOT_", 4 }, - { "$_ORNOT_", 4 }, - { "$_XOR_", 8 }, - { "$_XNOR_", 8 }, - { "$_AOI3_", 6 }, - { "$_OAI3_", 6 }, - { "$_AOI4_", 8 }, - { "$_OAI4_", 8 }, - { "$_MUX_", 4 } - }; - - if (gate_cost.count(type)) - return gate_cost.at(type); - - if (parameters.empty() && design && design->module(type)) - { - RTLIL::Module *mod = design->module(type); - - if (mod->attributes.count("\\cost")) - return mod->attributes.at("\\cost").as_int(); - - dict local_mod_cost_cache; - if (mod_cost_cache == nullptr) - mod_cost_cache = &local_mod_cost_cache; - - if (mod_cost_cache->count(mod->name)) - return mod_cost_cache->at(mod->name); - - int module_cost = 1; - for (auto c : mod->cells()) - module_cost += get_cell_cost(c, mod_cost_cache); - - (*mod_cost_cache)[mod->name] = module_cost; - return module_cost; + static const dict& default_gate_cost() { + static const dict db = { + { "$_BUF_", 1 }, + { "$_NOT_", 2 }, + { "$_AND_", 4 }, + { "$_NAND_", 4 }, + { "$_OR_", 4 }, + { "$_NOR_", 4 }, + { "$_ANDNOT_", 4 }, + { "$_ORNOT_", 4 }, + { "$_XOR_", 5 }, + { "$_XNOR_", 5 }, + { "$_AOI3_", 6 }, + { "$_OAI3_", 6 }, + { "$_AOI4_", 7 }, + { "$_OAI4_", 7 }, + { "$_MUX_", 4 }, + { "$_NMUX_", 4 } + }; + return db; } - log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(type), GetSize(parameters)); - return 1; -} + static const dict& cmos_gate_cost() { + static const dict db = { + { "$_BUF_", 1 }, + { "$_NOT_", 2 }, + { "$_AND_", 6 }, + { "$_NAND_", 4 }, + { "$_OR_", 6 }, + { "$_NOR_", 4 }, + { "$_ANDNOT_", 6 }, + { "$_ORNOT_", 6 }, + { "$_XOR_", 12 }, + { "$_XNOR_", 12 }, + { "$_AOI3_", 6 }, + { "$_OAI3_", 6 }, + { "$_AOI4_", 8 }, + { "$_OAI4_", 8 }, + { "$_MUX_", 12 }, + { "$_NMUX_", 10 } + }; + return db; + } -inline int get_cell_cost(RTLIL::Cell *cell, dict *mod_cost_cache) -{ - return get_cell_cost(cell->type, cell->parameters, cell->module->design, mod_cost_cache); -} + dict mod_cost_cache; + const dict *gate_cost = nullptr; + Design *design = nullptr; + + int get(RTLIL::IdString type) const + { + if (gate_cost && gate_cost->count(type)) + return gate_cost->at(type); + + log_warning("Can't determine cost of %s cell.\n", log_id(type)); + return 1; + } + + int get(RTLIL::Cell *cell) + { + if (gate_cost && gate_cost->count(cell->type)) + return gate_cost->at(cell->type); + + if (design && design->module(cell->type) && cell->parameters.empty()) + { + RTLIL::Module *mod = design->module(cell->type); + + if (mod->attributes.count("\\cost")) + return mod->attributes.at("\\cost").as_int(); + + if (mod_cost_cache.count(mod->name)) + return mod_cost_cache.at(mod->name); + + int module_cost = 1; + for (auto c : mod->cells()) + module_cost += get(c); + + mod_cost_cache[mod->name] = module_cost; + return module_cost; + } + + log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(cell->type), GetSize(cell->parameters)); + return 1; + } +}; YOSYS_NAMESPACE_END diff --git a/kernel/driver.cc b/kernel/driver.cc index f273057dd..70a97c4b9 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -522,6 +522,12 @@ int main(int argc, char **argv) if (!backend_command.empty()) run_backend(output_filename, backend_command); + yosys_design->check(); + for (auto it : saved_designs) + it.second->check(); + for (auto it : pushed_designs) + it->check(); + if (!depsfile.empty()) { FILE *f = fopen(depsfile.c_str(), "wt"); diff --git a/kernel/register.cc b/kernel/register.cc index 26da96b95..e4237cac4 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -25,6 +25,65 @@ #include #include +#ifdef YOSYS_ENABLE_ZLIB +#include + +PRIVATE_NAMESPACE_BEGIN +#define GZ_BUFFER_SIZE 8192 +void decompress_gzip(const std::string &filename, std::stringstream &out) +{ + char buffer[GZ_BUFFER_SIZE]; + int bytes_read; + gzFile gzf = gzopen(filename.c_str(), "rb"); + while(!gzeof(gzf)) { + bytes_read = gzread(gzf, reinterpret_cast(buffer), GZ_BUFFER_SIZE); + out.write(buffer, bytes_read); + } + gzclose(gzf); +} + +/* +An output stream that uses a stringbuf to buffer data internally, +using zlib to write gzip-compressed data every time the stream is flushed. +*/ +class gzip_ostream : public std::ostream { +public: + gzip_ostream() + { + rdbuf(&outbuf); + } + bool open(const std::string &filename) + { + return outbuf.open(filename); + } +private: + class gzip_streambuf : public std::stringbuf { + public: + gzip_streambuf() { }; + bool open(const std::string &filename) + { + gzf = gzopen(filename.c_str(), "wb"); + return gzf != nullptr; + } + virtual int sync() override + { + gzwrite(gzf, reinterpret_cast(str().c_str()), unsigned(str().size())); + str(""); + return 0; + } + ~gzip_streambuf() + { + sync(); + gzclose(gzf); + } + private: + gzFile gzf = nullptr; + } outbuf; +}; +PRIVATE_NAMESPACE_END + +#endif + YOSYS_NAMESPACE_BEGIN #define MAX_REG_COUNT 1000 @@ -236,8 +295,6 @@ void Pass::call(RTLIL::Design *design, std::vector args) pass_register[args[0]]->post_execute(state); while (design->selection_stack.size() > orig_sel_stack_pos) design->selection_stack.pop_back(); - - design->check(); } void Pass::call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::string command) @@ -319,8 +376,10 @@ void ScriptPass::run(std::string command, std::string info) log(" %s\n", command.c_str()); else log(" %s %s\n", command.c_str(), info.c_str()); - } else + } else { Pass::call(active_design, command); + active_design->check(); + } } void ScriptPass::run_script(RTLIL::Design *design, std::string run_from, std::string run_to) @@ -436,6 +495,28 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector(magic), 3); + if (n == 3 && magic[0] == 0x1f && magic[1] == 0x8b) { + #ifdef YOSYS_ENABLE_ZLIB + log("Found gzip magic in file `%s', decompressing using zlib.\n", filename.c_str()); + if (magic[2] != 8) + log_cmd_error("gzip file `%s' uses unsupported compression type %02x\n", + filename.c_str(), unsigned(magic[2])); + delete ff; + std::stringstream *df = new std::stringstream(); + decompress_gzip(filename, *df); + f = df; + #else + log_cmd_error("File `%s' is a gzip file, but Yosys is compiled without zlib.\n", filename.c_str()); + #endif + } else { + ff->clear(); + ff->seekg(0, std::ios::beg); + } + } } if (f == NULL) log_cmd_error("Can't open input file `%s' for reading: %s\n", filename.c_str(), strerror(errno)); @@ -492,8 +573,6 @@ void Frontend::frontend_call(RTLIL::Design *design, std::istream *f, std::string args.push_back(filename); frontend_register[args[0]]->execute(args, design); } - - design->check(); } Backend::Backend(std::string name, std::string short_help) : @@ -546,14 +625,28 @@ void Backend::extra_args(std::ostream *&f, std::string &filename, std::vectoropen(filename.c_str(), std::ofstream::trunc); - yosys_output_files.insert(filename); - if (ff->fail()) { - delete ff; - log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno)); + if (filename.size() > 3 && filename.substr(filename.size()-3) == ".gz") { +#ifdef YOSYS_ENABLE_ZLIB + gzip_ostream *gf = new gzip_ostream; + if (!gf->open(filename)) { + delete gf; + log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno)); + } + yosys_output_files.insert(filename); + f = gf; +#else + log_cmd_error("Yosys is compiled without zlib support, unable to write gzip output.\n"); +#endif + } else { + std::ofstream *ff = new std::ofstream; + ff->open(filename.c_str(), std::ofstream::trunc); + yosys_output_files.insert(filename); + if (ff->fail()) { + delete ff; + log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno)); + } + f = ff; } - f = ff; } if (called_with_fp) @@ -603,8 +696,6 @@ void Backend::backend_call(RTLIL::Design *design, std::ostream *f, std::string f while (design->selection_stack.size() > orig_sel_stack_pos) design->selection_stack.pop_back(); - - design->check(); } static struct CellHelpMessages { diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index a09f4a0d1..ba8472ec1 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -1249,6 +1249,7 @@ namespace { if (cell->type == "$_ANDNOT_") { check_gate("ABY"); return; } if (cell->type == "$_ORNOT_") { check_gate("ABY"); return; } if (cell->type == "$_MUX_") { check_gate("ABSY"); return; } + if (cell->type == "$_NMUX_") { check_gate("ABSY"); return; } if (cell->type == "$_AOI3_") { check_gate("ABCY"); return; } if (cell->type == "$_OAI3_") { check_gate("ABCY"); return; } if (cell->type == "$_AOI4_") { check_gate("ABCDY"); return; } @@ -1976,6 +1977,7 @@ DEF_METHOD_3(XnorGate, "$_XNOR_", A, B, Y) DEF_METHOD_3(AndnotGate, "$_ANDNOT_", A, B, Y) DEF_METHOD_3(OrnotGate, "$_ORNOT_", A, B, Y) DEF_METHOD_4(MuxGate, "$_MUX_", A, B, S, Y) +DEF_METHOD_4(NmuxGate, "$_NMUX_", A, B, S, Y) DEF_METHOD_4(Aoi3Gate, "$_AOI3_", A, B, C, Y) DEF_METHOD_4(Oai3Gate, "$_OAI3_", A, B, C, Y) DEF_METHOD_5(Aoi4Gate, "$_AOI4_", A, B, C, D, Y) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 82cbfaf28..c07d39c65 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -420,8 +420,12 @@ namespace RTLIL // It maintains a reference counter that is used to make sure that the container is not modified while being iterated over. template - struct ObjIterator - { + struct ObjIterator { + using iterator_category = std::forward_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; typename dict::iterator it; dict *list_p; int *refcount_p; @@ -474,13 +478,25 @@ namespace RTLIL return it != other.it; } - inline void operator++() { + + inline bool operator==(const RTLIL::ObjIterator &other) const { + return !(*this != other); + } + + inline ObjIterator& operator++() { log_assert(list_p != nullptr); if (++it == list_p->end()) { (*refcount_p)--; list_p = nullptr; refcount_p = nullptr; } + return *this; + } + + inline const ObjIterator operator++(int) { + ObjIterator result(*this); + ++(*this); + return result; } }; @@ -772,6 +788,7 @@ public: RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const; RTLIL::SigSpec extract(const pool &pattern, const RTLIL::SigSpec *other = NULL) const; RTLIL::SigSpec extract(int offset, int length = 1) const; + RTLIL::SigSpec extract_end(int offset) const { return extract(offset, width_ - offset); } void append(const RTLIL::SigSpec &signal); void append_bit(const RTLIL::SigBit &bit); @@ -818,6 +835,7 @@ public: operator std::vector() const { return chunks(); } operator std::vector() const { return bits(); } + RTLIL::SigBit at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; } unsigned int hash() const { if (!hash_) updhash(); return hash_; }; @@ -1138,6 +1156,7 @@ public: RTLIL::Cell* addAndnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = ""); RTLIL::Cell* addOrnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = ""); RTLIL::Cell* addMuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, RTLIL::SigBit sig_y, const std::string &src = ""); + RTLIL::Cell* addNmuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, RTLIL::SigBit sig_y, const std::string &src = ""); RTLIL::Cell* addAoi3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y, const std::string &src = ""); RTLIL::Cell* addOai3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y, const std::string &src = ""); RTLIL::Cell* addAoi4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, RTLIL::SigBit sig_y, const std::string &src = ""); @@ -1213,6 +1232,7 @@ public: RTLIL::SigBit AndnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = ""); RTLIL::SigBit OrnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = ""); RTLIL::SigBit MuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, const std::string &src = ""); + RTLIL::SigBit NmuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, const std::string &src = ""); RTLIL::SigBit Aoi3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, const std::string &src = ""); RTLIL::SigBit Oai3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, const std::string &src = ""); RTLIL::SigBit Aoi4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, const std::string &src = ""); diff --git a/kernel/satgen.h b/kernel/satgen.h index 210cca3f3..e9f3ecd44 100644 --- a/kernel/satgen.h +++ b/kernel/satgen.h @@ -475,7 +475,7 @@ struct SatGen return true; } - if (cell->type == "$_MUX_" || cell->type == "$mux") + if (cell->type == "$_MUX_" || cell->type == "$mux" || cell->type == "$_NMUX_") { std::vector a = importDefSigSpec(cell->getPort("\\A"), timestep); std::vector b = importDefSigSpec(cell->getPort("\\B"), timestep); @@ -483,7 +483,10 @@ struct SatGen std::vector y = importDefSigSpec(cell->getPort("\\Y"), timestep); std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - ez->assume(ez->vec_eq(ez->vec_ite(s.at(0), b, a), yy)); + if (cell->type == "$_NMUX_") + ez->assume(ez->vec_eq(ez->vec_not(ez->vec_ite(s.at(0), b, a)), yy)); + else + ez->assume(ez->vec_eq(ez->vec_ite(s.at(0), b, a), yy)); if (model_undef) { diff --git a/kernel/yosys.cc b/kernel/yosys.cc index a42a7c0b8..a4cc53f1a 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -894,23 +894,26 @@ void run_frontend(std::string filename, std::string command, std::string *backen design = yosys_design; if (command == "auto") { - if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v") + std::string filename_trim = filename; + if (filename_trim.size() > 3 && filename_trim.substr(filename_trim.size()-3) == ".gz") + filename_trim.erase(filename_trim.size()-3); + if (filename_trim.size() > 2 && filename_trim.substr(filename_trim.size()-2) == ".v") command = "verilog"; - else if (filename.size() > 2 && filename.substr(filename.size()-3) == ".sv") + else if (filename_trim.size() > 2 && filename_trim.substr(filename_trim.size()-3) == ".sv") command = "verilog -sv"; - else if (filename.size() > 3 && filename.substr(filename.size()-4) == ".vhd") + else if (filename_trim.size() > 3 && filename_trim.substr(filename_trim.size()-4) == ".vhd") command = "vhdl"; - else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".blif") + else if (filename_trim.size() > 4 && filename_trim.substr(filename_trim.size()-5) == ".blif") command = "blif"; - else if (filename.size() > 5 && filename.substr(filename.size()-6) == ".eblif") + else if (filename_trim.size() > 5 && filename_trim.substr(filename_trim.size()-6) == ".eblif") command = "blif"; - else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".json") + else if (filename_trim.size() > 4 && filename_trim.substr(filename_trim.size()-5) == ".json") command = "json"; - else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") + else if (filename_trim.size() > 3 && filename_trim.substr(filename_trim.size()-3) == ".il") command = "ilang"; - else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".ys") + else if (filename_trim.size() > 3 && filename_trim.substr(filename_trim.size()-3) == ".ys") command = "script"; - else if (filename.size() > 3 && filename.substr(filename.size()-4) == ".tcl") + else if (filename_trim.size() > 3 && filename_trim.substr(filename_trim.size()-4) == ".tcl") command = "tcl"; else if (filename == "-") command = "script"; @@ -961,14 +964,18 @@ void run_frontend(std::string filename, std::string command, std::string *backen command += next_line; } handle_label(command, from_to_active, run_from, run_to); - if (from_to_active) + if (from_to_active) { Pass::call(design, command); + design->check(); + } } if (!command.empty()) { handle_label(command, from_to_active, run_from, run_to); - if (from_to_active) + if (from_to_active) { Pass::call(design, command); + design->check(); + } } } catch (...) { @@ -997,6 +1004,7 @@ void run_frontend(std::string filename, std::string command, std::string *backen Pass::call(design, vector({command, filename})); else Frontend::frontend_call(design, NULL, filename, command); + design->check(); } void run_frontend(std::string filename, std::string command, RTLIL::Design *design) @@ -1180,6 +1188,7 @@ void shell(RTLIL::Design *design) design->selection_stack.pop_back(); log_reset_stack(); } + design->check(); } if (command == NULL) printf("exit\n"); diff --git a/kernel/yosys.h b/kernel/yosys.h index c7b671724..09e8139bb 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -87,6 +88,10 @@ extern int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName); extern void Tcl_Finalize(void); extern int Tcl_GetCommandInfo(Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr); extern const char *Tcl_GetStringResult(Tcl_Interp *interp); +extern Tcl_Obj *Tcl_NewStringObj(const char *bytes, int length); +extern Tcl_Obj *Tcl_NewIntObj(int intValue); +extern Tcl_Obj *Tcl_NewListObj(int objc, Tcl_Obj *const objv[]); +extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags); # endif #endif diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex index cb1bcf1be..0106059b6 100644 --- a/manual/CHAPTER_CellLib.tex +++ b/manual/CHAPTER_CellLib.tex @@ -494,6 +494,6 @@ Add information about {\tt \$\_DFFE\_??\_}, {\tt \$\_DFFSR\_???\_}, {\tt \$\_DLA \end{fixme} \begin{fixme} -Add information about {\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, and {\tt \$\_OAI4\_} cells. +Add information about {\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, {\tt \$\_OAI4\_}, and {\tt \$\_NMUX\_} cells. \end{fixme} diff --git a/misc/launcher.c b/misc/launcher.c index 157d68cf3..e0d8208f1 100644 --- a/misc/launcher.c +++ b/misc/launcher.c @@ -61,6 +61,7 @@ SOFTWARE. */ #include #include #include +#include int child_pid=0; @@ -338,7 +339,7 @@ int run(int argc, char **argv, int is_gui) { if (is_gui) { /* Use exec, we don't need to wait for the GUI to finish */ - execv(ptr, (const char * const *)(newargs)); + execv(ptr, (char * const *)(newargs)); return fail("Could not exec %s", ptr); /* shouldn't get here! */ } diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 80b400e0c..c8e4f3981 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -17,11 +17,10 @@ * */ -#include "kernel/register.h" +#include "kernel/yosys.h" #include "kernel/celltypes.h" #include "passes/techmap/libparse.h" - -#include "kernel/log.h" +#include "kernel/cost.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -228,21 +227,16 @@ struct statdata_t { int tran_cnt = 0; bool tran_cnt_exact = true; + auto &gate_costs = CellCosts::cmos_gate_cost(); for (auto it : num_cells_by_type) { auto ctype = it.first; auto cnum = it.second; - if (ctype == "$_NOT_") - tran_cnt += 2*cnum; - else if (ctype.in("$_NAND_", "$_NOR_")) - tran_cnt += 4*cnum; - else if (ctype.in("$_AOI3_", "$_OAI3_")) - tran_cnt += 6*cnum; - else if (ctype.in("$_AOI4_", "$_OAI4_")) - tran_cnt += 8*cnum; + if (gate_costs.count(ctype)) + tran_cnt += cnum * gate_costs.at(ctype); else if (ctype.in("$_DFF_P_", "$_DFF_N_")) - tran_cnt += 16*cnum; + tran_cnt += cnum * 16; else tran_cnt_exact = false; } diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 512ef0cbf..acdc39937 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -641,6 +641,31 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons did_something = true; } } + + if (cell->type.in("$add", "$sub")) { + RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A")); + RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B")); + RTLIL::SigSpec sig_y = cell->getPort("\\Y"); + bool sub = cell->type == "$sub"; + + int i; + for (i = 0; i < GetSize(sig_y); i++) { + if (sig_b.at(i, State::Sx) == State::S0 && sig_a.at(i, State::Sx) != State::Sx) + module->connect(sig_y[i], sig_a[i]); + else if (!sub && sig_a.at(i, State::Sx) == State::S0 && sig_b.at(i, State::Sx) != State::Sx) + module->connect(sig_y[i], sig_b[i]); + else + break; + } + if (i > 0) { + cover_list("opt.opt_expr.fine", "$add", "$sub", cell->type.str()); + cell->setPort("\\A", sig_a.extract_end(i)); + cell->setPort("\\B", sig_b.extract_end(i)); + cell->setPort("\\Y", sig_y.extract_end(i)); + cell->fixup_parameters(); + did_something = true; + } + } } if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" || cell->type == "$shift" || cell->type == "$shiftx" || diff --git a/passes/opt/opt_lut.cc b/passes/opt/opt_lut.cc index 182f63d99..587ef878a 100644 --- a/passes/opt/opt_lut.cc +++ b/passes/opt/opt_lut.cc @@ -81,7 +81,7 @@ struct OptLutWorker } } - log("Number of LUTs: %8zu\n", luts.size()); + log("Number of LUTs: %8d\n", GetSize(luts)); for (int arity = 1; arity <= max_arity; arity++) { if (arity_counts[arity]) @@ -351,14 +351,14 @@ struct OptLutWorker int lutM_arity = lutA_arity + lutB_arity - 1 - common_inputs.size(); if (lutA_dlogic_inputs.size()) - log_debug(" Cell A is a %d-LUT with %zu dedicated connections. ", lutA_arity, lutA_dlogic_inputs.size()); + log_debug(" Cell A is a %d-LUT with %d dedicated connections. ", lutA_arity, GetSize(lutA_dlogic_inputs)); else log_debug(" Cell A is a %d-LUT. ", lutA_arity); if (lutB_dlogic_inputs.size()) - log_debug("Cell B is a %d-LUT with %zu dedicated connections.\n", lutB_arity, lutB_dlogic_inputs.size()); + log_debug("Cell B is a %d-LUT with %d dedicated connections.\n", lutB_arity, GetSize(lutB_dlogic_inputs)); else log_debug("Cell B is a %d-LUT.\n", lutB_arity); - log_debug(" Cells share %zu input(s) and can be merged into one %d-LUT.\n", common_inputs.size(), lutM_arity); + log_debug(" Cells share %d input(s) and can be merged into one %d-LUT.\n", GetSize(common_inputs), lutM_arity); const int COMBINE_A = 1, COMBINE_B = 2, COMBINE_EITHER = COMBINE_A | COMBINE_B; int combine_mask = 0; diff --git a/passes/opt/rmports.cc b/passes/opt/rmports.cc index fc1596ebf..32363dd68 100644 --- a/passes/opt/rmports.cc +++ b/passes/opt/rmports.cc @@ -171,7 +171,7 @@ struct RmportsPassPass : public Pass { wire->port_output = false; wire->port_id = 0; } - log("Removed %zu unused ports.\n", unused_ports.size()); + log("Removed %d unused ports.\n", GetSize(unused_ports)); // Re-number all of the wires that DO have ports still on them for(size_t i=0; iports.size(); i++) diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 1fbc41082..1eeca2748 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -342,9 +342,9 @@ struct WreduceWorker } } - if (cell->type.in("$pos", "$add", "$mul", "$and", "$or", "$xor")) + if (cell->type.in("$pos", "$add", "$mul", "$and", "$or", "$xor", "$sub")) { - bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); + bool is_signed = cell->getParam("\\A_SIGNED").as_bool() || cell->type == "$sub"; int a_size = 0, b_size = 0; if (cell->hasPort("\\A")) a_size = GetSize(cell->getPort("\\A")); @@ -352,7 +352,7 @@ struct WreduceWorker int max_y_size = max(a_size, b_size); - if (cell->type == "$add") + if (cell->type.in("$add", "$sub")) max_y_size++; if (cell->type == "$mul") diff --git a/passes/proc/proc_prune.cc b/passes/proc/proc_prune.cc index 9e00b0a8a..b47ee79c2 100644 --- a/passes/proc/proc_prune.cc +++ b/passes/proc/proc_prune.cc @@ -82,14 +82,23 @@ struct PruneWorker if (root) { bool promotable = true; for (auto &bit : lhs) { - if (bit.wire && affected[bit]) { + if (bit.wire && affected[bit] && !assigned[bit]) { promotable = false; break; } } if (promotable) { + RTLIL::SigSpec rhs = sigmap(it->second); + RTLIL::SigSig conn; + for (int i = 0; i < GetSize(lhs); i++) { + RTLIL::SigBit lhs_bit = lhs[i]; + if (lhs_bit.wire && !assigned[lhs_bit]) { + conn.first.append_bit(lhs_bit); + conn.second.append(rhs.extract(i)); + } + } promoted_count++; - module->connect(*it); + module->connect(conn); remove.insert(*it); } } diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 65c7d1bb8..c0cfe2f36 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -81,6 +82,7 @@ enum class gate_type_t { G_ANDNOT, G_ORNOT, G_MUX, + G_NMUX, G_AOI3, G_OAI3, G_AOI4, @@ -111,7 +113,7 @@ std::vector signal_list; std::map signal_map; std::map signal_init; pool enabled_gates; -bool recover_init; +bool recover_init, cmos_cost; bool clk_polarity, en_polarity; RTLIL::SigSpec clk_sig, en_sig; @@ -257,7 +259,7 @@ void extract_cell(RTLIL::Cell *cell, bool keepff) return; } - if (cell->type == "$_MUX_") + if (cell->type.in("$_MUX_", "$_NMUX_")) { RTLIL::SigSpec sig_a = cell->getPort("\\A"); RTLIL::SigSpec sig_b = cell->getPort("\\B"); @@ -273,7 +275,7 @@ void extract_cell(RTLIL::Cell *cell, bool keepff) int mapped_b = map_signal(sig_b); int mapped_s = map_signal(sig_s); - map_signal(sig_y, G(MUX), mapped_a, mapped_b, mapped_s); + map_signal(sig_y, cell->type == "$_MUX_" ? G(MUX) : G(NMUX), mapped_a, mapped_b, mapped_s); module->remove(cell); return; @@ -885,6 +887,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id); fprintf(f, "1-0 1\n"); fprintf(f, "-11 1\n"); + } else if (si.type == G(NMUX)) { + fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id); + fprintf(f, "0-0 1\n"); + fprintf(f, "-01 1\n"); } else if (si.type == G(AOI3)) { fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id); fprintf(f, "-00 1\n"); @@ -925,46 +931,50 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin { log_header(design, "Executing ABC.\n"); + auto &cell_cost = cmos_cost ? CellCosts::cmos_gate_cost() : CellCosts::default_gate_cost(); + buffer = stringf("%s/stdcells.genlib", tempdir_name.c_str()); f = fopen(buffer.c_str(), "wt"); if (f == NULL) log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno)); fprintf(f, "GATE ZERO 1 Y=CONST0;\n"); fprintf(f, "GATE ONE 1 Y=CONST1;\n"); - fprintf(f, "GATE BUF %d Y=A; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_BUF_")); - fprintf(f, "GATE NOT %d Y=!A; PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOT_")); + fprintf(f, "GATE BUF %d Y=A; PIN * NONINV 1 999 1 0 1 0\n", cell_cost.at("$_BUF_")); + fprintf(f, "GATE NOT %d Y=!A; PIN * INV 1 999 1 0 1 0\n", cell_cost.at("$_NOT_")); if (enabled_gates.empty() || enabled_gates.count("AND")) - fprintf(f, "GATE AND %d Y=A*B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_AND_")); + fprintf(f, "GATE AND %d Y=A*B; PIN * NONINV 1 999 1 0 1 0\n", cell_cost.at("$_AND_")); if (enabled_gates.empty() || enabled_gates.count("NAND")) - fprintf(f, "GATE NAND %d Y=!(A*B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NAND_")); + fprintf(f, "GATE NAND %d Y=!(A*B); PIN * INV 1 999 1 0 1 0\n", cell_cost.at("$_NAND_")); if (enabled_gates.empty() || enabled_gates.count("OR")) - fprintf(f, "GATE OR %d Y=A+B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_OR_")); + fprintf(f, "GATE OR %d Y=A+B; PIN * NONINV 1 999 1 0 1 0\n", cell_cost.at("$_OR_")); if (enabled_gates.empty() || enabled_gates.count("NOR")) - fprintf(f, "GATE NOR %d Y=!(A+B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOR_")); + fprintf(f, "GATE NOR %d Y=!(A+B); PIN * INV 1 999 1 0 1 0\n", cell_cost.at("$_NOR_")); if (enabled_gates.empty() || enabled_gates.count("XOR")) - fprintf(f, "GATE XOR %d Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XOR_")); + fprintf(f, "GATE XOR %d Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_XOR_")); if (enabled_gates.empty() || enabled_gates.count("XNOR")) - fprintf(f, "GATE XNOR %d Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XNOR_")); + fprintf(f, "GATE XNOR %d Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_XNOR_")); if (enabled_gates.empty() || enabled_gates.count("ANDNOT")) - fprintf(f, "GATE ANDNOT %d Y=A*!B; PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_ANDNOT_")); + fprintf(f, "GATE ANDNOT %d Y=A*!B; PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_ANDNOT_")); if (enabled_gates.empty() || enabled_gates.count("ORNOT")) - fprintf(f, "GATE ORNOT %d Y=A+!B; PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_ORNOT_")); + fprintf(f, "GATE ORNOT %d Y=A+!B; PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_ORNOT_")); if (enabled_gates.empty() || enabled_gates.count("AOI3")) - fprintf(f, "GATE AOI3 %d Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI3_")); + fprintf(f, "GATE AOI3 %d Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n", cell_cost.at("$_AOI3_")); if (enabled_gates.empty() || enabled_gates.count("OAI3")) - fprintf(f, "GATE OAI3 %d Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI3_")); + fprintf(f, "GATE OAI3 %d Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n", cell_cost.at("$_OAI3_")); if (enabled_gates.empty() || enabled_gates.count("AOI4")) - fprintf(f, "GATE AOI4 %d Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI4_")); + fprintf(f, "GATE AOI4 %d Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n", cell_cost.at("$_AOI4_")); if (enabled_gates.empty() || enabled_gates.count("OAI4")) - fprintf(f, "GATE OAI4 %d Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI4_")); + fprintf(f, "GATE OAI4 %d Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n", cell_cost.at("$_OAI4_")); if (enabled_gates.empty() || enabled_gates.count("MUX")) - fprintf(f, "GATE MUX %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_MUX_")); + fprintf(f, "GATE MUX %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_MUX_")); + if (enabled_gates.empty() || enabled_gates.count("NMUX")) + fprintf(f, "GATE NMUX %d Y=!((A*B)+(S*B)+(!S*A)); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_NMUX_")); if (map_mux4) - fprintf(f, "GATE MUX4 %d Y=(!S*!T*A)+(S*!T*B)+(!S*T*C)+(S*T*D); PIN * UNKNOWN 1 999 1 0 1 0\n", 2*get_cell_cost("$_MUX_")); + fprintf(f, "GATE MUX4 %d Y=(!S*!T*A)+(S*!T*B)+(!S*T*C)+(S*T*D); PIN * UNKNOWN 1 999 1 0 1 0\n", 2*cell_cost.at("$_MUX_")); if (map_mux8) - fprintf(f, "GATE MUX8 %d Y=(!S*!T*!U*A)+(S*!T*!U*B)+(!S*T*!U*C)+(S*T*!U*D)+(!S*!T*U*E)+(S*!T*U*F)+(!S*T*U*G)+(S*T*U*H); PIN * UNKNOWN 1 999 1 0 1 0\n", 4*get_cell_cost("$_MUX_")); + fprintf(f, "GATE MUX8 %d Y=(!S*!T*!U*A)+(S*!T*!U*B)+(!S*T*!U*C)+(S*T*!U*D)+(!S*!T*U*E)+(S*!T*U*F)+(!S*T*U*G)+(S*T*U*H); PIN * UNKNOWN 1 999 1 0 1 0\n", 4*cell_cost.at("$_MUX_")); if (map_mux16) - fprintf(f, "GATE MUX16 %d Y=(!S*!T*!U*!V*A)+(S*!T*!U*!V*B)+(!S*T*!U*!V*C)+(S*T*!U*!V*D)+(!S*!T*U*!V*E)+(S*!T*U*!V*F)+(!S*T*U*!V*G)+(S*T*U*!V*H)+(!S*!T*!U*V*I)+(S*!T*!U*V*J)+(!S*T*!U*V*K)+(S*T*!U*V*L)+(!S*!T*U*V*M)+(S*!T*U*V*N)+(!S*T*U*V*O)+(S*T*U*V*P); PIN * UNKNOWN 1 999 1 0 1 0\n", 8*get_cell_cost("$_MUX_")); + fprintf(f, "GATE MUX16 %d Y=(!S*!T*!U*!V*A)+(S*!T*!U*!V*B)+(!S*T*!U*!V*C)+(S*T*!U*!V*D)+(!S*!T*U*!V*E)+(S*!T*U*!V*F)+(!S*T*U*!V*G)+(S*T*U*!V*H)+(!S*!T*!U*V*I)+(S*!T*!U*V*J)+(!S*T*!U*V*K)+(S*T*!U*V*L)+(!S*!T*U*V*M)+(S*!T*U*V*N)+(!S*T*U*V*O)+(S*T*U*V*P); PIN * UNKNOWN 1 999 1 0 1 0\n", 8*cell_cost.at("$_MUX_")); fclose(f); if (!lut_costs.empty()) { @@ -1065,8 +1075,8 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin design->select(module, cell); continue; } - if (c->type == "\\MUX") { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_MUX_"); + if (c->type == "\\MUX" || c->type == "\\NMUX") { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_"); if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx; cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)])); cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)])); @@ -1406,11 +1416,12 @@ struct AbcPass : public Pass { log("\n"); log(" The following aliases can be used to reference common sets of gate types:\n"); log(" simple: AND OR XOR MUX\n"); - log(" cmos2: NAND NOR\n"); - log(" cmos3: NAND NOR AOI3 OAI3\n"); - log(" cmos4: NAND NOR AOI3 OAI3 AOI4 OAI4\n"); - log(" gates: AND NAND OR NOR XOR XNOR ANDNOT ORNOT\n"); - log(" aig: AND NAND OR NOR ANDNOT ORNOT\n"); + log(" cmos2: NAND NOR\n"); + log(" cmos3: NAND NOR AOI3 OAI3\n"); + log(" cmos4: NAND NOR AOI3 OAI3 AOI4 OAI4\n"); + log(" cmos: NAND NOR AOI3 OAI3 AOI4 OAI4 NMUX MUX XOR XNOR\n"); + log(" gates: AND NAND OR NOR XOR XNOR ANDNOT ORNOT\n"); + log(" aig: AND NAND OR NOR ANDNOT ORNOT\n"); log("\n"); log(" Prefix a gate type with a '-' to remove it from the list. For example\n"); log(" the arguments 'AND,OR,XOR' and 'simple,-MUX' are equivalent.\n"); @@ -1488,6 +1499,7 @@ struct AbcPass : public Pass { map_mux8 = false; map_mux16 = false; enabled_gates.clear(); + cmos_cost = false; #ifdef _WIN32 #ifndef ABCEXTERNAL @@ -1628,11 +1640,15 @@ struct AbcPass : public Pass { goto ok_alias; } if (g == "cmos2") { + if (!remove_gates) + cmos_cost = true; gate_list.push_back("NAND"); gate_list.push_back("NOR"); goto ok_alias; } if (g == "cmos3") { + if (!remove_gates) + cmos_cost = true; gate_list.push_back("NAND"); gate_list.push_back("NOR"); gate_list.push_back("AOI3"); @@ -1640,6 +1656,8 @@ struct AbcPass : public Pass { goto ok_alias; } if (g == "cmos4") { + if (!remove_gates) + cmos_cost = true; gate_list.push_back("NAND"); gate_list.push_back("NOR"); gate_list.push_back("AOI3"); @@ -1648,6 +1666,21 @@ struct AbcPass : public Pass { gate_list.push_back("OAI4"); goto ok_alias; } + if (g == "cmos") { + if (!remove_gates) + cmos_cost = true; + gate_list.push_back("NAND"); + gate_list.push_back("NOR"); + gate_list.push_back("AOI3"); + gate_list.push_back("OAI3"); + gate_list.push_back("AOI4"); + gate_list.push_back("OAI4"); + gate_list.push_back("NMUX"); + gate_list.push_back("MUX"); + gate_list.push_back("XOR"); + gate_list.push_back("XNOR"); + goto ok_alias; + } if (g == "gates") { gate_list.push_back("AND"); gate_list.push_back("NAND"); diff --git a/passes/techmap/extract_fa.cc b/passes/techmap/extract_fa.cc index 591bc43dd..b541ceb6b 100644 --- a/passes/techmap/extract_fa.cc +++ b/passes/techmap/extract_fa.cc @@ -86,7 +86,7 @@ struct ExtractFaWorker for (auto cell : module->selected_cells()) { if (cell->type.in( "$_BUF_", "$_NOT_", "$_AND_", "$_NAND_", "$_OR_", "$_NOR_", - "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_", "$_MUX_", + "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_", "$_MUX_", "$_NMUX_", "$_AOI3_", "$_OAI3_", "$_AOI4_", "$_OAI4_")) { SigBit y = sigmap(SigBit(cell->getPort("\\Y"))); diff --git a/passes/techmap/flowmap.cc b/passes/techmap/flowmap.cc index f5892a60e..96d0df5f8 100644 --- a/passes/techmap/flowmap.cc +++ b/passes/techmap/flowmap.cc @@ -783,7 +783,7 @@ struct FlowmapWorker int depth = 0; for (auto label : labels) depth = max(depth, label.second); - log("Mapped to %zu LUTs with maximum depth %d.\n", lut_nodes.size(), depth); + log("Mapped to %d LUTs with maximum depth %d.\n", GetSize(lut_nodes), depth); if (debug) { @@ -1195,7 +1195,7 @@ struct FlowmapWorker bool relax_depth_for_bound(bool first, int depth_bound, dict> &lut_critical_outputs) { - size_t initial_count = lut_nodes.size(); + int initial_count = GetSize(lut_nodes); for (auto node : lut_nodes) { @@ -1215,7 +1215,7 @@ struct FlowmapWorker if (potentials.empty()) { - log(" Relaxed to %zu (+%zu) LUTs.\n", lut_nodes.size(), lut_nodes.size() - initial_count); + log(" Relaxed to %d (+%d) LUTs.\n", GetSize(lut_nodes), GetSize(lut_nodes) - initial_count); if (!first && break_num == 1) { log(" Design fully relaxed.\n"); @@ -1419,9 +1419,9 @@ struct FlowmapWorker lut_area += lut_table.size(); if ((int)input_nodes.size() >= minlut) - log(" Packed into a %zu-LUT %s.%s.\n", input_nodes.size(), log_id(module), log_id(lut)); + log(" Packed into a %d-LUT %s.%s.\n", GetSize(input_nodes), log_id(module), log_id(lut)); else - log(" Packed into a %zu-LUT %s.%s (implemented as %d-LUT).\n", input_nodes.size(), log_id(module), log_id(lut), minlut); + log(" Packed into a %d-LUT %s.%s (implemented as %d-LUT).\n", GetSize(input_nodes), log_id(module), log_id(lut), minlut); } for (auto node : mapped_nodes) diff --git a/techlibs/anlogic/anlogic_determine_init.cc b/techlibs/anlogic/anlogic_determine_init.cc index 34b1d4f8a..c4089dac2 100644 --- a/techlibs/anlogic/anlogic_determine_init.cc +++ b/techlibs/anlogic/anlogic_determine_init.cc @@ -50,7 +50,7 @@ struct AnlogicDetermineInitPass : public Pass { extra_args(args, args.size(), design); - size_t cnt = 0; + int cnt = 0; for (auto module : design->selected_modules()) { for (auto cell : module->selected_cells()) @@ -65,7 +65,7 @@ struct AnlogicDetermineInitPass : public Pass { } } } - log_header(design, "Updated %lu cells with determined init value.\n", cnt); + log_header(design, "Updated %d cells with determined init value.\n", cnt); } } AnlogicDetermineInitPass; diff --git a/techlibs/anlogic/anlogic_eqn.cc b/techlibs/anlogic/anlogic_eqn.cc index 741bf04cc..070d39a20 100644 --- a/techlibs/anlogic/anlogic_eqn.cc +++ b/techlibs/anlogic/anlogic_eqn.cc @@ -69,7 +69,7 @@ struct AnlogicEqnPass : public Pass { extra_args(args, args.size(), design); - size_t cnt = 0; + int cnt = 0; for (auto module : design->selected_modules()) { for (auto cell : module->selected_cells()) @@ -106,7 +106,7 @@ struct AnlogicEqnPass : public Pass { } } } - log_header(design, "Updated %lu of AL_MAP_LUT* elements with equation.\n", cnt); + log_header(design, "Updated %d of AL_MAP_LUT* elements with equation.\n", cnt); } } AnlogicEqnPass; diff --git a/techlibs/anlogic/arith_map.v b/techlibs/anlogic/arith_map.v index 11cd140ec..6d6a7ca37 100644 --- a/techlibs/anlogic/arith_map.v +++ b/techlibs/anlogic/arith_map.v @@ -42,10 +42,9 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO); wire [Y_WIDTH-1:0] AA = A_buf; wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; wire [Y_WIDTH+1:0] COx; - wire [Y_WIDTH+1:0] C = {COx, CI}; + wire [Y_WIDTH+2:0] C = {COx, CI}; wire dummy; - (* keep *) AL_MAP_ADDER #( .ALUTYPE("ADD_CARRY")) adder_cin ( @@ -55,19 +54,6 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO); genvar i; generate for (i = 0; i < Y_WIDTH; i = i + 1) begin: slice - if(i==Y_WIDTH-1) begin - (* keep *) - AL_MAP_ADDER #( - .ALUTYPE("ADD")) - adder_cout ( - .c(C[Y_WIDTH]), - .o(COx[Y_WIDTH]) - ); - assign CO = COx[Y_WIDTH]; - end - else - begin - (* keep *) AL_MAP_ADDER #( .ALUTYPE("ADD") ) adder_i ( @@ -76,9 +62,15 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO); .c(C[i+1]), .o({COx[i+1],Y[i]}) ); - end end: slice endgenerate /* End implementation */ + AL_MAP_ADDER #( + .ALUTYPE("ADD")) + adder_cout ( + .c(C[Y_WIDTH+1]), + .o(COx[Y_WIDTH+1]) + ); + assign CO = COx[Y_WIDTH+1]; assign X = AA ^ BB; endmodule \ No newline at end of file diff --git a/techlibs/common/simcells.v b/techlibs/common/simcells.v index 289673e82..64720e598 100644 --- a/techlibs/common/simcells.v +++ b/techlibs/common/simcells.v @@ -228,6 +228,25 @@ output Y; assign Y = S ? B : A; endmodule +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $_NMUX_ (A, B, S, Y) +//- +//- A 2-input inverting MUX gate. +//- +//- Truth table: A B S | Y +//- -------+--- +//- 0 - 0 | 1 +//- 1 - 0 | 0 +//- - 0 1 | 1 +//- - 1 1 | 0 +//- +module \$_NMUX_ (A, B, S, Y); +input A, B, S; +output Y; +assign Y = S ? !B : !A; +endmodule + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| //- //- $_MUX4_ (A, B, C, D, S, T, Y) diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v index ca88d0a5b..3d343b315 100644 --- a/techlibs/ecp5/cells_sim.v +++ b/techlibs/ecp5/cells_sim.v @@ -333,6 +333,31 @@ module TRELLIS_SLICE( parameter [127:0] CCU2_INJECT1_0 = "NO"; parameter [127:0] CCU2_INJECT1_1 = "NO"; parameter WREMUX = "WRE"; + parameter WCKMUX = "WCK"; + + parameter A0MUX = "A0"; + parameter A1MUX = "A1"; + parameter B0MUX = "B0"; + parameter B1MUX = "B1"; + parameter C0MUX = "C0"; + parameter C1MUX = "C1"; + parameter D0MUX = "D0"; + parameter D1MUX = "D1"; + + wire A0m, B0m, C0m, D0m; + wire A1m, B1m, C1m, D1m; + + generate + if (A0MUX == "1") assign A0m = 1'b1; else assign A0m = A0; + if (B0MUX == "1") assign B0m = 1'b1; else assign B0m = B0; + if (C0MUX == "1") assign C0m = 1'b1; else assign C0m = C0; + if (D0MUX == "1") assign D0m = 1'b1; else assign D0m = D0; + if (A1MUX == "1") assign A1m = 1'b1; else assign A1m = A1; + if (B1MUX == "1") assign B1m = 1'b1; else assign B1m = B1; + if (C1MUX == "1") assign C1m = 1'b1; else assign C1m = C1; + if (D1MUX == "1") assign D1m = 1'b1; else assign D1m = D1; + + endgenerate function [15:0] permute_initval; input [15:0] initval; @@ -350,13 +375,13 @@ module TRELLIS_SLICE( LUT4 #( .INIT(LUT0_INITVAL) ) lut4_0 ( - .A(A0), .B(B0), .C(C0), .D(D0), + .A(A0m), .B(B0m), .C(C0m), .D(D0m), .Z(F0) ); LUT4 #( .INIT(LUT1_INITVAL) ) lut4_1 ( - .A(A1), .B(B1), .C(C1), .D(D1), + .A(A1m), .B(B1m), .C(C1m), .D(D1m), .Z(F1) ); // LUT expansion muxes @@ -370,20 +395,20 @@ module TRELLIS_SLICE( .INJECT1_1(CCU2_INJECT1_1) ) ccu2c_i ( .CIN(FCI), - .A0(A0), .B0(B0), .C0(C0), .D0(D0), - .A1(A1), .B1(B1), .C1(C1), .D1(D1), + .A0(A0m), .B0(B0m), .C0(C0m), .D0(D0m), + .A1(A1m), .B1(B1m), .C1(C1m), .D1(D1m), .S0(F0), .S1(F1), .COUT(FCO) ); end else if (MODE == "RAMW") begin - assign WDO0 = C1; - assign WDO1 = A1; - assign WDO2 = D1; - assign WDO3 = B1; - assign WADO0 = D0; - assign WADO1 = B0; - assign WADO2 = C0; - assign WADO3 = A0; + assign WDO0 = C1m; + assign WDO1 = A1m; + assign WDO2 = D1m; + assign WDO3 = B1m; + assign WADO0 = D0m; + assign WADO1 = B0m; + assign WADO2 = C0m; + assign WADO3 = A0m; end else if (MODE == "DPRAM") begin TRELLIS_RAM16X2 #( .INITVAL_0(permute_initval(LUT0_INITVAL)), @@ -393,17 +418,19 @@ module TRELLIS_SLICE( .DI0(WD0), .DI1(WD1), .WAD0(WAD0), .WAD1(WAD1), .WAD2(WAD2), .WAD3(WAD3), .WRE(WRE), .WCK(WCK), - .RAD0(D0), .RAD1(B0), .RAD2(C0), .RAD3(A0), + .RAD0(D0m), .RAD1(B0m), .RAD2(C0m), .RAD3(A0m), .DO0(F0), .DO1(F1) ); // TODO: confirm RAD and INITVAL ordering // DPRAM mode contract? +`ifdef FORMAL always @(*) begin - assert(A0==A1); - assert(B0==B1); - assert(C0==C1); - assert(D0==D1); + assert(A0m==A1m); + assert(B0m==B1m); + assert(C0m==C1m); + assert(D0m==D1m); end +`endif end else begin ERROR_UNKNOWN_SLICE_MODE error(); end @@ -455,90 +482,206 @@ module DP16KD( input CSB2, CSB1, CSB0, output DOB17, DOB16, DOB15, DOB14, DOB13, DOB12, DOB11, DOB10, DOB9, DOB8, DOB7, DOB6, DOB5, DOB4, DOB3, DOB2, DOB1, DOB0 ); - parameter DATA_WIDTH_A = 18; - parameter DATA_WIDTH_B = 18; + parameter DATA_WIDTH_A = 18; + parameter DATA_WIDTH_B = 18; - parameter REGMODE_A = "NOREG"; - parameter REGMODE_B = "NOREG"; + parameter REGMODE_A = "NOREG"; + parameter REGMODE_B = "NOREG"; - parameter RESETMODE = "SYNC"; - parameter ASYNC_RESET_RELEASE = "SYNC"; + parameter RESETMODE = "SYNC"; + parameter ASYNC_RESET_RELEASE = "SYNC"; - parameter CSDECODE_A = "0b000"; - parameter CSDECODE_B = "0b000"; + parameter CSDECODE_A = "0b000"; + parameter CSDECODE_B = "0b000"; - parameter WRITEMODE_A = "NORMAL"; - parameter WRITEMODE_B = "NORMAL"; + parameter WRITEMODE_A = "NORMAL"; + parameter WRITEMODE_B = "NORMAL"; - parameter CLKAMUX = "CLKA"; - parameter CLKBMUX = "CLKB"; + parameter DIA17MUX = "DIA17"; + parameter DIA16MUX = "DIA16"; + parameter DIA15MUX = "DIA15"; + parameter DIA14MUX = "DIA14"; + parameter DIA13MUX = "DIA13"; + parameter DIA12MUX = "DIA12"; + parameter DIA11MUX = "DIA11"; + parameter DIA10MUX = "DIA10"; + parameter DIA9MUX = "DIA9"; + parameter DIA8MUX = "DIA8"; + parameter DIA7MUX = "DIA7"; + parameter DIA6MUX = "DIA6"; + parameter DIA5MUX = "DIA5"; + parameter DIA4MUX = "DIA4"; + parameter DIA3MUX = "DIA3"; + parameter DIA2MUX = "DIA2"; + parameter DIA1MUX = "DIA1"; + parameter DIA0MUX = "DIA0"; + parameter ADA13MUX = "ADA13"; + parameter ADA12MUX = "ADA12"; + parameter ADA11MUX = "ADA11"; + parameter ADA10MUX = "ADA10"; + parameter ADA9MUX = "ADA9"; + parameter ADA8MUX = "ADA8"; + parameter ADA7MUX = "ADA7"; + parameter ADA6MUX = "ADA6"; + parameter ADA5MUX = "ADA5"; + parameter ADA4MUX = "ADA4"; + parameter ADA3MUX = "ADA3"; + parameter ADA2MUX = "ADA2"; + parameter ADA1MUX = "ADA1"; + parameter ADA0MUX = "ADA0"; + parameter CEAMUX = "CEA"; + parameter OCEAMUX = "OCEA"; + parameter CLKAMUX = "CLKA"; + parameter WEAMUX = "WEA"; + parameter RSTAMUX = "RSTA"; + parameter CSA2MUX = "CSA2"; + parameter CSA1MUX = "CSA1"; + parameter CSA0MUX = "CSA0"; + parameter DOA17MUX = "DOA17"; + parameter DOA16MUX = "DOA16"; + parameter DOA15MUX = "DOA15"; + parameter DOA14MUX = "DOA14"; + parameter DOA13MUX = "DOA13"; + parameter DOA12MUX = "DOA12"; + parameter DOA11MUX = "DOA11"; + parameter DOA10MUX = "DOA10"; + parameter DOA9MUX = "DOA9"; + parameter DOA8MUX = "DOA8"; + parameter DOA7MUX = "DOA7"; + parameter DOA6MUX = "DOA6"; + parameter DOA5MUX = "DOA5"; + parameter DOA4MUX = "DOA4"; + parameter DOA3MUX = "DOA3"; + parameter DOA2MUX = "DOA2"; + parameter DOA1MUX = "DOA1"; + parameter DOA0MUX = "DOA0"; + parameter DIB17MUX = "DIB17"; + parameter DIB16MUX = "DIB16"; + parameter DIB15MUX = "DIB15"; + parameter DIB14MUX = "DIB14"; + parameter DIB13MUX = "DIB13"; + parameter DIB12MUX = "DIB12"; + parameter DIB11MUX = "DIB11"; + parameter DIB10MUX = "DIB10"; + parameter DIB9MUX = "DIB9"; + parameter DIB8MUX = "DIB8"; + parameter DIB7MUX = "DIB7"; + parameter DIB6MUX = "DIB6"; + parameter DIB5MUX = "DIB5"; + parameter DIB4MUX = "DIB4"; + parameter DIB3MUX = "DIB3"; + parameter DIB2MUX = "DIB2"; + parameter DIB1MUX = "DIB1"; + parameter DIB0MUX = "DIB0"; + parameter ADB13MUX = "ADB13"; + parameter ADB12MUX = "ADB12"; + parameter ADB11MUX = "ADB11"; + parameter ADB10MUX = "ADB10"; + parameter ADB9MUX = "ADB9"; + parameter ADB8MUX = "ADB8"; + parameter ADB7MUX = "ADB7"; + parameter ADB6MUX = "ADB6"; + parameter ADB5MUX = "ADB5"; + parameter ADB4MUX = "ADB4"; + parameter ADB3MUX = "ADB3"; + parameter ADB2MUX = "ADB2"; + parameter ADB1MUX = "ADB1"; + parameter ADB0MUX = "ADB0"; + parameter CEBMUX = "CEB"; + parameter OCEBMUX = "OCEB"; + parameter CLKBMUX = "CLKB"; + parameter WEBMUX = "WEB"; + parameter RSTBMUX = "RSTB"; + parameter CSB2MUX = "CSB2"; + parameter CSB1MUX = "CSB1"; + parameter CSB0MUX = "CSB0"; + parameter DOB17MUX = "DOB17"; + parameter DOB16MUX = "DOB16"; + parameter DOB15MUX = "DOB15"; + parameter DOB14MUX = "DOB14"; + parameter DOB13MUX = "DOB13"; + parameter DOB12MUX = "DOB12"; + parameter DOB11MUX = "DOB11"; + parameter DOB10MUX = "DOB10"; + parameter DOB9MUX = "DOB9"; + parameter DOB8MUX = "DOB8"; + parameter DOB7MUX = "DOB7"; + parameter DOB6MUX = "DOB6"; + parameter DOB5MUX = "DOB5"; + parameter DOB4MUX = "DOB4"; + parameter DOB3MUX = "DOB3"; + parameter DOB2MUX = "DOB2"; + parameter DOB1MUX = "DOB1"; + parameter DOB0MUX = "DOB0"; - parameter GSR = "ENABLED"; + parameter WID = 0; - parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_20 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_21 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_22 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_23 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_24 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_25 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_26 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_27 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_28 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_29 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_2F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_30 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_31 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_32 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_33 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_34 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_35 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_36 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_37 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_38 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_39 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter GSR = "ENABLED"; + + parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_20 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_21 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_22 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_23 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_24 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_25 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_26 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_27 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_28 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_29 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_30 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_31 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_32 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_33 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_34 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_35 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_36 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_37 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_38 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_39 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; endmodule // TODO: Diamond flip-flops diff --git a/techlibs/gowin/determine_init.cc b/techlibs/gowin/determine_init.cc index 991e5245a..d9a0880f6 100644 --- a/techlibs/gowin/determine_init.cc +++ b/techlibs/gowin/determine_init.cc @@ -50,7 +50,7 @@ struct DetermineInitPass : public Pass { extra_args(args, args.size(), design); - size_t cnt = 0; + int cnt = 0; for (auto module : design->selected_modules()) { for (auto cell : module->selected_cells()) @@ -65,7 +65,7 @@ struct DetermineInitPass : public Pass { } } } - log_header(design, "Updated %lu cells with determined init value.\n", cnt); + log_header(design, "Updated %d cells with determined init value.\n", cnt); } } DetermineInitPass; diff --git a/techlibs/intel/Makefile.inc b/techlibs/intel/Makefile.inc index ec7cea379..7a3d2c71a 100644 --- a/techlibs/intel/Makefile.inc +++ b/techlibs/intel/Makefile.inc @@ -3,8 +3,8 @@ OBJS += techlibs/intel/synth_intel.o $(eval $(call add_share_file,share/intel/common,techlibs/intel/common/m9k_bb.v)) $(eval $(call add_share_file,share/intel/common,techlibs/intel/common/altpll_bb.v)) -$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/brams.txt)) -$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/brams_map.v)) +$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/brams_m9k.txt)) +$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/brams_map_m9k.v)) $(eval $(call add_share_file,share/intel/max10,techlibs/intel/max10/cells_sim.v)) $(eval $(call add_share_file,share/intel/a10gx,techlibs/intel/a10gx/cells_sim.v)) $(eval $(call add_share_file,share/intel/cyclonev,techlibs/intel/cyclonev/cells_sim.v)) diff --git a/techlibs/intel/common/brams.txt b/techlibs/intel/common/brams_m9k.txt similarity index 100% rename from techlibs/intel/common/brams.txt rename to techlibs/intel/common/brams_m9k.txt diff --git a/techlibs/intel/common/brams_map.v b/techlibs/intel/common/brams_map_m9k.v similarity index 100% rename from techlibs/intel/common/brams_map.v rename to techlibs/intel/common/brams_map_m9k.v diff --git a/techlibs/intel/synth_intel.cc b/techlibs/intel/synth_intel.cc index d7b089503..e5dc1adc7 100644 --- a/techlibs/intel/synth_intel.cc +++ b/techlibs/intel/synth_intel.cc @@ -61,8 +61,8 @@ struct SynthIntelPass : public ScriptPass { log(" from label is synonymous to 'begin', and empty to label is\n"); log(" synonymous to the end of the command list.\n"); log("\n"); - log(" -noiopads\n"); - log(" do not use IO pad cells in output netlist\n"); + log(" -iopads\n"); + log(" use IO pad cells in output netlist\n"); log("\n"); log(" -nobram\n"); log(" do not use block RAM cells in output netlist\n"); @@ -79,7 +79,7 @@ struct SynthIntelPass : public ScriptPass { } string top_opt, family_opt, vout_file, blif_file; - bool retime, flatten, nobram, noiopads; + bool retime, flatten, nobram, iopads; void clear_flags() YS_OVERRIDE { @@ -90,7 +90,7 @@ struct SynthIntelPass : public ScriptPass { retime = false; flatten = true; nobram = false; - noiopads = false; + iopads = false; } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE @@ -125,8 +125,8 @@ struct SynthIntelPass : public ScriptPass { run_to = args[argidx].substr(pos + 1); continue; } - if (args[argidx] == "-noiopads") { - noiopads = true; + if (args[argidx] == "-iopads") { + iopads = true; continue; } if (args[argidx] == "-nobram") { @@ -187,8 +187,15 @@ struct SynthIntelPass : public ScriptPass { } if (!nobram && check_label("map_bram", "(skip if -nobram)")) { - run("memory_bram -rules +/intel/common/brams.txt"); - run("techmap -map +/intel/common/brams_map.v"); + if (family_opt == "cycloneiv" || + family_opt == "cycloneive" || + family_opt == "max10" || + help_mode) { + run("memory_bram -rules +/intel/common/brams_m9k.txt", "(if applicable for family)"); + run("techmap -map +/intel/common/brams_map_m9k.v", "(if applicable for family)"); + } else { + log_warning("BRAM mapping is not currently supported for %s.\n", family_opt.c_str()); + } } if (check_label("map_ffram")) { @@ -215,10 +222,9 @@ struct SynthIntelPass : public ScriptPass { } if (check_label("map_cells")) { - if (!noiopads) - run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)"); + if (iopads || help_mode) + run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(if -iopads)"); run(stringf("techmap -map +/intel/%s/cells_map.v", family_opt.c_str())); - run("dffinit -highlow -ff dffeas q power_up"); run("clean -purge"); } diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 2eb9fa2c1..b8e5bafc7 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -24,9 +24,9 @@ module _90_dff_nn0_to_np0 (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLA (* techmap_celltype = "$_DFF_PN0_" *) module _90_dff_pn0_to_pp0 (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule (* techmap_celltype = "$_DFF_NN1_" *) -module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule +module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule (* techmap_celltype = "$_DFF_PN1_" *) -module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule +module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule module \$__SHREG_ (input C, input D, input E, output Q); parameter DEPTH = 0; diff --git a/techlibs/xilinx/xc6s_brams_map.v b/techlibs/xilinx/xc6s_brams_map.v index c9b33af42..16fd15e74 100644 --- a/techlibs/xilinx/xc6s_brams_map.v +++ b/techlibs/xilinx/xc6s_brams_map.v @@ -52,7 +52,7 @@ module \$__XILINX_RAMB8BWER_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DAT .CLKBRDCLK(CLK2 ^ !CLKPOL2), .ENBRDEN(A1EN), .REGCEBREGCE(|1), - .RSTB(|0) + .RSTBRST(|0) ); endmodule @@ -217,7 +217,7 @@ module \$__XILINX_RAMB8BWER_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DAT .CLKBRDCLK(CLK3 ^ !CLKPOL3), .ENBRDEN(|1), .REGCEBREGCE(|0), - .RSTB(|0), + .RSTBRST(|0), .WEBWEU(B1EN_2) ); end else begin @@ -248,7 +248,7 @@ module \$__XILINX_RAMB8BWER_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DAT .CLKBRDCLK(CLK3 ^ !CLKPOL3), .ENBRDEN(|1), .REGCEBREGCE(|0), - .RSTB(|0), + .RSTBRST(|0), .WEBWEU(B1EN_2) ); end endgenerate diff --git a/tests/simple/xfirrtl b/tests/simple/xfirrtl index ba61a4476..10063d2c2 100644 --- a/tests/simple/xfirrtl +++ b/tests/simple/xfirrtl @@ -1,10 +1,12 @@ # This file contains the names of verilog files to exclude from verilog to FIRRTL regression tests due to known failures. arraycells.v inst id[0] of +defvalue.sv Initial value not supported dff_different_styles.v dff_init.v Initial value not supported generate.v combinational loop hierdefparam.v inst id[0] of i2c_master_tests.v $adff +implicit_ports.v not fully initialized macros.v drops modules mem2reg.v drops modules mem_arst.v $adff @@ -12,7 +14,6 @@ memory.v $adff multiplier.v inst id[0] of muxtree.v drops modules omsp_dbg_uart.v $adff -operators.v $pow partsel.v drops modules process.v drops modules realexpr.v drops modules @@ -23,5 +24,6 @@ specify.v no code (empty module generates error subbytes.v $adff task_func.v drops modules values.v combinational loop +wandwor.v Invalid connect to an expression that is not a reference or a WritePort. vloghammer.v combinational loop wreduce.v original verilog issues ( -x where x isn't declared signed) diff --git a/tests/various/.gitignore b/tests/various/.gitignore index 7b3e8c68e..31078b298 100644 --- a/tests/various/.gitignore +++ b/tests/various/.gitignore @@ -1,2 +1,4 @@ /*.log /*.out +/write_gzip.v +/write_gzip.v.gz diff --git a/tests/various/gzip_verilog.v.gz b/tests/various/gzip_verilog.v.gz new file mode 100644 index 000000000..c52a95358 Binary files /dev/null and b/tests/various/gzip_verilog.v.gz differ diff --git a/tests/various/gzip_verilog.ys b/tests/various/gzip_verilog.ys new file mode 100644 index 000000000..870317e80 --- /dev/null +++ b/tests/various/gzip_verilog.ys @@ -0,0 +1,2 @@ +read_verilog gzip_verilog.v.gz +select -assert-any top diff --git a/tests/various/opt_expr.ys b/tests/various/opt_expr.ys new file mode 100644 index 000000000..0c61ac881 --- /dev/null +++ b/tests/various/opt_expr.ys @@ -0,0 +1,148 @@ + +read_verilog <> 4) - i; +endmodule +EOT + +hierarchy -auto-top +proc +design -save gold + +opt_expr +wreduce + +select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i + +design -stash gate + +design -import gold -as gold +design -import gate -as gate + +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter + +########## + +read_verilog <>> 4) - i; +endmodule +EOT + +hierarchy -auto-top +proc +design -save gold + +opt_expr +wreduce + +dump +select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i + +design -stash gate + +design -import gold -as gold +design -import gate -as gate + +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter diff --git a/tests/various/write_gzip.ys b/tests/various/write_gzip.ys new file mode 100644 index 000000000..030ec318e --- /dev/null +++ b/tests/various/write_gzip.ys @@ -0,0 +1,16 @@ +read -vlog2k <