This commit is contained in:
Andrew Zonenberg 2017-02-11 11:25:16 -08:00
commit 203b521a78
10 changed files with 273 additions and 58 deletions

View File

@ -53,27 +53,35 @@ all: top-all
YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST))) YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST)))
VPATH := $(YOSYS_SRC) VPATH := $(YOSYS_SRC)
CXXFLAGS += -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -D_YOSYS_ -fPIC -I$(PREFIX)/include CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -D_YOSYS_ -fPIC -I$(PREFIX)/include
LDFLAGS += -L$(LIBDIR) LDFLAGS := $(LDFLAGS) -L$(LIBDIR)
LDLIBS = -lstdc++ -lm LDLIBS := $(LDLIBS) -lstdc++ -lm
PKG_CONFIG = pkg-config PKG_CONFIG ?= pkg-config
SED = sed SED ?= sed
BISON = bison BISON ?= bison
ifeq (Darwin,$(findstring Darwin,$(shell uname))) ifeq (Darwin,$(findstring Darwin,$(shell uname)))
# add macports/homebrew include and library path to search directories, don't use '-rdynamic' and '-lrt': # homebrew search paths
CXXFLAGS += -I/opt/local/include -I/usr/local/opt/readline/include ifneq ($(shell which brew),)
LDFLAGS += -L/opt/local/lib -L/usr/local/opt/readline/lib BREW_PREFIX := $(shell brew --prefix)/opt
# add homebrew's libffi include and library path CXXFLAGS += -I$(BREW_PREFIX)/readline/include
CXXFLAGS += $(shell PKG_CONFIG_PATH=$$(brew list libffi | grep pkgconfig | xargs dirname) pkg-config --silence-errors --cflags libffi) LDFLAGS += -L$(BREW_PREFIX)/readline/lib
LDFLAGS += $(shell PKG_CONFIG_PATH=$$(brew list libffi | grep pkgconfig | xargs dirname) pkg-config --silence-errors --libs libffi) PKG_CONFIG_PATH := $(BREW_PREFIX)/libffi/lib/pkgconfig:$(PKG_CONFIG_PATH)
# use bison installed by homebrew if available PKG_CONFIG_PATH := $(BREW_PREFIX)/tcl-tk/lib/pkgconfig:$(PKG_CONFIG_PATH)
BISON = $(shell (brew list bison | grep -m1 "bin/bison") || echo bison) export PATH := $(BREW_PREFIX)/bison/bin:$(BREW_PREFIX)/gettext/bin:$(BREW_PREFIX)/flex/bin:$(PATH)
SED = sed
# macports search paths
else ifneq ($(shell which port),)
PORT_PREFIX := $(patsubst %/bin/port,%,$(shell which port))
CXXFLAGS += -I$(PORT_PREFIX)/include
LDFLAGS += -L$(PORT_PREFIX)/lib
PKG_CONFIG_PATH := $(PORT_PREFIX)/lib/pkgconfig:$(PKG_CONFIG_PATH)
export PATH := $(PORT_PREFIX)/bin:$(PATH)
endif
else else
LDFLAGS += -rdynamic LDFLAGS += -rdynamic
LDLIBS += -lrt LDLIBS += -lrt
endif endif
YOSYS_VER := 0.7+$(shell cd $(YOSYS_SRC) && test -e .git && { git log --author=clifford@clifford.at --oneline 61f6811.. | wc -l; }) YOSYS_VER := 0.7+$(shell cd $(YOSYS_SRC) && test -e .git && { git log --author=clifford@clifford.at --oneline 61f6811.. | wc -l; })
@ -210,15 +218,16 @@ endif
endif endif
ifeq ($(ENABLE_PLUGINS),1) ifeq ($(ENABLE_PLUGINS),1)
CXXFLAGS += -DYOSYS_ENABLE_PLUGINS $(shell $(PKG_CONFIG) --silence-errors --cflags libffi) CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags libffi) -DYOSYS_ENABLE_PLUGINS
LDLIBS += $(shell $(PKG_CONFIG) --silence-errors --libs libffi || echo -lffi) -ldl LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs libffi || echo -lffi) -ldl
endif 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]')")
TCL_INCLUDE ?= /usr/include/$(TCL_VERSION) TCL_INCLUDE ?= /usr/include/$(TCL_VERSION)
CXXFLAGS += -I$(TCL_INCLUDE) -DYOSYS_ENABLE_TCL
LDLIBS += -l$(TCL_VERSION) CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags tcl || echo -I$(TCL_INCLUDE)) -DYOSYS_ENABLE_TCL
LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs tcl || echo -l$(TCL_VERSION))
endif endif
ifeq ($(ENABLE_GPROF),1) ifeq ($(ENABLE_GPROF),1)

