3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-04-12 20:18:20 +00:00

Merge branch 'master' into firrtl_err_on_unsupported_cell

# Conflicts:
#	backends/firrtl/firrtl.cc
This commit is contained in:
Jim Lawson 2019-08-07 10:14:45 -07:00
commit 5e8a98c8fd
64 changed files with 1316 additions and 490 deletions

View file

@ -36,6 +36,7 @@ matrix:
- libboost-system-dev - libboost-system-dev
- libboost-python-dev - libboost-python-dev
- libboost-filesystem-dev - libboost-filesystem-dev
- zlib1g-dev
env: env:
- MATRIX_EVAL="CONFIG=gcc && CC=gcc-4.8 && CXX=g++-4.8" - MATRIX_EVAL="CONFIG=gcc && CC=gcc-4.8 && CXX=g++-4.8"
@ -64,6 +65,7 @@ matrix:
- libboost-system-dev - libboost-system-dev
- libboost-python-dev - libboost-python-dev
- libboost-filesystem-dev - libboost-filesystem-dev
- zlib1g-dev
env: env:
- MATRIX_EVAL="CONFIG=gcc && CC=gcc-6 && CXX=g++-6" - MATRIX_EVAL="CONFIG=gcc && CC=gcc-6 && CXX=g++-6"
@ -92,6 +94,7 @@ matrix:
- libboost-system-dev - libboost-system-dev
- libboost-python-dev - libboost-python-dev
- libboost-filesystem-dev - libboost-filesystem-dev
- zlib1g-dev
env: env:
- MATRIX_EVAL="CONFIG=gcc && CC=gcc-7 && CXX=g++-7" - MATRIX_EVAL="CONFIG=gcc && CC=gcc-7 && CXX=g++-7"
@ -121,6 +124,7 @@ matrix:
- libboost-system-dev - libboost-system-dev
- libboost-python-dev - libboost-python-dev
- libboost-filesystem-dev - libboost-filesystem-dev
- zlib1g-dev
env: env:
- MATRIX_EVAL="CONFIG=clang && CC=clang-3.8 && CXX=clang++-3.8" - MATRIX_EVAL="CONFIG=clang && CC=clang-3.8 && CXX=clang++-3.8"
@ -149,6 +153,7 @@ matrix:
- libboost-system-dev - libboost-system-dev
- libboost-python-dev - libboost-python-dev
- libboost-filesystem-dev - libboost-filesystem-dev
- zlib1g-dev
env: env:
- MATRIX_EVAL="CONFIG=clang && CC=clang-5.0 && CXX=clang++-5.0" - MATRIX_EVAL="CONFIG=clang && CC=clang-5.0 && CXX=clang++-5.0"

View file

@ -14,7 +14,11 @@ Yosys 0.9 .. Yosys 0.9-dev
- Added "synth -abc9" (experimental) - Added "synth -abc9" (experimental)
- Added "script -scriptwire - Added "script -scriptwire
- "synth_xilinx" to now infer wide multiplexers (-widemux <min> to enable) - "synth_xilinx" to now infer wide multiplexers (-widemux <min> 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 Yosys 0.8 .. Yosys 0.8-dev
-------------------------- --------------------------

View file

@ -19,6 +19,7 @@ ENABLE_VERIFIC := 0
ENABLE_COVER := 1 ENABLE_COVER := 1
ENABLE_LIBYOSYS := 0 ENABLE_LIBYOSYS := 0
ENABLE_PROTOBUF := 0 ENABLE_PROTOBUF := 0
ENABLE_ZLIB := 1
# python wrappers # python wrappers
ENABLE_PYOSYS := 0 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' # 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 # will remove the 'abc' directory and you do not want to accidentally
# delete your work on ABC.. # delete your work on ABC..
ABCREV = 62487de ABCREV = 5776ad0
ABCPULL = 1 ABCPULL = 1
ABCURL ?= https://github.com/berkeley-abc/abc ABCURL ?= https://github.com/berkeley-abc/abc
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1
@ -260,7 +261,8 @@ CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
LDLIBS := $(filter-out -lrt,$(LDLIBS)) LDLIBS := $(filter-out -lrt,$(LDLIBS))
ABCMKARGS += ARCHFLAGS="-DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w" 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 EXE = .exe
else ifeq ($(CONFIG),msys2) else ifeq ($(CONFIG),msys2)
@ -384,6 +386,12 @@ ifeq ($(ENABLE_GLOB),1)
CXXFLAGS += -DYOSYS_ENABLE_GLOB CXXFLAGS += -DYOSYS_ENABLE_GLOB
endif endif
ifeq ($(ENABLE_ZLIB),1)
CXXFLAGS += -DYOSYS_ENABLE_ZLIB
LDLIBS += -lz
endif
ifeq ($(ENABLE_TCL),1) ifeq ($(ENABLE_TCL),1)
TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')") TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')")
ifeq ($(OS), FreeBSD) ifeq ($(OS), FreeBSD)
@ -394,7 +402,7 @@ endif
ifeq ($(CONFIG),mxe) ifeq ($(CONFIG),mxe)
CXXFLAGS += -DYOSYS_ENABLE_TCL CXXFLAGS += -DYOSYS_ENABLE_TCL
LDLIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 -lz LDLIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 -lz -luserenv
else else
CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags tcl || echo -I$(TCL_INCLUDE)) -DYOSYS_ENABLE_TCL CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags tcl || echo -I$(TCL_INCLUDE)) -DYOSYS_ENABLE_TCL
ifeq ($(OS), FreeBSD) ifeq ($(OS), FreeBSD)
@ -862,9 +870,11 @@ config-mxe: clean
config-msys2: clean config-msys2: clean
echo 'CONFIG := msys2' > Makefile.conf echo 'CONFIG := msys2' > Makefile.conf
echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
config-msys2-64: clean config-msys2-64: clean
echo 'CONFIG := msys2-64' > Makefile.conf echo 'CONFIG := msys2-64' > Makefile.conf
echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
config-cygwin: clean config-cygwin: clean
echo 'CONFIG := cygwin' > Makefile.conf echo 'CONFIG := cygwin' > Makefile.conf

View file

@ -67,13 +67,13 @@ prerequisites for building yosys:
$ sudo apt-get install build-essential clang bison flex \ $ sudo apt-get install build-essential clang bison flex \
libreadline-dev gawk tcl-dev libffi-dev git \ libreadline-dev gawk tcl-dev libffi-dev git \
graphviz xdot pkg-config python3 libboost-system-dev \ 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: Similarily, on Mac OS X MacPorts or Homebrew can be used to install dependencies:
$ brew tap Homebrew/bundle && brew bundle $ brew tap Homebrew/bundle && brew bundle
$ sudo port install bison flex readline gawk libffi \ $ 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: 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: 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 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 as a source distribution for Visual Studio. Visit the Yosys download page for
@ -130,18 +130,15 @@ commands and ``help <command>`` to print details on the specified command:
yosys> help help 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: writing the design to the console in Yosys's internal format:
yosys> write_ilang yosys> write_ilang
elaborate design hierarchy:
yosys> hierarchy
convert processes (``always`` blocks) to netlist elements and perform convert processes (``always`` blocks) to netlist elements and perform
some simple optimizations: some simple optimizations:
@ -163,51 +160,26 @@ write design netlist to a new Verilog file:
yosys> write_verilog synth.v 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: or using a simple synthesis script:
$ cat synth.ys $ cat synth.ys
read_verilog tests/simple/fiedler-cooley.v read -sv tests/simple/fiedler-cooley.v
hierarchy; proc; opt; techmap; opt hierarchy -top up3down5
proc; opt; techmap; opt
write_verilog synth.v write_verilog synth.v
$ ./yosys synth.ys $ ./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 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 in the liberty file ``mycells.lib``, the following synthesis script will
synthesize for the given cell library: synthesize for the given cell library:
# read design
read -sv tests/simple/fiedler-cooley.v
hierarchy -top up3down5
# the high-level stuff # the high-level stuff
hierarchy; proc; fsm; opt; memory; opt proc; fsm; opt; memory; opt
# mapping to internal cell library # mapping to internal cell library
techmap; opt techmap; opt
@ -222,7 +194,8 @@ synthesize for the given cell library:
clean clean
If you do not have a liberty file but want to test this synthesis script, 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 Liberty file downloads for and information about free and open ASIC standard
cell libraries can be found here: cell libraries can be found here:
@ -231,20 +204,18 @@ cell libraries can be found here:
- http://www.vlsitechnology.org/synopsys/vsclib013.lib - http://www.vlsitechnology.org/synopsys/vsclib013.lib
The command ``synth`` provides a good default synthesis script (see The command ``synth`` provides a good default synthesis script (see
``help synth``). If possible a synthesis script should borrow from ``synth``. ``help synth``):
For example:
# the high-level stuff read -sv tests/simple/fiedler-cooley.v
hierarchy synth -top up3down5
synth -run coarse
# mapping to internal cells # mapping to target cells
techmap; opt -fast
dfflibmap -liberty mycells.lib dfflibmap -liberty mycells.lib
abc -liberty mycells.lib abc -liberty mycells.lib
clean 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 Unsupported Verilog-2005 Features

View file

@ -53,7 +53,7 @@ PRIVATE_NAMESPACE_BEGIN
inline int32_t to_big_endian(int32_t i32) { inline int32_t to_big_endian(int32_t i32) {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
return __builtin_bswap32(i32); return bswap32(i32);
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
return i32; return i32;
#else #else
@ -610,15 +610,15 @@ struct XAigerWriter
std::stringstream h_buffer; std::stringstream h_buffer;
auto write_h_buffer = std::bind(write_buffer, std::ref(h_buffer), std::placeholders::_1); auto write_h_buffer = std::bind(write_buffer, std::ref(h_buffer), std::placeholders::_1);
write_h_buffer(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()); 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()); 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()); 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()); 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()); write_h_buffer(box_list.size());
RTLIL::Module *holes_module = nullptr; RTLIL::Module *holes_module = nullptr;
@ -772,7 +772,7 @@ struct XAigerWriter
if (output_bits.count(b)) { if (output_bits.count(b)) {
int o = ordered_outputs.at(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; continue;
} }

View file

@ -327,6 +327,13 @@ struct BlifDumper
goto internal_cell; 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_") { if (!config->icells_mode && cell->type == "$_FF_") {
f << stringf(".latch %s %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")), f << stringf(".latch %s %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")),
cstr_init(cell->getPort("\\Q"))); cstr_init(cell->getPort("\\Q")));

View file

@ -496,7 +496,7 @@ struct BtorWorker
goto okay; goto okay;
} }
if (cell->type.in("$mux", "$_MUX_")) if (cell->type.in("$mux", "$_MUX_", "$_NMUX_"))
{ {
SigSpec sig_a = sigmap(cell->getPort("\\A")); SigSpec sig_a = sigmap(cell->getPort("\\A"));
SigSpec sig_b = sigmap(cell->getPort("\\B")); SigSpec sig_b = sigmap(cell->getPort("\\B"));
@ -511,6 +511,12 @@ struct BtorWorker
int nid = next_nid++; int nid = next_nid++;
btorf("%d ite %d %d %d %d\n", nid, sid, nid_s, nid_b, nid_a); 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); add_nid_sig(nid, sig_y);
goto okay; goto okay;
} }

View file

@ -381,10 +381,10 @@ struct FirrtlWorker
// Given an expression for a shift amount, and a maximum width, // 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. // 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; 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; int max_shift_width_bits = FIRRTL_MAX_DSH_WIDTH_ERROR - 1;
string max_shift_string = stringf("UInt<%d>(%d)", max_shift_width_bits, (1<<max_shift_width_bits) - 1); string max_shift_string = stringf("UInt<%d>(%d)", max_shift_width_bits, (1<<max_shift_width_bits) - 1);
// Deal with the difference in semantics between FIRRTL and verilog // Deal with the difference in semantics between FIRRTL and verilog
@ -422,22 +422,33 @@ struct FirrtlWorker
for (auto cell : module->cells()) for (auto cell : module->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? // Is this cell is a module instance?
if (cell->type[0] != '$') if (cell->type[0] != '$')
{ {
process_instance(cell, wire_exprs); process_instance(cell, wire_exprs);
continue; 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")) 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")); string a_expr = make_expr(cell->getPort("\\A"));
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); 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 + ")"; a_expr = "asSInt(" + a_expr + ")";
} }
@ -446,12 +457,13 @@ struct FirrtlWorker
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
} }
string primop; // Assume the FIRRTL width is a single bit.
bool always_uint = false; firrtl_width = 1;
if (cell->type == "$not") primop = "not"; if (cell->type == "$not") primop = "not";
else if (cell->type == "$neg") { else if (cell->type == "$neg") {
primop = "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") { } else if (cell->type == "$logic_not") {
primop = "eq"; primop = "eq";
a_expr = stringf("%s, UInt(0)", a_expr.c_str()); a_expr = stringf("%s, UInt(0)", a_expr.c_str());
@ -466,14 +478,12 @@ struct FirrtlWorker
else if (cell->type == "$reduce_bool") { else if (cell->type == "$reduce_bool") {
primop = "neq"; primop = "neq";
// Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand. // 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); 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()); 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()); expr = stringf("asUInt(%s)", expr.c_str());
cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), 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; 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", "$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 a_expr = make_expr(cell->getPort("\\A"));
string b_expr = make_expr(cell->getPort("\\B")); 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)); 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 + ")"; a_expr = "asSInt(" + a_expr + ")";
} // Expand the "A" operand to the result width
// Shift amount is always unsigned, and needn't be padded to result width. if (a_width < y_width) {
if (!cell->type.in("$shr", "$sshr", "$shl", "$sshl")) { a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
if (cell->parameters.at("\\B_SIGNED").as_bool()) { a_width = y_width;
b_expr = "asSInt(" + b_expr + ")";
} }
if (b_padded_width < y_width) { }
auto b_sig = cell->getPort("\\B"); // Shift amount is always unsigned, and needn't be padded to result width,
b_padded_width = y_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"); auto a_sig = cell->getPort("\\A");
if (cell->parameters.at("\\A_SIGNED").as_bool() & (cell->type == "$shr")) { if (cell->type == "$add") {
a_expr = "asUInt(" + a_expr + ")"; 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" ) { else if (cell->type == "$or" ) {
primop = "or"; primop = "or";
always_uint = true; always_uint = true;
} firrtl_width = max(a_width, b_width);
}
else if (cell->type == "$xor") { else if (cell->type == "$xor") {
primop = "xor"; primop = "xor";
always_uint = true; 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")) { else if ((cell->type == "$eq") | (cell->type == "$eqx")) {
primop = "eq"; primop = "eq";
always_uint = true; always_uint = true;
} firrtl_width = 1;
}
else if ((cell->type == "$ne") | (cell->type == "$nex")) { else if ((cell->type == "$ne") | (cell->type == "$nex")) {
primop = "neq"; primop = "neq";
always_uint = true; always_uint = true;
} firrtl_width = 1;
}
else if (cell->type == "$gt") { else if (cell->type == "$gt") {
primop = "gt"; primop = "gt";
always_uint = true; always_uint = true;
} firrtl_width = 1;
}
else if (cell->type == "$ge") { else if (cell->type == "$ge") {
primop = "geq"; primop = "geq";
always_uint = true; always_uint = true;
} firrtl_width = 1;
}
else if (cell->type == "$lt") { else if (cell->type == "$lt") {
primop = "lt"; primop = "lt";
always_uint = true; always_uint = true;
} firrtl_width = 1;
}
else if (cell->type == "$le") { else if (cell->type == "$le") {
primop = "leq"; primop = "leq";
always_uint = true; always_uint = true;
} firrtl_width = 1;
}
else if ((cell->type == "$shl") | (cell->type == "$sshl")) { else if ((cell->type == "$shl") | (cell->type == "$sshl")) {
// FIRRTL will widen the result (y) by the amount of the shift. // 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. // 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"); auto b_sig = cell->getPort("\\B");
if (b_sig.is_fully_const()) { if (b_sig.is_fully_const()) {
primop = "shl"; 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 { } else {
primop = "dshl"; primop = "dshl";
// Convert from FIRRTL left shift semantics. // 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")) { else if ((cell->type == "$shr") | (cell->type == "$sshr")) {
@ -578,36 +631,86 @@ struct FirrtlWorker
auto b_sig = cell->getPort("\\B"); auto b_sig = cell->getPort("\\B");
if (b_sig.is_fully_const()) { if (b_sig.is_fully_const()) {
primop = "shr"; 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 { } else {
primop = "dshr"; 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")) { else if ((cell->type == "$logic_and")) {
primop = "and"; primop = "and";
a_expr = "neq(" + a_expr + ", UInt(0))"; a_expr = "neq(" + a_expr + ", UInt(0))";
b_expr = "neq(" + b_expr + ", UInt(0))"; b_expr = "neq(" + b_expr + ", UInt(0))";
always_uint = true; always_uint = true;
} firrtl_width = 1;
}
else if ((cell->type == "$logic_or")) { else if ((cell->type == "$logic_or")) {
primop = "or"; primop = "or";
a_expr = "neq(" + a_expr + ", UInt(0))"; a_expr = "neq(" + a_expr + ", UInt(0))";
b_expr = "neq(" + b_expr + ", UInt(0))"; b_expr = "neq(" + b_expr + ", UInt(0))";
always_uint = true; 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()) { if (!cell->parameters.at("\\B_SIGNED").as_bool()) {
b_expr = "asUInt(" + b_expr + ")"; b_expr = "asUInt(" + b_expr + ")";
} }
string expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str()); string expr;
// Deal with $xnor == ~^ (not xor)
// Deal with FIRRTL's "shift widens" semantics if (primop == "xnor") {
if (extract_y_bits) { expr = stringf("not(xor(%s, %s))", a_expr.c_str(), b_expr.c_str());
expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1); } 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()); expr = stringf("asUInt(%s)", expr.c_str());
cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), 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")) if (cell->type.in("$mux"))
{ {
string y_id = make_id(cell->name);
int width = cell->parameters.at("\\WIDTH").as_int(); int width = cell->parameters.at("\\WIDTH").as_int();
string a_expr = make_expr(cell->getPort("\\A")); string a_expr = make_expr(cell->getPort("\\A"));
string b_expr = make_expr(cell->getPort("\\B")); string b_expr = make_expr(cell->getPort("\\B"));
@ -762,15 +864,14 @@ struct FirrtlWorker
if (clkpol == false) if (clkpol == false)
log_error("Negative edge clock on FF %s.%s.\n", log_id(module), log_id(cell)); 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(); int width = cell->parameters.at("\\WIDTH").as_int();
string expr = make_expr(cell->getPort("\\D")); string expr = make_expr(cell->getPort("\\D"));
string clk_expr = "asClock(" + make_expr(cell->getPort("\\CLK")) + ")"; 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())); cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
register_reverse_wire_map(q_id, cell->getPort("\\Q")); register_reverse_wire_map(y_id, cell->getPort("\\Q"));
continue; continue;
} }
@ -785,8 +886,6 @@ struct FirrtlWorker
// assign y = a[b +: y_width]; // assign y = a[b +: y_width];
// We'll extract the correct bits as part of the primop. // 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")); string a_expr = make_expr(cell->getPort("\\A"));
// Get the initial bit selector // Get the initial bit selector
string b_expr = make_expr(cell->getPort("\\B")); string b_expr = make_expr(cell->getPort("\\B"));
@ -808,18 +907,15 @@ struct FirrtlWorker
// assign y = a >> b; // assign y = a >> b;
// where b may be negative // 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 a_expr = make_expr(cell->getPort("\\A"));
string b_expr = make_expr(cell->getPort("\\B")); string b_expr = make_expr(cell->getPort("\\B"));
auto b_string = b_expr.c_str(); auto b_string = b_expr.c_str();
int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int();
string expr; string expr;
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
if (cell->getParam("\\B_SIGNED").as_bool()) { if (cell->getParam("\\B_SIGNED").as_bool()) {
// We generate a left or right shift based on the sign of b. // 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); std::string dshr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string);
expr = stringf("mux(%s < 0, %s, %s)", expr = stringf("mux(%s < 0, %s, %s)",
b_string, b_string,
@ -833,6 +929,20 @@ struct FirrtlWorker
register_reverse_wire_map(y_id, cell->getPort("\\Y")); register_reverse_wire_map(y_id, cell->getPort("\\Y"));
continue; 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)); log_error("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
} }

View file

@ -83,20 +83,43 @@ struct JsonWriter
return str + " ]"; 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<IdString, Const> &parameters, bool for_module=false) void write_parameters(const dict<IdString, Const> &parameters, bool for_module=false)
{ {
bool first = true; bool first = true;
for (auto &param : parameters) { for (auto &param : parameters) {
f << stringf("%s\n", first ? "" : ","); f << stringf("%s\n", first ? "" : ",");
f << stringf(" %s%s: ", for_module ? "" : " ", get_name(param.first).c_str()); f << stringf(" %s%s: ", for_module ? "" : " ", get_name(param.first).c_str());
if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0) write_parameter_value(param.second);
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());
first = false; 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("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 <bit_vector>\n"); log("bits. Each individual signal bit is assigned a unique integer. The <bit_vector>\n");
log("values referenced above are vectors of this integers. Signal bits that are\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("connected to a constant driver are denoted as string \"0\", \"1\", \"x\", or\n");
log("a number.\n"); log("\"z\" instead of a number.\n");
log("\n"); log("\n");
log("Numeric parameter and attribute values up to 32 bits are written as decimal\n"); log("Numeric 32-bit parameter and attribute values are written as decimal values.\n");
log("values. Numbers larger than that are written as string holding the binary\n"); log("Bit verctors of different sizes, or ones containing 'x' or 'z' bits, are written\n");
log("representation of the value.\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("\n");
log("For example the following Verilog code:\n"); log("For example the following Verilog code:\n");
log("\n"); log("\n");

View file

@ -472,7 +472,7 @@ struct SimplecWorker
return; return;
} }
if (cell->type == "$_MUX_") if (cell->type.in("$_MUX_", "$_NMUX_"))
{ {
SigBit a = sigmaps.at(work->module)(cell->getPort("\\A")); SigBit a = sigmaps.at(work->module)(cell->getPort("\\A"));
SigBit b = sigmaps.at(work->module)(cell->getPort("\\B")); 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"; 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) // 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); log_assert(y.wire);
funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) + funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +

View file

@ -510,6 +510,7 @@ struct Smt2Worker
if (cell->type == "$_ANDNOT_") return export_gate(cell, "(and A (not B))"); 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 == "$_ORNOT_") return export_gate(cell, "(or A (not B))");
if (cell->type == "$_MUX_") return export_gate(cell, "(ite S B A)"); 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 == "$_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 == "$_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)))"); if (cell->type == "$_AOI4_") return export_gate(cell, "(not (or (and A B) (and C D)))");