View File

@ -40,14 +40,14 @@ Web Site
More information and documentation can be found on the Yosys web site: More information and documentation can be found on the Yosys web site:
http://www.clifford.at/yosys/ http://www.clifford.at/yosys/
Setup
Getting Started ======
===============
You need a C++ compiler with C++11 support (up-to-date CLANG or GCC is You need a C++ compiler with C++11 support (up-to-date CLANG or GCC is
recommended) and some standard tools such as GNU Flex, GNU Bison, and GNU Make. recommended) and some standard tools such as GNU Flex, GNU Bison, and GNU Make.
TCL, readline and libffi are optional (see ``ENABLE_*`` settings in Makefile). TCL, readline and libffi are optional (see ``ENABLE_*`` settings in Makefile).
Xdot (graphviz) is used by the ``show`` command in yosys to display schematics. Xdot (graphviz) is used by the ``show`` command in yosys to display schematics.
For example on Ubuntu Linux 16.04 LTS the following commands will install all For example on Ubuntu Linux 16.04 LTS the following commands will install all
prerequisites for building yosys: prerequisites for building yosys:
@ -55,6 +55,13 @@ prerequisites for building yosys:
libreadline-dev gawk tcl-dev libffi-dev git mercurial \ libreadline-dev gawk tcl-dev libffi-dev git mercurial \
graphviz xdot pkg-config python3 graphviz xdot pkg-config python3
Similarily, on Mac OS X MacPorts or Homebrew can be used to install dependencies:
$ brew install bison flex gawk libffi \
git mercurial graphviz pkg-config python3
$ sudo port install bison flex readline gawk libffi \
git mercurial graphviz pkgconfig python36
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
more information: http://www.clifford.at/yosys/download.html more information: http://www.clifford.at/yosys/download.html
@ -80,6 +87,9 @@ To build Yosys simply type 'make' in this directory.
Note that this also downloads, builds and installs ABC (using yosys-abc Note that this also downloads, builds and installs ABC (using yosys-abc
as executable name). as executable name).
Getting Started
===============
Yosys can be used with the interactive command shell, with Yosys can be used with the interactive command shell, with
synthesis scripts or with command line arguments. Let's perform synthesis scripts or with command line arguments. Let's perform
a simple synthesis job using the interactive command shell: a simple synthesis job using the interactive command shell:
@ -379,10 +389,13 @@ Non-standard or SystemVerilog features for formal verification
to 0 otherwise. to 0 otherwise.
- The system task ``$anyconst`` evaluates to any constant value. This is - The system task ``$anyconst`` evaluates to any constant value. This is
equivalent to declaring a reg as ``const rand``. equivalent to declaring a reg as ``rand const``, but also works outside
of checkers. (Yosys also supports ``rand const`` outside checkers.)
- The system task ``$anyseq`` evaluates to any value, possibly a different - The system task ``$anyseq`` evaluates to any value, possibly a different
value in each cycle. This is equivalent to declaring a reg as ``rand``. value in each cycle. This is equivalent to declaring a reg as ``rand``,
but also works outside of checkers. (Yosys also supports ``rand``
variables outside checkers.)
- The SystemVerilog tasks ``$past``, ``$stable``, ``$rose`` and ``$fell`` are - The SystemVerilog tasks ``$past``, ``$stable``, ``$rose`` and ``$fell`` are
supported in any clocked block. supported in any clocked block.
@ -407,7 +420,10 @@ from SystemVerilog:
- The keywords ``always_comb``, ``always_ff`` and ``always_latch``, ``logic`` - The keywords ``always_comb``, ``always_ff`` and ``always_latch``, ``logic``
and ``bit`` are supported. and ``bit`` are supported.
- Declaring free variables with ``rand`` and ``const rand`` is supported. - Declaring free variables with ``rand`` and ``rand const`` is supported.
- Checkers without a port list that do not need to be instantiated (but instead
behave like a named block) are supported.
- SystemVerilog packages are supported. Once a SystemVerilog file is read - SystemVerilog packages are supported. Once a SystemVerilog file is read
into a design with ``read_verilog``, all its packages are available to into a design with ``read_verilog``, all its packages are available to

View File

@ -57,7 +57,7 @@ PRIVATE_NAMESPACE_BEGIN
void msg_func(msg_type_t msg_type, const char *message_id, linefile_type linefile, const char *msg, va_list args) void msg_func(msg_type_t msg_type, const char *message_id, linefile_type linefile, const char *msg, va_list args)
{ {
log("VERIFIC-%s [%s] ", string message = stringf("VERIFIC-%s [%s] ",
msg_type == VERIFIC_NONE ? "NONE" : msg_type == VERIFIC_NONE ? "NONE" :
msg_type == VERIFIC_ERROR ? "ERROR" : msg_type == VERIFIC_ERROR ? "ERROR" :
msg_type == VERIFIC_WARNING ? "WARNING" : msg_type == VERIFIC_WARNING ? "WARNING" :
@ -65,10 +65,16 @@ void msg_func(msg_type_t msg_type, const char *message_id, linefile_type linefil
msg_type == VERIFIC_INFO ? "INFO" : msg_type == VERIFIC_INFO ? "INFO" :
msg_type == VERIFIC_COMMENT ? "COMMENT" : msg_type == VERIFIC_COMMENT ? "COMMENT" :
msg_type == VERIFIC_PROGRAM_ERROR ? "PROGRAM_ERROR" : "UNKNOWN", message_id); msg_type == VERIFIC_PROGRAM_ERROR ? "PROGRAM_ERROR" : "UNKNOWN", message_id);
if (linefile) if (linefile)
log("%s:%d: ", LineFile::GetFileName(linefile), LineFile::GetLineNo(linefile)); message += stringf("%s:%d: ", LineFile::GetFileName(linefile), LineFile::GetLineNo(linefile));
logv(msg, args);
log("\n"); message += vstringf(msg, args);
if (msg_type == VERIFIC_ERROR || msg_type == VERIFIC_WARNING || msg_type == VERIFIC_PROGRAM_ERROR)
log_warning("%s\n", message.c_str());
else
log("%s\n", message.c_str());
} }
struct VerificImporter struct VerificImporter
@ -617,6 +623,10 @@ struct VerificImporter
module->fixup_ports(); module->fixup_ports();
dict<Net*, char, hash_ptr_ops> init_nets;
pool<Net*, hash_ptr_ops> anyconst_nets;
pool<Net*, hash_ptr_ops> anyseq_nets;
FOREACH_NET_OF_NETLIST(nl, mi, net) FOREACH_NET_OF_NETLIST(nl, mi, net)
{ {
if (net->IsRamNet()) if (net->IsRamNet())
@ -643,9 +653,59 @@ struct VerificImporter
memory->width = bits_in_word; memory->width = bits_in_word;
memory->size = number_of_bits / bits_in_word; memory->size = number_of_bits / bits_in_word;
const char *ascii_initdata = net->GetWideInitialValue();
if (ascii_initdata) {
while (*ascii_initdata != 0 && *ascii_initdata != '\'')
ascii_initdata++;
if (*ascii_initdata == '\'')
ascii_initdata++;
if (*ascii_initdata != 0) {
log_assert(*ascii_initdata == 'b');
ascii_initdata++;
}
for (int word_idx = 0; word_idx < memory->size; word_idx++) {
Const initval = Const(State::Sx, memory->width);
bool initval_valid = false;
for (int bit_idx = memory->width-1; bit_idx >= 0; bit_idx--) {
if (*ascii_initdata == 0)
break;
if (*ascii_initdata == '0' || *ascii_initdata == '1') {
initval[bit_idx] = (*ascii_initdata == '0') ? State::S0 : State::S1;
initval_valid = true;
}
ascii_initdata++;
}
if (initval_valid) {
RTLIL::Cell *cell = module->addCell(NEW_ID, "$meminit");
cell->parameters["\\WORDS"] = 1;
if (net->GetOrigTypeRange()->LeftRangeBound() < net->GetOrigTypeRange()->RightRangeBound())
cell->setPort("\\ADDR", word_idx);
else
cell->setPort("\\ADDR", memory->size - word_idx - 1);
cell->setPort("\\DATA", initval);
cell->parameters["\\MEMID"] = RTLIL::Const(memory->name.str());
cell->parameters["\\ABITS"] = 32;
cell->parameters["\\WIDTH"] = memory->width;
cell->parameters["\\PRIORITY"] = RTLIL::Const(autoidx-1);
}
}
}
continue; continue;
} }
if (net->GetInitialValue())
init_nets[net] = net->GetInitialValue();
const char *rand_const_attr = net->GetAttValue(" rand_const");
const char *rand_attr = net->GetAttValue(" rand");
if (rand_const_attr != nullptr && !strcmp(rand_const_attr, "1"))
anyconst_nets.insert(net);
else if (rand_attr != nullptr && !strcmp(rand_attr, "1"))
anyseq_nets.insert(net);
if (net_map.count(net)) { if (net_map.count(net)) {
// log(" skipping net %s.\n", net->Name()); // log(" skipping net %s.\n", net->Name());
continue; continue;
@ -683,25 +743,94 @@ struct VerificImporter
wire->start_offset = min(netbus->LeftIndex(), netbus->RightIndex()); wire->start_offset = min(netbus->LeftIndex(), netbus->RightIndex());
import_attributes(wire->attributes, netbus); import_attributes(wire->attributes, netbus);
for (int i = netbus->LeftIndex();; i += netbus->IsUp() ? +1 : -1) { RTLIL::Const initval = Const(State::Sx, GetSize(wire));
if (netbus->ElementAtIndex(i)) { bool initval_valid = false;
for (int i = netbus->LeftIndex();; i += netbus->IsUp() ? +1 : -1)
{
if (netbus->ElementAtIndex(i))
{
int bitidx = i - wire->start_offset;
net = netbus->ElementAtIndex(i); net = netbus->ElementAtIndex(i);
RTLIL::SigBit bit(wire, i - wire->start_offset); RTLIL::SigBit bit(wire, bitidx);
if (init_nets.count(net)) {
if (init_nets.at(net) == '0')
initval.bits.at(bitidx) = State::S0;
if (init_nets.at(net) == '1')
initval.bits.at(bitidx) = State::S1;
initval_valid = true;
init_nets.erase(net);
}
if (net_map.count(net) == 0) if (net_map.count(net) == 0)
net_map[net] = bit; net_map[net] = bit;
else else
module->connect(bit, net_map.at(net)); module->connect(bit, net_map.at(net));
} }
if (i == netbus->RightIndex()) if (i == netbus->RightIndex())
break; break;
} }
if (initval_valid)
wire->attributes["\\init"] = initval;
} }
else else
{ {
// log(" skipping netbus %s.\n", netbus->Name()); // log(" skipping netbus %s.\n", netbus->Name());
} }
SigSpec anyconst_sig;
SigSpec anyseq_sig;
for (int i = netbus->RightIndex();; i += netbus->IsUp() ? -1 : +1) {
net = netbus->ElementAtIndex(i);
if (net != nullptr && anyconst_nets.count(net)) {
anyconst_sig.append(net_map.at(net));
anyconst_nets.erase(net);
}
if (net != nullptr && anyseq_nets.count(net)) {
anyseq_sig.append(net_map.at(net));
anyseq_nets.erase(net);
}
if (i == netbus->LeftIndex())
break;
}
if (GetSize(anyconst_sig))
module->connect(anyconst_sig, module->Anyconst(NEW_ID, GetSize(anyconst_sig)));
if (GetSize(anyseq_sig))
module->connect(anyseq_sig, module->Anyseq(NEW_ID, GetSize(anyseq_sig)));
} }
for (auto it : init_nets)
{
Const initval;
SigBit bit = net_map.at(it.first);
log_assert(bit.wire);
if (bit.wire->attributes.count("\\init"))
initval = bit.wire->attributes.at("\\init");
while (GetSize(initval) < GetSize(bit.wire))
initval.bits.push_back(State::Sx);
if (it.second == '0')
initval.bits.at(bit.offset) = State::S0;
if (it.second == '1')
initval.bits.at(bit.offset) = State::S1;
bit.wire->attributes["\\init"] = initval;
}
for (auto net : anyconst_nets)
module->connect(net_map.at(net), module->Anyconst(NEW_ID));
for (auto net : anyseq_nets)
module->connect(net_map.at(net), module->Anyseq(NEW_ID));
FOREACH_INSTANCE_OF_NETLIST(nl, mi, inst) FOREACH_INSTANCE_OF_NETLIST(nl, mi, inst)
{ {
if (inst->Type() == PRIM_SVA_POSEDGE) { if (inst->Type() == PRIM_SVA_POSEDGE) {
@ -733,7 +862,7 @@ struct VerificImporter
SigBit outsig = net_map.at(out); SigBit outsig = net_map.at(out);
log_assert(outsig.wire && GetSize(outsig.wire) == 1); log_assert(outsig.wire && GetSize(outsig.wire) == 1);
outsig.wire->attributes["\\init"] == Const(0, 1); outsig.wire->attributes["\\init"] = Const(1, 1);
module->addDff(NEW_ID, net_map.at(clk), net_map.at(in2), net_map.at(out)); module->addDff(NEW_ID, net_map.at(clk), net_map.at(in2), net_map.at(out));
continue; continue;

View File

@ -175,15 +175,17 @@ YOSYS_NAMESPACE_END
"always_ff" { SV_KEYWORD(TOK_ALWAYS); } "always_ff" { SV_KEYWORD(TOK_ALWAYS); }
"always_latch" { SV_KEYWORD(TOK_ALWAYS); } "always_latch" { SV_KEYWORD(TOK_ALWAYS); }
"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); } "assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); } "assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
"cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); } "cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); }
"restrict" { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); } "restrict" { if (formal_mode) return TOK_RESTRICT; SV_KEYWORD(TOK_RESTRICT); }
"property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); } "property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); }
"rand" { if (formal_mode) return TOK_RAND; SV_KEYWORD(TOK_RAND); } "rand" { if (formal_mode) return TOK_RAND; SV_KEYWORD(TOK_RAND); }
"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); } "const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
"logic" { SV_KEYWORD(TOK_REG); } "checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); }
"bit" { SV_KEYWORD(TOK_REG); } "endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); }
"logic" { SV_KEYWORD(TOK_REG); }
"bit" { SV_KEYWORD(TOK_REG); }
"input" { return TOK_INPUT; } "input" { return TOK_INPUT; }
"output" { return TOK_OUTPUT; } "output" { return TOK_OUTPUT; }