View file

@ -537,6 +537,13 @@ struct SmvWorker
continue; 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_") if (cell->type == "$_AOI3_")
{ {
definitions.push_back(stringf("%s := !((%s & %s) | %s);", lvalue(cell->getPort("\\Y")), definitions.push_back(stringf("%s := !((%s & %s) | %s);", lvalue(cell->getPort("\\Y")),

View file

@ -558,6 +558,20 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
return true; 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_")) { if (cell->type.in("$_AOI3_", "$_OAI3_")) {
f << stringf("%s" "assign ", indent.c_str()); f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, cell->getPort("\\Y")); dump_sigspec(f, cell->getPort("\\Y"));

8
examples/mimas2/README Normal file
View file

@ -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

View file

@ -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 ;

14
examples/mimas2/example.v Normal file
View file

@ -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

8
examples/mimas2/run.sh Normal file
View file

@ -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

View file

@ -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

View file

@ -301,7 +301,11 @@ static uint32_t parse_xaiger_literal(std::istream &f)
uint32_t l; uint32_t l;
f.read(reinterpret_cast<char*>(&l), sizeof(l)); f.read(reinterpret_cast<char*>(&l), sizeof(l));
if (f.gcount() != sizeof(l)) if (f.gcount() != sizeof(l))
#if defined(_WIN32) && defined(__MINGW32__)
log_error("Offset %I64d: unable to read literal!\n", static_cast<int64_t>(f.tellg()));
#else
log_error("Offset %" PRId64 ": unable to read literal!\n", static_cast<int64_t>(f.tellg())); log_error("Offset %" PRId64 ": unable to read literal!\n", static_cast<int64_t>(f.tellg()));
#endif
return from_big_endian(l); return from_big_endian(l);
} }

View file

@ -3439,19 +3439,11 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
{ {
std::map<std::string, AstNode*> backup_scope; std::map<std::string, AstNode*> backup_scope;
std::map<std::string, AstNode::varinfo_t> variables; std::map<std::string, AstNode::varinfo_t> variables;
bool delete_temp_block = false; AstNode *block = new AstNode(AST_BLOCK);
AstNode *block = NULL;
size_t argidx = 0; size_t argidx = 0;
for (auto child : children) for (auto child : children)
{ {
if (child->type == AST_BLOCK)
{
log_assert(block == NULL);
block = child;
continue;
}
if (child->type == AST_WIRE) if (child->type == AST_WIRE)
{ {
while (child->simplify(true, false, false, 1, -1, false, true)) { } while (child->simplify(true, false, false, 1, -1, false, true)) { }
@ -3468,13 +3460,9 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
continue; continue;
} }
log_assert(block == NULL);
delete_temp_block = true;
block = new AstNode(AST_BLOCK);
block->children.push_back(child->clone()); block->children.push_back(child->clone());
} }
log_assert(block != NULL);
log_assert(variables.count(str) != 0); log_assert(variables.count(str) != 0);
while (!block->children.empty()) while (!block->children.empty())
@ -3642,8 +3630,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
log_abort(); log_abort();
} }
if (delete_temp_block) delete block;
delete block;
for (auto &it : backup_scope) for (auto &it : backup_scope)
if (it.second == NULL) if (it.second == NULL)

View file

@ -25,7 +25,7 @@ struct JsonNode
{ {
char type; // S=String, N=Number, A=Array, D=Dict char type; // S=String, N=Number, A=Array, D=Dict
string data_string; string data_string;
int data_number; int64_t data_number;
vector<JsonNode*> data_array; vector<JsonNode*> data_array;
dict<string, JsonNode*> data_dict; dict<string, JsonNode*> data_dict;
vector<string> data_dict_keys; vector<string> 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<IdString, Const> &results, JsonNode *node) void json_parse_attr_param(dict<IdString, Const> &results, JsonNode *node)
{ {
if (node->type != 'D') if (node->type != 'D')
@ -214,28 +246,7 @@ void json_parse_attr_param(dict<IdString, Const> &results, JsonNode *node)
for (auto it : node->data_dict) for (auto it : node->data_dict)
{ {
IdString key = RTLIL::escape_id(it.first.c_str()); IdString key = RTLIL::escape_id(it.first.c_str());
JsonNode *value_node = it.second; Const value = json_parse_attr_param_value(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();
}
results[key] = value; results[key] = value;
} }
} }

View file

@ -2484,7 +2484,7 @@ struct ReadPass : public Pass {
args[0] = "verific"; args[0] = "verific";
} else { } else {
args[0] = "read_verilog"; args[0] = "read_verilog";
args.erase(args.begin()+1, args.begin()+2); args[1] = "-defer";
} }
Pass::call(design, args); Pass::call(design, args);
return; return;
@ -2498,6 +2498,7 @@ struct ReadPass : public Pass {
if (args[1] == "-formal") if (args[1] == "-formal")
args.insert(args.begin()+1, std::string()); args.insert(args.begin()+1, std::string());
args[1] = "-sv"; args[1] = "-sv";
args.insert(args.begin()+1, "-defer");
} }
Pass::call(design, args); Pass::call(design, args);
return; return;

View file

@ -70,6 +70,9 @@ YOSYS_NAMESPACE_END
#define YY_INPUT(buf,result,max_size) \ #define YY_INPUT(buf,result,max_size) \
result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size) result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size)
#undef YY_BUF_SIZE
#define YY_BUF_SIZE 65536
%} %}
%option yylineno %option yylineno