View File

@ -116,7 +116,7 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED %token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME %token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME
%token TOK_RESTRICT TOK_COVER TOK_PROPERTY TOK_ENUM TOK_TYPEDEF %token TOK_RESTRICT TOK_COVER TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
%token TOK_RAND TOK_CONST %token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER
%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int %type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list %type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
@ -465,7 +465,18 @@ module_body:
module_body_stmt: module_body_stmt:
task_func_decl | param_decl | localparam_decl | defparam_decl | wire_decl | assign_stmt | cell_stmt | task_func_decl | param_decl | localparam_decl | defparam_decl | wire_decl | assign_stmt | cell_stmt |
always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property; always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl;
checker_decl:
TOK_CHECKER TOK_ID ';' {
AstNode *node = new AstNode(AST_GENBLOCK);
node->str = *$2;
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
} module_body TOK_ENDCHECKER {
delete $2;
ast_stack.pop_back();
};
task_func_decl: task_func_decl:
attr TOK_DPI_FUNCTION TOK_ID TOK_ID { attr TOK_DPI_FUNCTION TOK_ID TOK_ID {

View File

@ -488,6 +488,13 @@ void log_cell(RTLIL::Cell *cell, std::string indent)
log("%s", buf.str().c_str()); log("%s", buf.str().c_str());
} }
void log_wire(RTLIL::Wire *wire, std::string indent)
{
std::stringstream buf;
ILANG_BACKEND::dump_wire(buf, indent, wire);
log("%s", buf.str().c_str());
}
// --------------------------------------------------- // ---------------------------------------------------
// This is the magic behind the code coverage counters // This is the magic behind the code coverage counters
// --------------------------------------------------- // ---------------------------------------------------

View File

@ -90,6 +90,7 @@ template<typename T> static inline const char *log_id(T *obj) {
void log_module(RTLIL::Module *module, std::string indent = ""); void log_module(RTLIL::Module *module, std::string indent = "");
void log_cell(RTLIL::Cell *cell, std::string indent = ""); void log_cell(RTLIL::Cell *cell, std::string indent = "");
void log_wire(RTLIL::Wire *wire, std::string indent = "");
#ifndef NDEBUG #ifndef NDEBUG
static inline void log_assert_worker(bool cond, const char *expr, const char *file, int line) { static inline void log_assert_worker(bool cond, const char *expr, const char *file, int line) {

View File

@ -383,7 +383,8 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (detect_const_and || detect_const_or) if (detect_const_and || detect_const_or)
{ {
pool<SigBit> input_bits = assign_map(cell->getPort("\\A")).to_sigbit_pool(); pool<SigBit> input_bits = assign_map(cell->getPort("\\A")).to_sigbit_pool();
bool found_zero = false, found_one = false, found_inv = false; bool found_zero = false, found_one = false, found_undef = false, found_inv = false, many_conconst = false;
SigBit non_const_input = State::Sm;
if (cell->hasPort("\\B")) { if (cell->hasPort("\\B")) {
vector<SigBit> more_bits = assign_map(cell->getPort("\\B")).to_sigbit_vector(); vector<SigBit> more_bits = assign_map(cell->getPort("\\B")).to_sigbit_vector();
@ -391,12 +392,20 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
} }
for (auto bit : input_bits) { for (auto bit : input_bits) {
if (bit == State::S0) if (bit.wire) {
found_zero = true; if (invert_map.count(bit) && input_bits.count(invert_map.at(bit)))
if (bit == State::S1) found_inv = true;
found_one = true; if (non_const_input != State::Sm)
if (invert_map.count(bit) && input_bits.count(invert_map.at(bit))) many_conconst = true;
found_inv = true; non_const_input = many_conconst ? State::Sm : bit;
} else {
if (bit == State::S0)
found_zero = true;
else if (bit == State::S1)
found_one = true;
else
found_undef = true;
}
} }
if (detect_const_and && (found_zero || found_inv)) { if (detect_const_and && (found_zero || found_inv)) {
@ -410,6 +419,12 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
replace_cell(assign_map, module, cell, "const_or", "\\Y", RTLIL::State::S1); replace_cell(assign_map, module, cell, "const_or", "\\Y", RTLIL::State::S1);
goto next_cell; goto next_cell;
} }
if (non_const_input != State::Sm && !found_undef) {
cover("opt.opt_expr.and_or_buffer");
replace_cell(assign_map, module, cell, "and_or_buffer", "\\Y", non_const_input);
goto next_cell;
}
} }
if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_bool", "$reduce_xor", "$reduce_xnor", "$neg") && if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_bool", "$reduce_xor", "$reduce_xnor", "$neg") &&
@ -1208,6 +1223,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
//width of the variable port //width of the variable port
int width; int width;
int const_width;
bool var_signed; bool var_signed;
@ -1216,6 +1232,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
sigVar = cell->getPort("\\A"); sigVar = cell->getPort("\\A");
sigConst = cell->getPort("\\B"); sigConst = cell->getPort("\\B");
width = cell->parameters["\\A_WIDTH"].as_int(); width = cell->parameters["\\A_WIDTH"].as_int();
const_width = cell->parameters["\\B_WIDTH"].as_int();
var_signed = cell->parameters["\\A_SIGNED"].as_bool(); var_signed = cell->parameters["\\A_SIGNED"].as_bool();
} else } else
if (cell->type == "$gt" || cell->type == "$le") { if (cell->type == "$gt" || cell->type == "$le") {
@ -1223,8 +1240,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
sigVar = cell->getPort("\\B"); sigVar = cell->getPort("\\B");
sigConst = cell->getPort("\\A"); sigConst = cell->getPort("\\A");
width = cell->parameters["\\B_WIDTH"].as_int(); width = cell->parameters["\\B_WIDTH"].as_int();
const_width = cell->parameters["\\A_WIDTH"].as_int();
var_signed = cell->parameters["\\B_SIGNED"].as_bool(); var_signed = cell->parameters["\\B_SIGNED"].as_bool();
} } else
log_abort();
// replace a(signed) < 0 with the high bit of a // replace a(signed) < 0 with the high bit of a
if (sigConst.is_fully_const() && sigConst.is_fully_zero() && var_signed == true) if (sigConst.is_fully_const() && sigConst.is_fully_zero() && var_signed == true)
@ -1265,7 +1284,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
} }
int const_bit_set = get_onehot_bit_index(sigConst); int const_bit_set = get_onehot_bit_index(sigConst);
if (const_bit_set >= 0) { if (const_bit_set >= 0 && const_bit_set < width) {
int bit_set = const_bit_set; int bit_set = const_bit_set;
RTLIL::SigSpec a_prime(RTLIL::State::S0, width - bit_set); RTLIL::SigSpec a_prime(RTLIL::State::S0, width - bit_set);
for (int i = bit_set; i < width; i++) { for (int i = bit_set; i < width; i++) {
@ -1284,6 +1303,21 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
did_something = true; did_something = true;
goto next_cell; goto next_cell;
} }
else if(const_bit_set >= width && const_bit_set >= 0){
RTLIL::SigSpec a_prime(RTLIL::State::S0, 1);
if(is_lt){
a_prime[0] = RTLIL::State::S1;
log("Replacing %s cell `%s' (implementing unsigned X[%d:0] < %s[%d:0]) with constant 0.\n", log_id(cell->type), log_id(cell), width-1, log_signal(sigConst),const_width-1);
}
else{
log("Replacing %s cell `%s' (implementing unsigned X[%d:0]>= %s[%d:0]) with constant 1.\n", log_id(cell->type), log_id(cell), width-1, log_signal(sigConst),const_width-1);
}
module->connect(cell->getPort("\\Y"), a_prime);
module->remove(cell);
did_something = true;
goto next_cell;
}
} }
} }