View file

@ -325,6 +325,8 @@ Aig::Aig(Cell *cell)
int A = mk.inport("\\A", i); int A = mk.inport("\\A", i);
int B = mk.inport("\\B", i); int B = mk.inport("\\B", i);
int Y = mk.mux_gate(A, B, S); int Y = mk.mux_gate(A, B, S);
if (cell->type == "$_NMUX_")
Y = mk.not_gate(Y);
mk.outport(Y, "\\Y", i); mk.outport(Y, "\\Y", i);
} }
goto optimize; goto optimize;

View file

@ -193,6 +193,7 @@ struct CellTypes
setup_type("$_ANDNOT_", {A, B}, {Y}, true); setup_type("$_ANDNOT_", {A, B}, {Y}, true);
setup_type("$_ORNOT_", {A, B}, {Y}, true); setup_type("$_ORNOT_", {A, B}, {Y}, true);
setup_type("$_MUX_", {A, B, S}, {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("$_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("$_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); 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);

View file

@ -145,7 +145,7 @@ struct ConstEval
if (cell->hasPort("\\B")) if (cell->hasPort("\\B"))
sig_b = cell->getPort("\\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<RTLIL::SigSpec> y_candidates; std::vector<RTLIL::SigSpec> y_candidates;
int count_maybe_set_s_bits = 0; int count_maybe_set_s_bits = 0;
@ -175,7 +175,10 @@ struct ConstEval
for (auto &yc : y_candidates) { for (auto &yc : y_candidates) {
if (!eval(yc, undef, cell)) if (!eval(yc, undef, cell))
return false; 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) if (y_values.size() > 1)

View file

@ -24,62 +24,92 @@
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN
int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr); struct CellCosts
inline int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL::Const> &parameters = dict<RTLIL::IdString, RTLIL::Const>(),
RTLIL::Design *design = nullptr, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr)
{ {
static dict<RTLIL::IdString, int> gate_cost = { static const dict<RTLIL::IdString, int>& default_gate_cost() {
{ "$_BUF_", 1 }, static const dict<RTLIL::IdString, int> db = {
{ "$_NOT_", 2 }, { "$_BUF_", 1 },
{ "$_AND_", 4 }, { "$_NOT_", 2 },
{ "$_NAND_", 4 }, { "$_AND_", 4 },
{ "$_OR_", 4 }, { "$_NAND_", 4 },
{ "$_NOR_", 4 }, { "$_OR_", 4 },
{ "$_ANDNOT_", 4 }, { "$_NOR_", 4 },
{ "$_ORNOT_", 4 }, { "$_ANDNOT_", 4 },
{ "$_XOR_", 8 }, { "$_ORNOT_", 4 },
{ "$_XNOR_", 8 }, { "$_XOR_", 5 },
{ "$_AOI3_", 6 }, { "$_XNOR_", 5 },
{ "$_OAI3_", 6 }, { "$_AOI3_", 6 },
{ "$_AOI4_", 8 }, { "$_OAI3_", 6 },
{ "$_OAI4_", 8 }, { "$_AOI4_", 7 },
{ "$_MUX_", 4 } { "$_OAI4_", 7 },
}; { "$_MUX_", 4 },
{ "$_NMUX_", 4 }
if (gate_cost.count(type)) };
return gate_cost.at(type); return db;
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<RTLIL::IdString, int> 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;
} }
log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(type), GetSize(parameters)); static const dict<RTLIL::IdString, int>& cmos_gate_cost() {
return 1; static const dict<RTLIL::IdString, int> 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<RTLIL::IdString, int> *mod_cost_cache) dict<RTLIL::IdString, int> mod_cost_cache;
{ const dict<RTLIL::IdString, int> *gate_cost = nullptr;
return get_cell_cost(cell->type, cell->parameters, cell->module->design, mod_cost_cache); 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 YOSYS_NAMESPACE_END

View file

@ -522,6 +522,12 @@ int main(int argc, char **argv)
if (!backend_command.empty()) if (!backend_command.empty())
run_backend(output_filename, backend_command); 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()) if (!depsfile.empty())
{ {
FILE *f = fopen(depsfile.c_str(), "wt"); FILE *f = fopen(depsfile.c_str(), "wt");

View file

@ -25,6 +25,65 @@
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
#ifdef YOSYS_ENABLE_ZLIB
#include <zlib.h>
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<void *>(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<const void *>(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 YOSYS_NAMESPACE_BEGIN
#define MAX_REG_COUNT 1000 #define MAX_REG_COUNT 1000
@ -236,8 +295,6 @@ void Pass::call(RTLIL::Design *design, std::vector<std::string> args)
pass_register[args[0]]->post_execute(state); pass_register[args[0]]->post_execute(state);
while (design->selection_stack.size() > orig_sel_stack_pos) while (design->selection_stack.size() > orig_sel_stack_pos)
design->selection_stack.pop_back(); design->selection_stack.pop_back();
design->check();
} }
void Pass::call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::string command) 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()); log(" %s\n", command.c_str());
else else
log(" %s %s\n", command.c_str(), info.c_str()); log(" %s %s\n", command.c_str(), info.c_str());
} else } else {
Pass::call(active_design, command); Pass::call(active_design, command);
active_design->check();
}
} }
void ScriptPass::run_script(RTLIL::Design *design, std::string run_from, std::string run_to) 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<s
delete ff; delete ff;
else else
f = ff; f = ff;
if (f != NULL) {
// Check for gzip magic
unsigned char magic[3];
int n = readsome(*ff, reinterpret_cast<char*>(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) if (f == NULL)
log_cmd_error("Can't open input file `%s' for reading: %s\n", filename.c_str(), strerror(errno)); 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); args.push_back(filename);
frontend_register[args[0]]->execute(args, design); frontend_register[args[0]]->execute(args, design);
} }
design->check();
} }
Backend::Backend(std::string name, std::string short_help) : Backend::Backend(std::string name, std::string short_help) :
@ -546,14 +625,28 @@ void Backend::extra_args(std::ostream *&f, std::string &filename, std::vector<st
filename = arg; filename = arg;
rewrite_filename(filename); rewrite_filename(filename);
std::ofstream *ff = new std::ofstream; if (filename.size() > 3 && filename.substr(filename.size()-3) == ".gz") {
ff->open(filename.c_str(), std::ofstream::trunc); #ifdef YOSYS_ENABLE_ZLIB
yosys_output_files.insert(filename); gzip_ostream *gf = new gzip_ostream;
if (ff->fail()) { if (!gf->open(filename)) {
delete ff; delete gf;
log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno)); 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) 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) while (design->selection_stack.size() > orig_sel_stack_pos)
design->selection_stack.pop_back(); design->selection_stack.pop_back();
design->check();
} }
static struct CellHelpMessages { static struct CellHelpMessages {

View file

@ -1249,6 +1249,7 @@ namespace {
if (cell->type == "$_ANDNOT_") { check_gate("ABY"); return; } if (cell->type == "$_ANDNOT_") { check_gate("ABY"); return; }
if (cell->type == "$_ORNOT_") { check_gate("ABY"); return; } if (cell->type == "$_ORNOT_") { check_gate("ABY"); return; }
if (cell->type == "$_MUX_") { check_gate("ABSY"); 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 == "$_AOI3_") { check_gate("ABCY"); return; }
if (cell->type == "$_OAI3_") { check_gate("ABCY"); return; } if (cell->type == "$_OAI3_") { check_gate("ABCY"); return; }
if (cell->type == "$_AOI4_") { check_gate("ABCDY"); 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(AndnotGate, "$_ANDNOT_", A, B, Y)
DEF_METHOD_3(OrnotGate, "$_ORNOT_", A, B, Y) DEF_METHOD_3(OrnotGate, "$_ORNOT_", A, B, Y)
DEF_METHOD_4(MuxGate, "$_MUX_", A, B, S, 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(Aoi3Gate, "$_AOI3_", A, B, C, Y)
DEF_METHOD_4(Oai3Gate, "$_OAI3_", A, B, C, Y) DEF_METHOD_4(Oai3Gate, "$_OAI3_", A, B, C, Y)
DEF_METHOD_5(Aoi4Gate, "$_AOI4_", A, B, C, D, Y) DEF_METHOD_5(Aoi4Gate, "$_AOI4_", A, B, C, D, Y)

View file

@ -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. // It maintains a reference counter that is used to make sure that the container is not modified while being iterated over.
template<typename T> template<typename T>
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<RTLIL::IdString, T>::iterator it; typename dict<RTLIL::IdString, T>::iterator it;
dict<RTLIL::IdString, T> *list_p; dict<RTLIL::IdString, T> *list_p;
int *refcount_p; int *refcount_p;
@ -474,13 +478,25 @@ namespace RTLIL
return it != other.it; return it != other.it;
} }
inline void operator++() {
inline bool operator==(const RTLIL::ObjIterator<T> &other) const {
return !(*this != other);
}
inline ObjIterator<T>& operator++() {
log_assert(list_p != nullptr); log_assert(list_p != nullptr);
if (++it == list_p->end()) { if (++it == list_p->end()) {
(*refcount_p)--; (*refcount_p)--;
list_p = nullptr; list_p = nullptr;
refcount_p = nullptr; refcount_p = nullptr;
} }
return *this;
}
inline const ObjIterator<T> operator++(int) {
ObjIterator<T> 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 RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const;
RTLIL::SigSpec extract(const pool<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other = NULL) const; RTLIL::SigSpec extract(const pool<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other = NULL) const;
RTLIL::SigSpec extract(int offset, int length = 1) 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(const RTLIL::SigSpec &signal);
void append_bit(const RTLIL::SigBit &bit); void append_bit(const RTLIL::SigBit &bit);
@ -818,6 +835,7 @@ public:
operator std::vector<RTLIL::SigChunk>() const { return chunks(); } operator std::vector<RTLIL::SigChunk>() const { return chunks(); }
operator std::vector<RTLIL::SigBit>() const { return bits(); } operator std::vector<RTLIL::SigBit>() 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_; }; 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* 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* 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* 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* 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* 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 = ""); 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 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 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 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 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 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 = ""); 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 = "");

View file

@ -475,7 +475,7 @@ struct SatGen
return true; return true;
} }
if (cell->type == "$_MUX_" || cell->type == "$mux") if (cell->type == "$_MUX_" || cell->type == "$mux" || cell->type == "$_NMUX_")
{ {
std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
@ -483,7 +483,10 @@ struct SatGen
std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; std::vector<int> 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) if (model_undef)
{ {

View file

@ -894,23 +894,26 @@ void run_frontend(std::string filename, std::string command, std::string *backen
design = yosys_design; design = yosys_design;
if (command == "auto") { 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"; 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"; 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"; 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"; 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"; 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"; 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"; 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"; 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"; command = "tcl";
else if (filename == "-") else if (filename == "-")
command = "script"; command = "script";
@ -961,14 +964,18 @@ void run_frontend(std::string filename, std::string command, std::string *backen
command += next_line; command += next_line;
} }
handle_label(command, from_to_active, run_from, run_to); handle_label(command, from_to_active, run_from, run_to);
if (from_to_active) if (from_to_active) {
Pass::call(design, command); Pass::call(design, command);
design->check();
}
} }
if (!command.empty()) { if (!command.empty()) {
handle_label(command, from_to_active, run_from, run_to); handle_label(command, from_to_active, run_from, run_to);
if (from_to_active) if (from_to_active) {
Pass::call(design, command); Pass::call(design, command);
design->check();
}
} }
} }
catch (...) { catch (...) {
@ -997,6 +1004,7 @@ void run_frontend(std::string filename, std::string command, std::string *backen
Pass::call(design, vector<string>({command, filename})); Pass::call(design, vector<string>({command, filename}));
else else
Frontend::frontend_call(design, NULL, filename, command); Frontend::frontend_call(design, NULL, filename, command);
design->check();
} }
void run_frontend(std::string filename, std::string command, RTLIL::Design *design) 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(); design->selection_stack.pop_back();
log_reset_stack(); log_reset_stack();
} }
design->check();
} }
if (command == NULL) if (command == NULL)
printf("exit\n"); printf("exit\n");