View File

@ -280,8 +280,12 @@ struct OptMergeWorker
dff_init_map.set(module); dff_init_map.set(module);
for (auto &it : module->wires_) for (auto &it : module->wires_)
if (it.second->attributes.count("\\init") != 0) if (it.second->attributes.count("\\init") != 0) {
dff_init_map.add(it.second, it.second->attributes.at("\\init")); Const initval = it.second->attributes.at("\\init");
for (int i = 0; i < GetSize(initval) && i < GetSize(it.second); i++)
if (initval[i] == State::S0 || initval[i] == State::S1)
dff_init_map.add(SigBit(it.second, i), initval[i]);
}
bool did_something = true; bool did_something = true;
while (did_something) while (did_something)

View File

@ -244,7 +244,9 @@ struct OptRmdffPass : public Pass {
{ {
if (wire->attributes.count("\\init") != 0) { if (wire->attributes.count("\\init") != 0) {
Const initval = wire->attributes.at("\\init"); Const initval = wire->attributes.at("\\init");
dff_init_map.add(wire, initval); for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++)
if (initval[i] == State::S0 || initval[i] == State::S1)
dff_init_map.add(SigBit(wire, i), initval[i]);
for (int i = 0; i < GetSize(wire); i++) { for (int i = 0; i < GetSize(wire); i++) {
SigBit wire_bit(wire, i), mapped_bit = assign_map(wire_bit); SigBit wire_bit(wire, i), mapped_bit = assign_map(wire_bit);
if (mapped_bit.wire) { if (mapped_bit.wire) {