View file

@ -52,6 +52,7 @@
#include <stdexcept> #include <stdexcept>
#include <memory> #include <memory>
#include <cmath> #include <cmath>
#include <cstddef>
#include <sstream> #include <sstream>
#include <fstream> #include <fstream>
@ -87,6 +88,10 @@ extern int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName);
extern void Tcl_Finalize(void); extern void Tcl_Finalize(void);
extern int Tcl_GetCommandInfo(Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr); extern int Tcl_GetCommandInfo(Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr);
extern const char *Tcl_GetStringResult(Tcl_Interp *interp); 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
#endif #endif

View file

@ -494,6 +494,6 @@ Add information about {\tt \$\_DFFE\_??\_}, {\tt \$\_DFFSR\_???\_}, {\tt \$\_DLA
\end{fixme} \end{fixme}
\begin{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} \end{fixme}

View file

@ -61,6 +61,7 @@ SOFTWARE. */
#include <windows.h> #include <windows.h>
#include <tchar.h> #include <tchar.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h>
int child_pid=0; int child_pid=0;
@ -338,7 +339,7 @@ int run(int argc, char **argv, int is_gui) {
if (is_gui) { if (is_gui) {
/* Use exec, we don't need to wait for the GUI to finish */ /* 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! */ return fail("Could not exec %s", ptr); /* shouldn't get here! */
} }

View file

@ -17,11 +17,10 @@
* *
*/ */
#include "kernel/register.h" #include "kernel/yosys.h"
#include "kernel/celltypes.h" #include "kernel/celltypes.h"
#include "passes/techmap/libparse.h" #include "passes/techmap/libparse.h"
#include "kernel/cost.h"
#include "kernel/log.h"
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
@ -228,21 +227,16 @@ struct statdata_t
{ {
int tran_cnt = 0; int tran_cnt = 0;
bool tran_cnt_exact = true; bool tran_cnt_exact = true;
auto &gate_costs = CellCosts::cmos_gate_cost();
for (auto it : num_cells_by_type) { for (auto it : num_cells_by_type) {
auto ctype = it.first; auto ctype = it.first;
auto cnum = it.second; auto cnum = it.second;
if (ctype == "$_NOT_") if (gate_costs.count(ctype))
tran_cnt += 2*cnum; tran_cnt += cnum * gate_costs.at(ctype);
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;
else if (ctype.in("$_DFF_P_", "$_DFF_N_")) else if (ctype.in("$_DFF_P_", "$_DFF_N_"))
tran_cnt += 16*cnum; tran_cnt += cnum * 16;
else else
tran_cnt_exact = false; tran_cnt_exact = false;
} }

View file

@ -641,6 +641,31 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
did_something = true; 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" || if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" || cell->type == "$shift" || cell->type == "$shiftx" ||

View file

@ -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++) for (int arity = 1; arity <= max_arity; arity++)
{ {
if (arity_counts[arity]) if (arity_counts[arity])
@ -351,14 +351,14 @@ struct OptLutWorker
int lutM_arity = lutA_arity + lutB_arity - 1 - common_inputs.size(); int lutM_arity = lutA_arity + lutB_arity - 1 - common_inputs.size();
if (lutA_dlogic_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 else
log_debug(" Cell A is a %d-LUT. ", lutA_arity); log_debug(" Cell A is a %d-LUT. ", lutA_arity);
if (lutB_dlogic_inputs.size()) 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 else
log_debug("Cell B is a %d-LUT.\n", lutB_arity); 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; const int COMBINE_A = 1, COMBINE_B = 2, COMBINE_EITHER = COMBINE_A | COMBINE_B;
int combine_mask = 0; int combine_mask = 0;

View file

@ -171,7 +171,7 @@ struct RmportsPassPass : public Pass {
wire->port_output = false; wire->port_output = false;
wire->port_id = 0; 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 // Re-number all of the wires that DO have ports still on them
for(size_t i=0; i<module->ports.size(); i++) for(size_t i=0; i<module->ports.size(); i++)

View file

@ -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; int a_size = 0, b_size = 0;
if (cell->hasPort("\\A")) a_size = GetSize(cell->getPort("\\A")); 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); int max_y_size = max(a_size, b_size);
if (cell->type == "$add") if (cell->type.in("$add", "$sub"))
max_y_size++; max_y_size++;
if (cell->type == "$mul") if (cell->type == "$mul")

View file

@ -82,14 +82,23 @@ struct PruneWorker
if (root) { if (root) {
bool promotable = true; bool promotable = true;
for (auto &bit : lhs) { for (auto &bit : lhs) {
if (bit.wire && affected[bit]) { if (bit.wire && affected[bit] && !assigned[bit]) {
promotable = false; promotable = false;
break; break;
} }
} }
if (promotable) { 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++; promoted_count++;
module->connect(*it); module->connect(conn);
remove.insert(*it); remove.insert(*it);
} }
} }

View file

@ -49,6 +49,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <cctype>
#include <cerrno> #include <cerrno>
#include <sstream> #include <sstream>
#include <climits> #include <climits>
@ -81,6 +82,7 @@ enum class gate_type_t {
G_ANDNOT, G_ANDNOT,
G_ORNOT, G_ORNOT,
G_MUX, G_MUX,
G_NMUX,
G_AOI3, G_AOI3,
G_OAI3, G_OAI3,
G_AOI4, G_AOI4,
@ -111,7 +113,7 @@ std::vector<gate_t> signal_list;
std::map<RTLIL::SigBit, int> signal_map; std::map<RTLIL::SigBit, int> signal_map;
std::map<RTLIL::SigBit, RTLIL::State> signal_init; std::map<RTLIL::SigBit, RTLIL::State> signal_init;
pool<std::string> enabled_gates; pool<std::string> enabled_gates;
bool recover_init; bool recover_init, cmos_cost;
bool clk_polarity, en_polarity; bool clk_polarity, en_polarity;
RTLIL::SigSpec clk_sig, en_sig; RTLIL::SigSpec clk_sig, en_sig;
@ -257,7 +259,7 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
return; return;
} }
if (cell->type == "$_MUX_") if (cell->type.in("$_MUX_", "$_NMUX_"))
{ {
RTLIL::SigSpec sig_a = cell->getPort("\\A"); RTLIL::SigSpec sig_a = cell->getPort("\\A");
RTLIL::SigSpec sig_b = cell->getPort("\\B"); 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_b = map_signal(sig_b);
int mapped_s = map_signal(sig_s); 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); module->remove(cell);
return; 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, ".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, "1-0 1\n");
fprintf(f, "-11 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)) { } 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, ".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"); 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"); 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()); buffer = stringf("%s/stdcells.genlib", tempdir_name.c_str());
f = fopen(buffer.c_str(), "wt"); f = fopen(buffer.c_str(), "wt");
if (f == NULL) if (f == NULL)
log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno)); 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 ZERO 1 Y=CONST0;\n");
fprintf(f, "GATE ONE 1 Y=CONST1;\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 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", get_cell_cost("$_NOT_")); 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")) 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")) 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")) 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")) 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")) 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")) 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")) 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")) 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")) 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")) 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")) 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")) 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")) 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) 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) 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) 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); fclose(f);
if (!lut_costs.empty()) { if (!lut_costs.empty()) {
@ -1065,8 +1075,8 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
design->select(module, cell); design->select(module, cell);
continue; continue;
} }
if (c->type == "\\MUX") { if (c->type == "\\MUX" || c->type == "\\NMUX") {
RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_MUX_"); RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx; if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)])); 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)])); 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("\n");
log(" The following aliases can be used to reference common sets of gate types:\n"); log(" The following aliases can be used to reference common sets of gate types:\n");
log(" simple: AND OR XOR MUX\n"); log(" simple: AND OR XOR MUX\n");
log(" cmos2: NAND NOR\n"); log(" cmos2: NAND NOR\n");
log(" cmos3: NAND NOR AOI3 OAI3\n"); log(" cmos3: NAND NOR AOI3 OAI3\n");
log(" cmos4: NAND NOR AOI3 OAI3 AOI4 OAI4\n"); log(" cmos4: NAND NOR AOI3 OAI3 AOI4 OAI4\n");
log(" gates: AND NAND OR NOR XOR XNOR ANDNOT ORNOT\n"); log(" cmos: NAND NOR AOI3 OAI3 AOI4 OAI4 NMUX MUX XOR XNOR\n");
log(" aig: AND NAND OR NOR ANDNOT ORNOT\n"); log(" gates: AND NAND OR NOR XOR XNOR ANDNOT ORNOT\n");
log(" aig: AND NAND OR NOR ANDNOT ORNOT\n");
log("\n"); log("\n");
log(" Prefix a gate type with a '-' to remove it from the list. For example\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"); log(" the arguments 'AND,OR,XOR' and 'simple,-MUX' are equivalent.\n");
@ -1488,6 +1499,7 @@ struct AbcPass : public Pass {
map_mux8 = false; map_mux8 = false;
map_mux16 = false; map_mux16 = false;
enabled_gates.clear(); enabled_gates.clear();
cmos_cost = false;
#ifdef _WIN32 #ifdef _WIN32
#ifndef ABCEXTERNAL #ifndef ABCEXTERNAL
@ -1628,11 +1640,15 @@ struct AbcPass : public Pass {
goto ok_alias; goto ok_alias;
} }
if (g == "cmos2") { if (g == "cmos2") {
if (!remove_gates)
cmos_cost = true;
gate_list.push_back("NAND"); gate_list.push_back("NAND");
gate_list.push_back("NOR"); gate_list.push_back("NOR");
goto ok_alias; goto ok_alias;
} }
if (g == "cmos3") { if (g == "cmos3") {
if (!remove_gates)
cmos_cost = true;
gate_list.push_back("NAND"); gate_list.push_back("NAND");
gate_list.push_back("NOR"); gate_list.push_back("NOR");
gate_list.push_back("AOI3"); gate_list.push_back("AOI3");
@ -1640,6 +1656,8 @@ struct AbcPass : public Pass {
goto ok_alias; goto ok_alias;
} }
if (g == "cmos4") { if (g == "cmos4") {
if (!remove_gates)
cmos_cost = true;
gate_list.push_back("NAND"); gate_list.push_back("NAND");
gate_list.push_back("NOR"); gate_list.push_back("NOR");
gate_list.push_back("AOI3"); gate_list.push_back("AOI3");
@ -1648,6 +1666,21 @@ struct AbcPass : public Pass {
gate_list.push_back("OAI4"); gate_list.push_back("OAI4");
goto ok_alias; 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") { if (g == "gates") {
gate_list.push_back("AND"); gate_list.push_back("AND");
gate_list.push_back("NAND"); gate_list.push_back("NAND");

View file

@ -86,7 +86,7 @@ struct ExtractFaWorker
for (auto cell : module->selected_cells()) for (auto cell : module->selected_cells())
{ {
if (cell->type.in( "$_BUF_", "$_NOT_", "$_AND_", "$_NAND_", "$_OR_", "$_NOR_", 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_")) "$_AOI3_", "$_OAI3_", "$_AOI4_", "$_OAI4_"))
{ {
SigBit y = sigmap(SigBit(cell->getPort("\\Y"))); SigBit y = sigmap(SigBit(cell->getPort("\\Y")));

View file

@ -783,7 +783,7 @@ struct FlowmapWorker
int depth = 0; int depth = 0;
for (auto label : labels) for (auto label : labels)
depth = max(depth, label.second); 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) if (debug)
{ {
@ -1195,7 +1195,7 @@ struct FlowmapWorker
bool relax_depth_for_bound(bool first, int depth_bound, dict<RTLIL::SigBit, pool<RTLIL::SigBit>> &lut_critical_outputs) bool relax_depth_for_bound(bool first, int depth_bound, dict<RTLIL::SigBit, pool<RTLIL::SigBit>> &lut_critical_outputs)
{ {
size_t initial_count = lut_nodes.size(); int initial_count = GetSize(lut_nodes);
for (auto node : lut_nodes) for (auto node : lut_nodes)
{ {
@ -1215,7 +1215,7 @@ struct FlowmapWorker
if (potentials.empty()) 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) if (!first && break_num == 1)
{ {
log(" Design fully relaxed.\n"); log(" Design fully relaxed.\n");
@ -1419,9 +1419,9 @@ struct FlowmapWorker
lut_area += lut_table.size(); lut_area += lut_table.size();
if ((int)input_nodes.size() >= minlut) 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 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) for (auto node : mapped_nodes)

View file

@ -50,7 +50,7 @@ struct AnlogicDetermineInitPass : public Pass {
extra_args(args, args.size(), design); extra_args(args, args.size(), design);
size_t cnt = 0; int cnt = 0;
for (auto module : design->selected_modules()) for (auto module : design->selected_modules())
{ {
for (auto cell : module->selected_cells()) 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; } AnlogicDetermineInitPass;

View file

@ -69,7 +69,7 @@ struct AnlogicEqnPass : public Pass {
extra_args(args, args.size(), design); extra_args(args, args.size(), design);
size_t cnt = 0; int cnt = 0;
for (auto module : design->selected_modules()) for (auto module : design->selected_modules())
{ {
for (auto cell : module->selected_cells()) 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; } AnlogicEqnPass;

View file

@ -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] AA = A_buf;
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
wire [Y_WIDTH+1:0] COx; wire [Y_WIDTH+1:0] COx;
wire [Y_WIDTH+1:0] C = {COx, CI}; wire [Y_WIDTH+2:0] C = {COx, CI};
wire dummy; wire dummy;
(* keep *)
AL_MAP_ADDER #( AL_MAP_ADDER #(
.ALUTYPE("ADD_CARRY")) .ALUTYPE("ADD_CARRY"))
adder_cin ( adder_cin (
@ -55,19 +54,6 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO);
genvar i; genvar i;
generate for (i = 0; i < Y_WIDTH; i = i + 1) begin: slice 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 #( AL_MAP_ADDER #(
.ALUTYPE("ADD") .ALUTYPE("ADD")
) adder_i ( ) adder_i (
@ -76,9 +62,15 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO);
.c(C[i+1]), .c(C[i+1]),
.o({COx[i+1],Y[i]}) .o({COx[i+1],Y[i]})
); );
end
end: slice end: slice
endgenerate endgenerate
/* End implementation */ /* 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; assign X = AA ^ BB;
endmodule endmodule

View file

@ -228,6 +228,25 @@ output Y;
assign Y = S ? B : A; assign Y = S ? B : A;
endmodule 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---| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
//- //-
//- $_MUX4_ (A, B, C, D, S, T, Y) //- $_MUX4_ (A, B, C, D, S, T, Y)

View file

@ -333,6 +333,31 @@ module TRELLIS_SLICE(
parameter [127:0] CCU2_INJECT1_0 = "NO"; parameter [127:0] CCU2_INJECT1_0 = "NO";
parameter [127:0] CCU2_INJECT1_1 = "NO"; parameter [127:0] CCU2_INJECT1_1 = "NO";
parameter WREMUX = "WRE"; 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; function [15:0] permute_initval;
input [15:0] initval; input [15:0] initval;
@ -350,13 +375,13 @@ module TRELLIS_SLICE(
LUT4 #( LUT4 #(
.INIT(LUT0_INITVAL) .INIT(LUT0_INITVAL)
) lut4_0 ( ) lut4_0 (
.A(A0), .B(B0), .C(C0), .D(D0), .A(A0m), .B(B0m), .C(C0m), .D(D0m),
.Z(F0) .Z(F0)
); );
LUT4 #( LUT4 #(
.INIT(LUT1_INITVAL) .INIT(LUT1_INITVAL)
) lut4_1 ( ) lut4_1 (
.A(A1), .B(B1), .C(C1), .D(D1), .A(A1m), .B(B1m), .C(C1m), .D(D1m),
.Z(F1) .Z(F1)
); );
// LUT expansion muxes // LUT expansion muxes
@ -370,20 +395,20 @@ module TRELLIS_SLICE(
.INJECT1_1(CCU2_INJECT1_1) .INJECT1_1(CCU2_INJECT1_1)
) ccu2c_i ( ) ccu2c_i (
.CIN(FCI), .CIN(FCI),
.A0(A0), .B0(B0), .C0(C0), .D0(D0), .A0(A0m), .B0(B0m), .C0(C0m), .D0(D0m),
.A1(A1), .B1(B1), .C1(C1), .D1(D1), .A1(A1m), .B1(B1m), .C1(C1m), .D1(D1m),
.S0(F0), .S1(F1), .S0(F0), .S1(F1),
.COUT(FCO) .COUT(FCO)
); );
end else if (MODE == "RAMW") begin end else if (MODE == "RAMW") begin
assign WDO0 = C1; assign WDO0 = C1m;
assign WDO1 = A1; assign WDO1 = A1m;
assign WDO2 = D1; assign WDO2 = D1m;
assign WDO3 = B1; assign WDO3 = B1m;
assign WADO0 = D0; assign WADO0 = D0m;
assign WADO1 = B0; assign WADO1 = B0m;
assign WADO2 = C0; assign WADO2 = C0m;
assign WADO3 = A0; assign WADO3 = A0m;
end else if (MODE == "DPRAM") begin end else if (MODE == "DPRAM") begin
TRELLIS_RAM16X2 #( TRELLIS_RAM16X2 #(
.INITVAL_0(permute_initval(LUT0_INITVAL)), .INITVAL_0(permute_initval(LUT0_INITVAL)),
@ -393,17 +418,19 @@ module TRELLIS_SLICE(
.DI0(WD0), .DI1(WD1), .DI0(WD0), .DI1(WD1),
.WAD0(WAD0), .WAD1(WAD1), .WAD2(WAD2), .WAD3(WAD3), .WAD0(WAD0), .WAD1(WAD1), .WAD2(WAD2), .WAD3(WAD3),
.WRE(WRE), .WCK(WCK), .WRE(WRE), .WCK(WCK),
.RAD0(D0), .RAD1(B0), .RAD2(C0), .RAD3(A0), .RAD0(D0m), .RAD1(B0m), .RAD2(C0m), .RAD3(A0m),
.DO0(F0), .DO1(F1) .DO0(F0), .DO1(F1)
); );
// TODO: confirm RAD and INITVAL ordering // TODO: confirm RAD and INITVAL ordering
// DPRAM mode contract? // DPRAM mode contract?
`ifdef FORMAL
always @(*) begin always @(*) begin
assert(A0==A1); assert(A0m==A1m);
assert(B0==B1); assert(B0m==B1m);
assert(C0==C1); assert(C0m==C1m);
assert(D0==D1); assert(D0m==D1m);
end end
`endif
end else begin end else begin
ERROR_UNKNOWN_SLICE_MODE error(); ERROR_UNKNOWN_SLICE_MODE error();
end end
@ -455,90 +482,206 @@ module DP16KD(
input CSB2, CSB1, CSB0, input CSB2, CSB1, CSB0,
output DOB17, DOB16, DOB15, DOB14, DOB13, DOB12, DOB11, DOB10, DOB9, DOB8, DOB7, DOB6, DOB5, DOB4, DOB3, DOB2, DOB1, DOB0 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_A = 18;
parameter DATA_WIDTH_B = 18; parameter DATA_WIDTH_B = 18;
parameter REGMODE_A = "NOREG"; parameter REGMODE_A = "NOREG";
parameter REGMODE_B = "NOREG"; parameter REGMODE_B = "NOREG";
parameter RESETMODE = "SYNC"; parameter RESETMODE = "SYNC";
parameter ASYNC_RESET_RELEASE = "SYNC"; parameter ASYNC_RESET_RELEASE = "SYNC";
parameter CSDECODE_A = "0b000"; parameter CSDECODE_A = "0b000";
parameter CSDECODE_B = "0b000"; parameter CSDECODE_B = "0b000";
parameter WRITEMODE_A = "NORMAL"; parameter WRITEMODE_A = "NORMAL";
parameter WRITEMODE_B = "NORMAL"; parameter WRITEMODE_B = "NORMAL";
parameter CLKAMUX = "CLKA"; parameter DIA17MUX = "DIA17";
parameter CLKBMUX = "CLKB"; 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 GSR = "ENABLED";
parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_20 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_21 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_22 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_20 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_23 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_21 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_24 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_22 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_25 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_23 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_26 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_24 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_27 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_25 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_28 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_26 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_29 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_27 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_2A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_28 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_2B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_29 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_2C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_2A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_2D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_2B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_2E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_2C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_2F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_2D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_30 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_2E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_31 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_2F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_32 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_30 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_33 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_31 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_34 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_32 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_35 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_33 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_36 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_34 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_37 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_35 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_38 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_36 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_39 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_37 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_3A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_38 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_3B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_39 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_3C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_3A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_3D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_3B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_3C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_3D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
endmodule endmodule
// TODO: Diamond flip-flops // TODO: Diamond flip-flops

View file

@ -50,7 +50,7 @@ struct DetermineInitPass : public Pass {
extra_args(args, args.size(), design); extra_args(args, args.size(), design);
size_t cnt = 0; int cnt = 0;
for (auto module : design->selected_modules()) for (auto module : design->selected_modules())
{ {
for (auto cell : module->selected_cells()) 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; } DetermineInitPass;

View file

@ -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/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/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_m9k.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_map_m9k.v))
$(eval $(call add_share_file,share/intel/max10,techlibs/intel/max10/cells_sim.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/a10gx,techlibs/intel/a10gx/cells_sim.v))
$(eval $(call add_share_file,share/intel/cyclonev,techlibs/intel/cyclonev/cells_sim.v)) $(eval $(call add_share_file,share/intel/cyclonev,techlibs/intel/cyclonev/cells_sim.v))

View file

@ -61,8 +61,8 @@ struct SynthIntelPass : public ScriptPass {
log(" from label is synonymous to 'begin', and empty to label is\n"); log(" from label is synonymous to 'begin', and empty to label is\n");
log(" synonymous to the end of the command list.\n"); log(" synonymous to the end of the command list.\n");
log("\n"); log("\n");
log(" -noiopads\n"); log(" -iopads\n");
log(" do not use IO pad cells in output netlist\n"); log(" use IO pad cells in output netlist\n");
log("\n"); log("\n");
log(" -nobram\n"); log(" -nobram\n");
log(" do not use block RAM cells in output netlist\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; string top_opt, family_opt, vout_file, blif_file;
bool retime, flatten, nobram, noiopads; bool retime, flatten, nobram, iopads;
void clear_flags() YS_OVERRIDE void clear_flags() YS_OVERRIDE
{ {
@ -90,7 +90,7 @@ struct SynthIntelPass : public ScriptPass {
retime = false; retime = false;
flatten = true; flatten = true;
nobram = false; nobram = false;
noiopads = false; iopads = false;
} }
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@ -125,8 +125,8 @@ struct SynthIntelPass : public ScriptPass {
run_to = args[argidx].substr(pos + 1); run_to = args[argidx].substr(pos + 1);
continue; continue;
} }
if (args[argidx] == "-noiopads") { if (args[argidx] == "-iopads") {
noiopads = true; iopads = true;
continue; continue;
} }
if (args[argidx] == "-nobram") { if (args[argidx] == "-nobram") {
@ -187,8 +187,15 @@ struct SynthIntelPass : public ScriptPass {
} }
if (!nobram && check_label("map_bram", "(skip if -nobram)")) { if (!nobram && check_label("map_bram", "(skip if -nobram)")) {
run("memory_bram -rules +/intel/common/brams.txt"); if (family_opt == "cycloneiv" ||
run("techmap -map +/intel/common/brams_map.v"); 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")) { if (check_label("map_ffram")) {
@ -215,10 +222,9 @@ struct SynthIntelPass : public ScriptPass {
} }
if (check_label("map_cells")) { if (check_label("map_cells")) {
if (!noiopads) if (iopads || help_mode)
run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)"); 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(stringf("techmap -map +/intel/%s/cells_map.v", family_opt.c_str()));
run("dffinit -highlow -ff dffeas q power_up"); run("dffinit -highlow -ff dffeas q power_up");
run("clean -purge"); run("clean -purge");
} }

View file

@ -24,9 +24,9 @@ module _90_dff_nn0_to_np0 (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLA
(* techmap_celltype = "$_DFF_PN0_" *) (* 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 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_" *) (* 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_" *) (* 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); module \$__SHREG_ (input C, input D, input E, output Q);
parameter DEPTH = 0; parameter DEPTH = 0;

View file

@ -52,7 +52,7 @@ module \$__XILINX_RAMB8BWER_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DAT
.CLKBRDCLK(CLK2 ^ !CLKPOL2), .CLKBRDCLK(CLK2 ^ !CLKPOL2),
.ENBRDEN(A1EN), .ENBRDEN(A1EN),
.REGCEBREGCE(|1), .REGCEBREGCE(|1),
.RSTB(|0) .RSTBRST(|0)
); );
endmodule endmodule
@ -217,7 +217,7 @@ module \$__XILINX_RAMB8BWER_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DAT
.CLKBRDCLK(CLK3 ^ !CLKPOL3), .CLKBRDCLK(CLK3 ^ !CLKPOL3),
.ENBRDEN(|1), .ENBRDEN(|1),
.REGCEBREGCE(|0), .REGCEBREGCE(|0),
.RSTB(|0), .RSTBRST(|0),
.WEBWEU(B1EN_2) .WEBWEU(B1EN_2)
); );
end else begin end else begin
@ -248,7 +248,7 @@ module \$__XILINX_RAMB8BWER_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DAT
.CLKBRDCLK(CLK3 ^ !CLKPOL3), .CLKBRDCLK(CLK3 ^ !CLKPOL3),
.ENBRDEN(|1), .ENBRDEN(|1),
.REGCEBREGCE(|0), .REGCEBREGCE(|0),
.RSTB(|0), .RSTBRST(|0),
.WEBWEU(B1EN_2) .WEBWEU(B1EN_2)
); );
end endgenerate end endgenerate

View file

@ -1,10 +1,12 @@
# This file contains the names of verilog files to exclude from verilog to FIRRTL regression tests due to known failures. # 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 arraycells.v inst id[0] of
defvalue.sv Initial value not supported
dff_different_styles.v dff_different_styles.v
dff_init.v Initial value not supported dff_init.v Initial value not supported
generate.v combinational loop generate.v combinational loop
hierdefparam.v inst id[0] of hierdefparam.v inst id[0] of
i2c_master_tests.v $adff i2c_master_tests.v $adff
implicit_ports.v not fully initialized
macros.v drops modules macros.v drops modules
mem2reg.v drops modules mem2reg.v drops modules
mem_arst.v $adff mem_arst.v $adff
@ -12,7 +14,6 @@ memory.v $adff
multiplier.v inst id[0] of multiplier.v inst id[0] of
muxtree.v drops modules muxtree.v drops modules
omsp_dbg_uart.v $adff omsp_dbg_uart.v $adff
operators.v $pow
partsel.v drops modules partsel.v drops modules
process.v drops modules process.v drops modules
realexpr.v drops modules realexpr.v drops modules
@ -23,5 +24,6 @@ specify.v no code (empty module generates error
subbytes.v $adff subbytes.v $adff
task_func.v drops modules task_func.v drops modules
values.v combinational loop values.v combinational loop
wandwor.v Invalid connect to an expression that is not a reference or a WritePort.
vloghammer.v combinational loop vloghammer.v combinational loop
wreduce.v original verilog issues ( -x where x isn't declared signed) wreduce.v original verilog issues ( -x where x isn't declared signed)

View file

@ -1,2 +1,4 @@
/*.log /*.log
/*.out /*.out
/write_gzip.v
/write_gzip.v.gz

Binary file not shown.

View file

@ -0,0 +1,2 @@
read_verilog gzip_verilog.v.gz
select -assert-any top

148
tests/various/opt_expr.ys Normal file
View file

@ -0,0 +1,148 @@
read_verilog <<EOT
module opt_expr_add_test(input [3:0] i, input [7:0] j, output [8:0] o);
assign o = (i << 4) + j;
endmodule
EOT
hierarchy -auto-top
proc
design -save gold
opt_expr -fine
wreduce
select -assert-count 1 t:$add 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 <<EOT
module opt_expr_add_signed_test(input signed [3:0] i, input signed [7:0] j, output signed [8:0] o);
assign o = (i << 4) + j;
endmodule
EOT
hierarchy -auto-top
proc
design -save gold
opt_expr -fine
wreduce
select -assert-count 1 t:$add 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 <<EOT
module opt_expr_sub_test1(input [3:0] i, input [7:0] j, output [8:0] o);
assign o = j - (i << 4);
endmodule
EOT
hierarchy -auto-top
proc
design -save gold
opt_expr -fine
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 <<EOT
module opt_expr_sub_signed_test1(input signed [3:0] i, input signed [7:0] j, output signed [8:0] o);
assign o = j - (i << 4);
endmodule
EOT
hierarchy -auto-top
proc
design -save gold
opt_expr -fine
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 <<EOT
module opt_expr_sub_test2(input [3:0] i, input [7:0] j, output [8:0] o);
assign o = (i << 4) - j;
endmodule
EOT
hierarchy -auto-top
proc
design -save gold
opt_expr -fine
wreduce
select -assert-count 1 t:$sub r:A_WIDTH=8 r:B_WIDTH=8 r:Y_WIDTH=9 %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 <<EOT
module opt_expr_sub_test4(input [3:0] i, output [8:0] o);
assign o = 5'b00010 - i;
endmodule
EOT
hierarchy -auto-top
proc
design -save gold
opt_expr -fine
wreduce
select -assert-count 1 t:$sub r:A_WIDTH=2 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

48
tests/various/wreduce.ys Normal file
View file

@ -0,0 +1,48 @@
read_verilog <<EOT
module wreduce_sub_test(input [3:0] i, input [7:0] j, output [8:0] o);
assign o = (j >> 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 <<EOT
module wreduce_sub_signed_test(input signed [3:0] i, input signed [7:0] j, output signed [8:0] o);
assign o = (j >>> 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

View file

@ -0,0 +1,16 @@
read -vlog2k <<EOT
module top(input a, output y);
assign y = !a;
endmodule
EOT
prep -top top
write_verilog write_gzip.v.gz
design -reset
! rm -f write_gzip.v
! gunzip write_gzip.v.gz
read -vlog2k write_gzip.v
! rm -f write_gzip.v
hierarchy -top top
select -assert-any top