Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Jim Lawson 2019-05-21 12:47:55 -07:00
commit 489c555b41
66 changed files with 2299 additions and 630 deletions

13
.clang-format Normal file
View File

@ -0,0 +1,13 @@
# Default Linux style
BasedOnStyle: LLVM
IndentWidth: 8
UseTab: Always
BreakBeforeBraces: Linux
AllowShortIfStatementsOnASingleLine: false
IndentCaseLabels: false
# From CodingReadme
TabWidth: 8
ContinuationIndentWidth: 2
ColumnLimit: 150
# BreakBeforeBraces: Linux

View File

@ -25,7 +25,8 @@ PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.versi
PYTHON_EXECUTABLE := $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi) PYTHON_EXECUTABLE := $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi)
PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"") PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"")
PYTHON_MAJOR_VERSION := $(shell echo $(PYTHON_VERSION) | cut -f1 -d.) PYTHON_MAJOR_VERSION := $(shell echo $(PYTHON_VERSION) | cut -f1 -d.)
PYTHON_DESTDIR := `$(PYTHON_EXECUTABLE)-config --prefix`/lib/python$(PYTHON_VERSION)/dist-packages PYTHON_PREFIX := `$(PYTHON_EXECUTABLE)-config --prefix`
PYTHON_DESTDIR := $(PYTHON_PREFIX)/lib/python$(PYTHON_VERSION)/site-packages
# other configuration flags # other configuration flags
ENABLE_GCOV := 0 ENABLE_GCOV := 0
@ -679,13 +680,13 @@ endif
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR) $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR)
$(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/. $(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/.
ifeq ($(ENABLE_LIBYOSYS),1) ifeq ($(ENABLE_LIBYOSYS),1)
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR) $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR)
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)/
$(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so
$(INSTALL_SUDO) ldconfig
ifeq ($(ENABLE_PYOSYS),1) ifeq ($(ENABLE_PYOSYS),1)
$(INSTALL_SUDO) mkdir -p $(PYTHON_DESTDIR)/pyosys $(INSTALL_SUDO) mkdir -p $(PYTHON_DESTDIR)/pyosys
$(INSTALL_SUDO) cp libyosys.so $(PYTHON_DESTDIR)/pyosys $(INSTALL_SUDO) cp libyosys.so $(PYTHON_DESTDIR)/pyosys/
$(INSTALL_SUDO) cp misc/__init__.py $(PYTHON_DESTDIR)/pyosys $(INSTALL_SUDO) cp misc/__init__.py $(PYTHON_DESTDIR)/pyosys/
endif endif
endif endif

View File

@ -259,11 +259,7 @@ for them:
- The ``tri``, ``triand``, ``trior``, ``wand`` and ``wor`` net types - The ``tri``, ``triand``, ``trior``, ``wand`` and ``wor`` net types
- The ``config`` keyword and library map files - The ``config`` and ``disable`` keywords and library map files
- The ``disable``, ``primitive`` and ``specify`` statements
- Latched logic (is synthesized as logic with feedback loops)
Verilog Attributes and non-standard features Verilog Attributes and non-standard features
@ -420,9 +416,15 @@ Verilog Attributes and non-standard features
expressions as <size>. If the expression is not a simple identifier, it expressions as <size>. If the expression is not a simple identifier, it
must be put in parentheses. Examples: ``WIDTH'd42``, ``(4+2)'b101010`` must be put in parentheses. Examples: ``WIDTH'd42``, ``(4+2)'b101010``
- The system tasks ``$finish`` and ``$display`` are supported in initial blocks - The system tasks ``$finish``, ``$stop`` and ``$display`` are supported in
in an unconditional context (only if/case statements on parameters initial blocks in an unconditional context (only if/case statements on
and constant values). The intended use for this is synthesis-time DRC. expressions over parameters and constant values are allowed). The intended
use for this is synthesis-time DRC.
- There is limited support for converting specify .. endspecify statements to
special ``$specify2``, ``$specify3``, and ``$specrule`` cells, for use in
blackboxes and whiteboxes. Use ``read_verilog -specify`` to enable this
functionality. (By default specify .. endspecify blocks are ignored.)
Non-standard or SystemVerilog features for formal verification Non-standard or SystemVerilog features for formal verification

View File

@ -344,6 +344,7 @@ struct FirrtlWorker
switch (dir) { switch (dir) {
case FD_INOUT: case FD_INOUT:
log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second)); log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second));
/* FALLTHRU */
case FD_OUT: case FD_OUT:
sourceExpr = firstName; sourceExpr = firstName;
sinkExpr = secondExpr; sinkExpr = secondExpr;
@ -351,7 +352,7 @@ struct FirrtlWorker
break; break;
case FD_NODIRECTION: case FD_NODIRECTION:
log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second)); log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second));
/* FALL_THROUGH */ /* FALLTHRU */
case FD_IN: case FD_IN:
sourceExpr = secondExpr; sourceExpr = secondExpr;
sinkExpr = firstName; sinkExpr = firstName;

View File

@ -160,7 +160,10 @@ void ILANG_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::
} }
f << stringf("%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str()); f << stringf("%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str());
for (auto &it : cell->parameters) { for (auto &it : cell->parameters) {
f << stringf("%s parameter%s %s ", indent.c_str(), (it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", it.first.c_str()); f << stringf("%s parameter%s%s %s ", indent.c_str(),
(it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "",
(it.second.flags & RTLIL::CONST_FLAG_REAL) != 0 ? " real" : "",
it.first.c_str());
dump_const(f, it.second); dump_const(f, it.second);
f << stringf("\n"); f << stringf("\n");
} }

View File

@ -183,8 +183,9 @@ bool is_reg_wire(RTLIL::SigSpec sig, std::string &reg_name)
return true; return true;
} }
void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false, bool escape_comment = false) void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool escape_comment = false)
{ {
bool set_signed = (data.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
if (width < 0) if (width < 0)
width = data.bits.size() - offset; width = data.bits.size() - offset;
if (width == 0) { if (width == 0) {
@ -275,7 +276,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
} }
} }
} else { } else {
f << stringf("\""); if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0)
f << stringf("\"");
std::string str = data.decode_string(); std::string str = data.decode_string();
for (size_t i = 0; i < str.size(); i++) { for (size_t i = 0; i < str.size(); i++) {
if (str[i] == '\n') if (str[i] == '\n')
@ -293,7 +295,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
else else
f << str[i]; f << str[i];
} }
f << stringf("\""); if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0)
f << stringf("\"");
} }
} }
@ -373,7 +376,7 @@ void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString,
else if (modattr && (it->second == Const(1, 1) || it->second == Const(1))) else if (modattr && (it->second == Const(1, 1) || it->second == Const(1)))
f << stringf(" 1 "); f << stringf(" 1 ");
else else
dump_const(f, it->second, -1, 0, false, false, attr2comment); dump_const(f, it->second, -1, 0, false, attr2comment);
f << stringf(" %s%c", attr2comment ? "*/" : "*)", term); f << stringf(" %s%c", attr2comment ? "*/" : "*)", term);
} }
} }
@ -1242,6 +1245,118 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
return true; return true;
} }
if (cell->type.in("$assert", "$assume", "$cover"))
{
f << stringf("%s" "always @* if (", indent.c_str());
dump_sigspec(f, cell->getPort("\\EN"));
f << stringf(") %s(", cell->type.c_str()+1);
dump_sigspec(f, cell->getPort("\\A"));
f << stringf(");\n");
return true;
}
if (cell->type.in("$specify2", "$specify3"))
{
f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str());
SigSpec en = cell->getPort("\\EN");
if (en != State::S1) {
f << stringf("if (");
dump_sigspec(f, cell->getPort("\\EN"));
f << stringf(") ");
}
f << "(";
if (cell->type == "$specify3" && cell->getParam("\\EDGE_EN").as_bool())
f << (cell->getParam("\\EDGE_POL").as_bool() ? "posedge ": "negedge ");
dump_sigspec(f, cell->getPort("\\SRC"));
f << " ";
if (cell->getParam("\\SRC_DST_PEN").as_bool())
f << (cell->getParam("\\SRC_DST_POL").as_bool() ? "+": "-");
f << (cell->getParam("\\FULL").as_bool() ? "*> ": "=> ");
if (cell->type == "$specify3") {
f << "(";
dump_sigspec(f, cell->getPort("\\DST"));
f << " ";
if (cell->getParam("\\DAT_DST_PEN").as_bool())
f << (cell->getParam("\\DAT_DST_POL").as_bool() ? "+": "-");
f << ": ";
dump_sigspec(f, cell->getPort("\\DAT"));
f << ")";
} else {
dump_sigspec(f, cell->getPort("\\DST"));
}
bool bak_decimal = decimal;
decimal = 1;
f << ") = (";
dump_const(f, cell->getParam("\\T_RISE_MIN"));
f << ":";
dump_const(f, cell->getParam("\\T_RISE_TYP"));
f << ":";
dump_const(f, cell->getParam("\\T_RISE_MAX"));
f << ", ";
dump_const(f, cell->getParam("\\T_FALL_MIN"));
f << ":";
dump_const(f, cell->getParam("\\T_FALL_TYP"));
f << ":";
dump_const(f, cell->getParam("\\T_FALL_MAX"));
f << ");\n";
decimal = bak_decimal;
f << stringf("%s" "endspecify\n", indent.c_str());
return true;
}
if (cell->type == "$specrule")
{
f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str());
string spec_type = cell->getParam("\\TYPE").decode_string();
f << stringf("%s(", spec_type.c_str());
if (cell->getParam("\\SRC_PEN").as_bool())
f << (cell->getParam("\\SRC_POL").as_bool() ? "posedge ": "negedge ");
dump_sigspec(f, cell->getPort("\\SRC"));
if (cell->getPort("\\SRC_EN") != State::S1) {
f << " &&& ";
dump_sigspec(f, cell->getPort("\\SRC_EN"));
}
f << ", ";
if (cell->getParam("\\DST_PEN").as_bool())
f << (cell->getParam("\\DST_POL").as_bool() ? "posedge ": "negedge ");
dump_sigspec(f, cell->getPort("\\DST"));
if (cell->getPort("\\DST_EN") != State::S1) {
f << " &&& ";
dump_sigspec(f, cell->getPort("\\DST_EN"));
}
bool bak_decimal = decimal;
decimal = 1;
f << ", ";
dump_const(f, cell->getParam("\\T_LIMIT"));
if (spec_type == "$setuphold" || spec_type == "$recrem" || spec_type == "$fullskew") {
f << ", ";
dump_const(f, cell->getParam("\\T_LIMIT2"));
}
f << ");\n";
decimal = bak_decimal;
f << stringf("%s" "endspecify\n", indent.c_str());
return true;
}
// FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_ // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
// FIXME: $sr, $dlatch, $memrd, $memwr, $fsm // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
@ -1264,8 +1379,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
if (it != cell->parameters.begin()) if (it != cell->parameters.begin())
f << stringf(","); f << stringf(",");
f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str()); f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0; dump_const(f, it->second);
dump_const(f, it->second, -1, 0, false, is_signed);
f << stringf(")"); f << stringf(")");
} }
f << stringf("\n%s" ")", indent.c_str()); f << stringf("\n%s" ")", indent.c_str());
@ -1312,8 +1426,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
if (defparam && cell->parameters.size() > 0) { if (defparam && cell->parameters.size() > 0) {
for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) { for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str()); f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str());
bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0; dump_const(f, it->second);
dump_const(f, it->second, -1, 0, false, is_signed);
f << stringf(";\n"); f << stringf(";\n");
} }
} }
@ -1505,7 +1618,8 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
SigSpec sig = active_sigmap(wire); SigSpec sig = active_sigmap(wire);
Const val = wire->attributes.at("\\init"); Const val = wire->attributes.at("\\init");
for (int i = 0; i < GetSize(sig) && i < GetSize(val); i++) for (int i = 0; i < GetSize(sig) && i < GetSize(val); i++)
active_initdata[sig[i]] = val.bits.at(i); if (val[i] == State::S0 || val[i] == State::S1)
active_initdata[sig[i]] = val[i];
} }
if (!module->processes.empty()) if (!module->processes.empty())

View File

@ -951,6 +951,9 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
continue; continue;
if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM) if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
continue; continue;
if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
(child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule"))
continue;
blackbox_module = false; blackbox_module = false;
break; break;
} }
@ -1035,6 +1038,9 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
child->delete_children(); child->delete_children();
child->children.push_back(AstNode::mkconst_int(0, false, 0)); child->children.push_back(AstNode::mkconst_int(0, false, 0));
new_children.push_back(child); new_children.push_back(child);
} else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
(child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) {
new_children.push_back(child);
} else { } else {
delete child; delete child;
} }

View File

@ -645,6 +645,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (!id_ast->children[0]->range_valid) if (!id_ast->children[0]->range_valid)
log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str()); log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str());
this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1; this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
if (children.size() > 1)
range = children[1];
} else } else
log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str()); log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str());
if (range) { if (range) {
@ -1490,10 +1492,12 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
continue; continue;
} }
if (child->type == AST_PARASET) { if (child->type == AST_PARASET) {
int extra_const_flags = 0;
IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str; IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
if (child->children[0]->type == AST_REALVALUE) { if (child->children[0]->type == AST_REALVALUE) {
log_file_warning(filename, linenum, "Replacing floating point parameter %s.%s = %f with string.\n", log_file_warning(filename, linenum, "Replacing floating point parameter %s.%s = %f with string.\n",
log_id(cell), log_id(paraname), child->children[0]->realvalue); log_id(cell), log_id(paraname), child->children[0]->realvalue);
extra_const_flags = RTLIL::CONST_FLAG_REAL;
auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue)); auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue));
strnode->cloneInto(child->children[0]); strnode->cloneInto(child->children[0]);
delete strnode; delete strnode;
@ -1502,6 +1506,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
log_file_error(filename, linenum, "Parameter %s.%s with non-constant value!\n", log_file_error(filename, linenum, "Parameter %s.%s with non-constant value!\n",
log_id(cell), log_id(paraname)); log_id(cell), log_id(paraname));
cell->parameters[paraname] = child->children[0]->asParaConst(); cell->parameters[paraname] = child->children[0]->asParaConst();
cell->parameters[paraname].flags |= extra_const_flags;
continue; continue;
} }
if (child->type == AST_ARGUMENT) { if (child->type == AST_ARGUMENT) {
@ -1521,9 +1526,29 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
} }
for (auto &attr : attributes) { for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT) if (attr.second->type != AST_CONSTANT)
log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); log_file_error(filename, linenum, "Attribute `%s' with non-constant value.\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst(); cell->attributes[attr.first] = attr.second->asAttrConst();
} }
if (cell->type.in("$specify2", "$specify3")) {
int src_width = GetSize(cell->getPort("\\SRC"));
int dst_width = GetSize(cell->getPort("\\DST"));
bool full = cell->getParam("\\FULL").as_bool();
if (!full && src_width != dst_width)
log_file_error(filename, linenum, "Parallel specify SRC width does not match DST width.\n");
if (cell->type == "$specify3") {
int dat_width = GetSize(cell->getPort("\\DAT"));
if (dat_width != dst_width)
log_file_error(filename, linenum, "Specify DAT width does not match DST width.\n");
}
cell->setParam("\\SRC_WIDTH", Const(src_width));
cell->setParam("\\DST_WIDTH", Const(dst_width));
}
if (cell->type == "$specrule") {
int src_width = GetSize(cell->getPort("\\SRC"));
int dst_width = GetSize(cell->getPort("\\DST"));
cell->setParam("\\SRC_WIDTH", Const(src_width));
cell->setParam("\\DST_WIDTH", Const(dst_width));
}
} }
break; break;

View File

@ -1172,14 +1172,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
varbuf->children[0] = buf; varbuf->children[0] = buf;
} }
#if 0
if (type == AST_FOR) { if (type == AST_FOR) {
AstNode *buf = next_ast->clone(); AstNode *buf = next_ast->clone();
delete buf->children[1]; delete buf->children[1];
buf->children[1] = varbuf->children[0]->clone(); buf->children[1] = varbuf->children[0]->clone();
current_block->children.insert(current_block->children.begin() + current_block_idx++, buf); current_block->children.insert(current_block->children.begin() + current_block_idx++, buf);
} }
#endif
current_scope[varbuf->str] = backup_scope_varbuf; current_scope[varbuf->str] = backup_scope_varbuf;
delete varbuf; delete varbuf;
@ -1607,6 +1605,7 @@ skip_dynamic_range_lvalue_expansion:;
current_scope[wire_tmp->str] = wire_tmp; current_scope[wire_tmp->str] = wire_tmp;
wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false); wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
while (wire_tmp->simplify(true, false, false, 1, -1, false, false)) { } while (wire_tmp->simplify(true, false, false, 1, -1, false, false)) { }
wire_tmp->is_logic = true;
AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER); AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER);
wire_tmp_id->str = wire_tmp->str; wire_tmp_id->str = wire_tmp->str;

View File

@ -53,6 +53,7 @@ USING_YOSYS_NAMESPACE
"attribute" { return TOK_ATTRIBUTE; } "attribute" { return TOK_ATTRIBUTE; }
"parameter" { return TOK_PARAMETER; } "parameter" { return TOK_PARAMETER; }
"signed" { return TOK_SIGNED; } "signed" { return TOK_SIGNED; }
"real" { return TOK_REAL; }
"wire" { return TOK_WIRE; } "wire" { return TOK_WIRE; }
"memory" { return TOK_MEMORY; } "memory" { return TOK_MEMORY; }
"width" { return TOK_WIDTH; } "width" { return TOK_WIDTH; }

View File

@ -45,7 +45,16 @@ YOSYS_NAMESPACE_END
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
%} %}
%name-prefix "rtlil_frontend_ilang_yy" %define api.prefix {rtlil_frontend_ilang_yy}
/* The union is defined in the header, so we need to provide all the
* includes it requires
*/
%code requires {
#include <string>
#include <vector>
#include "frontends/ilang/ilang_frontend.h"
}
%union { %union {
char *string; char *string;
@ -61,7 +70,7 @@ USING_YOSYS_NAMESPACE
%token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC %token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC
%token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_GLOBAL TOK_INIT %token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_GLOBAL TOK_INIT
%token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET %token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET
%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_UPTO %token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_REAL TOK_UPTO
%type <rsigspec> sigspec_list_reversed %type <rsigspec> sigspec_list_reversed
%type <sigspec> sigspec sigspec_list %type <sigspec> sigspec sigspec_list
@ -241,6 +250,12 @@ cell_body:
free($4); free($4);
delete $5; delete $5;
} | } |
cell_body TOK_PARAMETER TOK_REAL TOK_ID constant EOL {
current_cell->parameters[$4] = *$5;
current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_REAL;
free($4);
delete $5;
} |
cell_body TOK_CONNECT TOK_ID sigspec EOL { cell_body TOK_CONNECT TOK_ID sigspec EOL {
if (current_cell->hasPort($3)) if (current_cell->hasPort($3))
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell port %s.", $3).c_str()); rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell port %s.", $3).c_str());
@ -445,4 +460,3 @@ conn_stmt:
delete $2; delete $2;
delete $3; delete $3;
}; };

View File

@ -46,7 +46,7 @@ USING_YOSYS_NAMESPACE
#include "VeriModule.h" #include "VeriModule.h"
#include "VeriWrite.h" #include "VeriWrite.h"
#include "VhdlUnits.h" #include "VhdlUnits.h"
#include "Message.h" #include "VeriLibrary.h"
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic pop #pragma clang diagnostic pop
@ -776,13 +776,14 @@ void VerificImporter::merge_past_ffs(pool<RTLIL::Cell*> &candidates)
void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*> &nl_todo) void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*> &nl_todo)
{ {
std::string module_name = nl->IsOperator() ? std::string("$verific$") + nl->Owner()->Name() : RTLIL::escape_id(nl->Owner()->Name()); std::string netlist_name = nl->GetAtt(" \\top") ? nl->CellBaseName() : nl->Owner()->Name();
std::string module_name = nl->IsOperator() ? "$verific$" + netlist_name : RTLIL::escape_id(netlist_name);
netlist = nl; netlist = nl;
if (design->has(module_name)) { if (design->has(module_name)) {
if (!nl->IsOperator() && !is_blackbox(nl)) if (!nl->IsOperator() && !is_blackbox(nl))
log_cmd_error("Re-definition of module `%s'.\n", nl->Owner()->Name()); log_cmd_error("Re-definition of module `%s'.\n", netlist_name.c_str());
return; return;
} }
@ -1752,32 +1753,64 @@ struct VerificExtNets
} }
}; };
void verific_import(Design *design, std::string top) void verific_import(Design *design, const std::map<std::string,std::string> &parameters, std::string top)
{ {
verific_sva_fsm_limit = 16; verific_sva_fsm_limit = 16;
std::set<Netlist*> nl_todo, nl_done; std::set<Netlist*> nl_todo, nl_done;
{ VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1);
VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1); VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1);
VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1); Array *netlists = NULL;
Array veri_libs, vhdl_libs;
if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
if (veri_lib) veri_libs.InsertLast(veri_lib);
Array veri_libs, vhdl_libs; Map verific_params(STRING_HASH);
if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib); for (const auto &i : parameters)
if (veri_lib) veri_libs.InsertLast(veri_lib); verific_params.Insert(i.first.c_str(), i.second.c_str());
Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs); if (top.empty()) {
Netlist *nl; netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, &verific_params);
int i; }
else {
Array veri_modules, vhdl_units;
FOREACH_ARRAY_ITEM(netlists, i, nl) { if (veri_lib) {
if (top.empty() || nl->Owner()->Name() == top) VeriModule *veri_module = veri_lib->GetModule(top.c_str(), 1);
nl_todo.insert(nl); if (veri_module) {
veri_modules.InsertLast(veri_module);
}
// Also elaborate all root modules since they may contain bind statements
MapIter mi;
FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) {
if (!veri_module->IsRootModule()) continue;
veri_modules.InsertLast(veri_module);
}
} }
delete netlists; if (vhdl_lib) {
VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(top.c_str());
if (vhdl_unit)
vhdl_units.InsertLast(vhdl_unit);
}
netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, &verific_params);
} }
Netlist *nl;
int i;
FOREACH_ARRAY_ITEM(netlists, i, nl) {
if (top.empty() && nl->CellBaseName() != top)
continue;
nl->AddAtt(new Att(" \\top", NULL));
nl_todo.insert(nl);
}
delete netlists;
if (!verific_error_msg.empty()) if (!verific_error_msg.empty())
log_error("%s\n", verific_error_msg.c_str()); log_error("%s\n", verific_error_msg.c_str());
@ -2212,8 +2245,8 @@ struct VerificPass : public Pass {
continue; continue;
} }
if (args[argidx] == "-chparam" && argidx+2 < GetSize(args)) { if (args[argidx] == "-chparam" && argidx+2 < GetSize(args)) {
const std::string &key = args[++argidx]; const std::string &key = args[++argidx];
const std::string &value = args[++argidx]; const std::string &value = args[++argidx];
unsigned new_insertion = parameters.Insert(key.c_str(), value.c_str(), unsigned new_insertion = parameters.Insert(key.c_str(), value.c_str(),
1 /* force_overwrite */); 1 /* force_overwrite */);
if (!new_insertion) if (!new_insertion)
@ -2270,12 +2303,22 @@ struct VerificPass : public Pass {
for (; argidx < GetSize(args); argidx++) for (; argidx < GetSize(args); argidx++)
{ {
const char *name = args[argidx].c_str(); const char *name = args[argidx].c_str();
VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1);
VeriModule *veri_module = veri_file::GetModule(name); if (veri_lib) {
if (veri_module) { VeriModule *veri_module = veri_lib->GetModule(name, 1);
log("Adding Verilog module '%s' to elaboration queue.\n", name); if (veri_module) {
veri_modules.InsertLast(veri_module); log("Adding Verilog module '%s' to elaboration queue.\n", name);
continue; veri_modules.InsertLast(veri_module);
continue;
}
// Also elaborate all root modules since they may contain bind statements
MapIter mi;
FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) {
if (!veri_module->IsRootModule()) continue;
veri_modules.InsertLast(veri_module);
}
} }
VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1); VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1);
@ -2294,8 +2337,10 @@ struct VerificPass : public Pass {
Netlist *nl; Netlist *nl;
int i; int i;
FOREACH_ARRAY_ITEM(netlists, i, nl) FOREACH_ARRAY_ITEM(netlists, i, nl) {
nl->AddAtt(new Att(" \\top", NULL));
nl_todo.insert(nl); nl_todo.insert(nl);
}
delete netlists; delete netlists;
} }

View File

@ -26,7 +26,7 @@ YOSYS_NAMESPACE_BEGIN
extern int verific_verbose; extern int verific_verbose;
extern bool verific_import_pending; extern bool verific_import_pending;
extern void verific_import(Design *design, std::string top = std::string()); extern void verific_import(Design *design, const std::map<std::string,std::string> &parameters, std::string top = std::string());
extern pool<int> verific_sva_prims; extern pool<int> verific_sva_prims;

View File

@ -14,7 +14,7 @@ frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l
$(Q) mkdir -p $(dir $@) $(Q) mkdir -p $(dir $@)
$(P) flex -o frontends/verilog/verilog_lexer.cc $< $(P) flex -o frontends/verilog/verilog_lexer.cc $<
frontends/verilog/verilog_parser.tab.o: CXXFLAGS += -DYYMAXDEPTH=100000 frontends/verilog/verilog_parser.tab.o: CXXFLAGS += -DYYMAXDEPTH=10000000
OBJS += frontends/verilog/verilog_parser.tab.o OBJS += frontends/verilog/verilog_parser.tab.o
OBJS += frontends/verilog/verilog_lexer.o OBJS += frontends/verilog/verilog_lexer.o

View File

@ -158,6 +158,9 @@ struct VerilogFrontend : public Frontend {
log(" delete (* whitebox *) and (* lib_whitebox *) attributes from\n"); log(" delete (* whitebox *) and (* lib_whitebox *) attributes from\n");
log(" all modules.\n"); log(" all modules.\n");
log("\n"); log("\n");
log(" -specify\n");
log(" parse and import specify blocks\n");
log("\n");
log(" -noopt\n"); log(" -noopt\n");
log(" don't perform basic optimizations (such as const folding) in the\n"); log(" don't perform basic optimizations (such as const folding) in the\n");
log(" high-level front-end.\n"); log(" high-level front-end.\n");
@ -228,6 +231,8 @@ struct VerilogFrontend : public Frontend {
bool flag_nooverwrite = false; bool flag_nooverwrite = false;
bool flag_overwrite = false; bool flag_overwrite = false;
bool flag_defer = false; bool flag_defer = false;
bool flag_noblackbox = false;
bool flag_nowb = false;
std::map<std::string, std::string> defines_map; std::map<std::string, std::string> defines_map;
std::list<std::string> include_dirs; std::list<std::string> include_dirs;
std::list<std::string> attributes; std::list<std::string> attributes;
@ -237,9 +242,8 @@ struct VerilogFrontend : public Frontend {
formal_mode = false; formal_mode = false;
norestrict_mode = false; norestrict_mode = false;
assume_asserts_mode = false; assume_asserts_mode = false;
noblackbox_mode = false;
lib_mode = false; lib_mode = false;
nowb_mode = false; specify_mode = false;
default_nettype_wire = true; default_nettype_wire = true;
args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end()); args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end());
@ -340,7 +344,7 @@ struct VerilogFrontend : public Frontend {
continue; continue;
} }
if (arg == "-noblackbox") { if (arg == "-noblackbox") {
noblackbox_mode = true; flag_noblackbox = true;
continue; continue;
} }
if (arg == "-lib") { if (arg == "-lib") {
@ -349,7 +353,11 @@ struct VerilogFrontend : public Frontend {
continue; continue;
} }
if (arg == "-nowb") { if (arg == "-nowb") {
nowb_mode = true; flag_nowb = true;
continue;
}
if (arg == "-specify") {
specify_mode = true;
continue; continue;
} }
if (arg == "-noopt") { if (arg == "-noopt") {
@ -450,7 +458,7 @@ struct VerilogFrontend : public Frontend {
error_on_dpi_function(current_ast); error_on_dpi_function(current_ast);
AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches,
flag_nomeminit, flag_nomem2reg, flag_mem2reg, noblackbox_mode, lib_mode, nowb_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
if (!flag_nopp) if (!flag_nopp)
delete lexin; delete lexin;

View File

@ -69,14 +69,11 @@ namespace VERILOG_FRONTEND
// running in -assert-assumes mode // running in -assert-assumes mode
extern bool assert_assumes_mode; extern bool assert_assumes_mode;
// running in -noblackbox mode
extern bool noblackbox_mode;
// running in -lib mode // running in -lib mode
extern bool lib_mode; extern bool lib_mode;
// running in -nowb mode // running in -specify mode
extern bool nowb_mode; extern bool specify_mode;
// lexer input stream // lexer input stream
extern std::istream *lexin; extern std::istream *lexin;

View File

@ -148,7 +148,7 @@ YOSYS_NAMESPACE_END
"endfunction" { return TOK_ENDFUNCTION; } "endfunction" { return TOK_ENDFUNCTION; }
"task" { return TOK_TASK; } "task" { return TOK_TASK; }
"endtask" { return TOK_ENDTASK; } "endtask" { return TOK_ENDTASK; }
"specify" { return TOK_SPECIFY; } "specify" { return specify_mode ? TOK_SPECIFY : TOK_IGNORED_SPECIFY; }
"endspecify" { return TOK_ENDSPECIFY; } "endspecify" { return TOK_ENDSPECIFY; }
"specparam" { return TOK_SPECPARAM; } "specparam" { return TOK_SPECPARAM; }
"package" { SV_KEYWORD(TOK_PACKAGE); } "package" { SV_KEYWORD(TOK_PACKAGE); }
@ -206,7 +206,9 @@ YOSYS_NAMESPACE_END
"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); } "const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
"checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); } "checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); }
"endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); } "endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); }
"final" { SV_KEYWORD(TOK_FINAL); }
"logic" { SV_KEYWORD(TOK_LOGIC); } "logic" { SV_KEYWORD(TOK_LOGIC); }
"var" { SV_KEYWORD(TOK_VAR); }
"bit" { SV_KEYWORD(TOK_REG); } "bit" { SV_KEYWORD(TOK_REG); }
"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); } "eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
@ -301,6 +303,12 @@ supply1 { return TOK_SUPPLY1; }
return TOK_ID; return TOK_ID;
} }
"$"(setup|hold|setuphold|removal|recovery|recrem|skew|timeskew|fullskew|nochange) {
if (!specify_mode) REJECT;
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_ID;
}
"$signed" { return TOK_TO_SIGNED; } "$signed" { return TOK_TO_SIGNED; }
"$unsigned" { return TOK_TO_UNSIGNED; } "$unsigned" { return TOK_TO_UNSIGNED; }
@ -411,6 +419,17 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
"+:" { return TOK_POS_INDEXED; } "+:" { return TOK_POS_INDEXED; }
"-:" { return TOK_NEG_INDEXED; } "-:" { return TOK_NEG_INDEXED; }
[-+]?[=*]> {
if (!specify_mode) REJECT;
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_SPECIFY_OPER;
}
"&&&" {
if (!specify_mode) REJECT;
return TOK_SPECIFY_AND;
}
"/*" { BEGIN(COMMENT); } "/*" { BEGIN(COMMENT); }
<COMMENT>. /* ignore comment body */ <COMMENT>. /* ignore comment body */
<COMMENT>\n /* ignore comment body */ <COMMENT>\n /* ignore comment body */

View File

@ -59,7 +59,7 @@ namespace VERILOG_FRONTEND {
std::vector<char> case_type_stack; std::vector<char> case_type_stack;
bool do_not_require_port_stubs; bool do_not_require_port_stubs;
bool default_nettype_wire; bool default_nettype_wire;
bool sv_mode, formal_mode, noblackbox_mode, lib_mode, nowb_mode; bool sv_mode, formal_mode, lib_mode, specify_mode;
bool noassert_mode, noassume_mode, norestrict_mode; bool noassert_mode, noassume_mode, norestrict_mode;
bool assume_asserts_mode, assert_assumes_mode; bool assume_asserts_mode, assert_assumes_mode;
bool current_wire_rand, current_wire_const; bool current_wire_rand, current_wire_const;
@ -94,29 +94,58 @@ static void free_attr(std::map<std::string, AstNode*> *al)
delete al; delete al;
} }
struct specify_target {
char polarity_op;
AstNode *dst, *dat;
};
struct specify_triple {
AstNode *t_min, *t_avg, *t_max;
};
struct specify_rise_fall {
specify_triple rise;
specify_triple fall;
};
%} %}
%name-prefix "frontend_verilog_yy" %define api.prefix {frontend_verilog_yy}
/* The union is defined in the header, so we need to provide all the
* includes it requires
*/
%code requires {
#include <map>
#include <string>
#include "frontends/verilog/verilog_frontend.h"
}
%union { %union {
std::string *string; std::string *string;
struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast; struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast;
std::map<std::string, YOSYS_NAMESPACE_PREFIX AST::AstNode*> *al; std::map<std::string, YOSYS_NAMESPACE_PREFIX AST::AstNode*> *al;
struct specify_target *specify_target_ptr;
struct specify_triple *specify_triple_ptr;
struct specify_rise_fall *specify_rise_fall_ptr;
bool boolean; bool boolean;
char ch;
} }
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL %token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER %token <string> TOK_SVA_LABEL TOK_SPECIFY_OPER
%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER TOK_FINAL
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT %token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR
%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC %token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC
%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL %token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT %token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT
%token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC %token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC
%token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT %token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT
%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM %token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY
%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL %token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE %token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED %token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
@ -130,6 +159,12 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%type <boolean> opt_signed opt_property unique_case_attr %type <boolean> opt_signed opt_property unique_case_attr
%type <al> attr case_attr %type <al> attr case_attr
%type <specify_target_ptr> specify_target
%type <specify_triple_ptr> specify_triple
%type <specify_rise_fall_ptr> specify_rise_fall
%type <ast> specify_if specify_condition specify_opt_arg
%type <ch> specify_edge
// operator precedence from low to high // operator precedence from low to high
%left OP_LOR %left OP_LOR
%left OP_LAND %left OP_LAND
@ -456,6 +491,9 @@ wire_type_token:
TOK_LOGIC { TOK_LOGIC {
astbuf3->is_logic = true; astbuf3->is_logic = true;
} | } |
TOK_VAR {
astbuf3->is_logic = true;
} |
TOK_INTEGER { TOK_INTEGER {
astbuf3->is_reg = true; astbuf3->is_reg = true;
astbuf3->range_left = 31; astbuf3->range_left = 31;
@ -539,7 +577,7 @@ module_body:
module_body_stmt: module_body_stmt:
task_func_decl | specify_block |param_decl | localparam_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt | task_func_decl | specify_block |param_decl | localparam_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt |
always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl; always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block;
checker_decl: checker_decl:
TOK_CHECKER TOK_ID ';' { TOK_CHECKER TOK_ID ';' {
@ -697,15 +735,254 @@ task_func_body:
task_func_body behavioral_stmt | task_func_body behavioral_stmt |
/* empty */; /* empty */;
specify_block: /*************************** specify parser ***************************/
TOK_SPECIFY specify_item_opt TOK_ENDSPECIFY |
TOK_SPECIFY TOK_ENDSPECIFY ;
specify_item_opt: specify_block:
specify_item_opt specify_item | TOK_SPECIFY specify_item_list TOK_ENDSPECIFY;
specify_item ;
specify_item_list:
specify_item specify_item_list |
/* empty */;
specify_item: specify_item:
specify_if '(' specify_edge expr TOK_SPECIFY_OPER specify_target ')' '=' specify_rise_fall ';' {
AstNode *en_expr = $1;
char specify_edge = $3;
AstNode *src_expr = $4;
string *oper = $5;
specify_target *target = $6;
specify_rise_fall *timing = $9;
if (specify_edge != 0 && target->dat == nullptr)
frontend_verilog_yyerror("Found specify edge but no data spec.\n");
AstNode *cell = new AstNode(AST_CELL);
ast_stack.back()->children.push_back(cell);
cell->str = stringf("$specify$%d", autoidx++);
cell->children.push_back(new AstNode(AST_CELLTYPE));
cell->children.back()->str = target->dat ? "$specify3" : "$specify2";
char oper_polarity = 0;
char oper_type = oper->at(0);
if (oper->size() == 3) {
oper_polarity = oper->at(0);
oper_type = oper->at(1);
}
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_type == '*', false, 1)));
cell->children.back()->str = "\\FULL";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity != 0, false, 1)));
cell->children.back()->str = "\\SRC_DST_PEN";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity == '+', false, 1)));
cell->children.back()->str = "\\SRC_DST_POL";
cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_min));
cell->children.back()->str = "\\T_RISE_MIN";
cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_avg));
cell->children.back()->str = "\\T_RISE_TYP";
cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_max));
cell->children.back()->str = "\\T_RISE_MAX";
cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_min));
cell->children.back()->str = "\\T_FALL_MIN";
cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_avg));
cell->children.back()->str = "\\T_FALL_TYP";
cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_max));
cell->children.back()->str = "\\T_FALL_MAX";
cell->children.push_back(new AstNode(AST_ARGUMENT, en_expr ? en_expr : AstNode::mkconst_int(1, false, 1)));
cell->children.back()->str = "\\EN";
cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr));
cell->children.back()->str = "\\SRC";
cell->children.push_back(new AstNode(AST_ARGUMENT, target->dst));
cell->children.back()->str = "\\DST";
if (target->dat)
{
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge != 0, false, 1)));
cell->children.back()->str = "\\EDGE_EN";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge == 'p', false, 1)));
cell->children.back()->str = "\\EDGE_POL";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op != 0, false, 1)));
cell->children.back()->str = "\\DAT_DST_PEN";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op == '+', false, 1)));
cell->children.back()->str = "\\DAT_DST_POL";
cell->children.push_back(new AstNode(AST_ARGUMENT, target->dat));
cell->children.back()->str = "\\DAT";
}
delete oper;
delete target;
delete timing;
} |
TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' expr specify_opt_arg ')' ';' {
if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" &&
*$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange")
frontend_verilog_yyerror("Unsupported specify rule type: %s\n", $1->c_str());
AstNode *src_pen = AstNode::mkconst_int($3 != 0, false, 1);
AstNode *src_pol = AstNode::mkconst_int($3 == 'p', false, 1);
AstNode *src_expr = $4, *src_en = $5 ? $5 : AstNode::mkconst_int(1, false, 1);
AstNode *dst_pen = AstNode::mkconst_int($7 != 0, false, 1);
AstNode *dst_pol = AstNode::mkconst_int($7 == 'p', false, 1);
AstNode *dst_expr = $8, *dst_en = $9 ? $9 : AstNode::mkconst_int(1, false, 1);
AstNode *limit = $11;
AstNode *limit2 = $12;
AstNode *cell = new AstNode(AST_CELL);
ast_stack.back()->children.push_back(cell);
cell->str = stringf("$specify$%d", autoidx++);
cell->children.push_back(new AstNode(AST_CELLTYPE));
cell->children.back()->str = "$specrule";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_str(*$1)));
cell->children.back()->str = "\\TYPE";
cell->children.push_back(new AstNode(AST_PARASET, limit));
cell->children.back()->str = "\\T_LIMIT";
cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2 : AstNode::mkconst_int(0, true)));
cell->children.back()->str = "\\T_LIMIT2";
cell->children.push_back(new AstNode(AST_PARASET, src_pen));
cell->children.back()->str = "\\SRC_PEN";
cell->children.push_back(new AstNode(AST_PARASET, src_pol));
cell->children.back()->str = "\\SRC_POL";
cell->children.push_back(new AstNode(AST_PARASET, dst_pen));
cell->children.back()->str = "\\DST_PEN";
cell->children.push_back(new AstNode(AST_PARASET, dst_pol));
cell->children.back()->str = "\\DST_POL";
cell->children.push_back(new AstNode(AST_ARGUMENT, src_en));
cell->children.back()->str = "\\SRC_EN";
cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr));
cell->children.back()->str = "\\SRC";
cell->children.push_back(new AstNode(AST_ARGUMENT, dst_en));
cell->children.back()->str = "\\DST_EN";
cell->children.push_back(new AstNode(AST_ARGUMENT, dst_expr));
cell->children.back()->str = "\\DST";
delete $1;
};
specify_opt_arg:
',' expr {
$$ = $2;
} |
/* empty */ {
$$ = nullptr;
};
specify_if:
TOK_IF '(' expr ')' {
$$ = $3;
} |
/* empty */ {
$$ = nullptr;
};
specify_condition:
TOK_SPECIFY_AND expr {
$$ = $2;
} |
/* empty */ {
$$ = nullptr;
};
specify_target:
expr {
$$ = new specify_target;
$$->polarity_op = 0;
$$->dst = $1;
$$->dat = nullptr;
} |
'(' expr ':' expr ')'{
$$ = new specify_target;
$$->polarity_op = 0;
$$->dst = $2;
$$->dat = $4;
} |
'(' expr TOK_NEG_INDEXED expr ')'{
$$ = new specify_target;
$$->polarity_op = '-';
$$->dst = $2;
$$->dat = $4;
} |
'(' expr TOK_POS_INDEXED expr ')'{
$$ = new specify_target;
$$->polarity_op = '+';
$$->dst = $2;
$$->dat = $4;
};
specify_edge:
TOK_POSEDGE { $$ = 'p'; } |
TOK_NEGEDGE { $$ = 'n'; } |
{ $$ = 0; };
specify_rise_fall:
specify_triple {
$$ = new specify_rise_fall;
$$->rise = *$1;
$$->fall.t_min = $1->t_min->clone();
$$->fall.t_avg = $1->t_avg->clone();
$$->fall.t_max = $1->t_max->clone();
delete $1;
} |
'(' specify_triple ',' specify_triple ')' {
$$ = new specify_rise_fall;
$$->rise = *$2;
$$->fall = *$4;
delete $2;
delete $4;
};
specify_triple:
expr {
$$ = new specify_triple;
$$->t_min = $1;
$$->t_avg = $1->clone();
$$->t_max = $1->clone();
} |
expr ':' expr ':' expr {
$$ = new specify_triple;
$$->t_min = $1;
$$->t_avg = $3;
$$->t_max = $5;
};
/******************** ignored specify parser **************************/
ignored_specify_block:
TOK_IGNORED_SPECIFY ignored_specify_item_opt TOK_ENDSPECIFY |
TOK_IGNORED_SPECIFY TOK_ENDSPECIFY ;
ignored_specify_item_opt:
ignored_specify_item_opt ignored_specify_item |
ignored_specify_item ;
ignored_specify_item:
specparam_declaration specparam_declaration
// | pulsestyle_declaration // | pulsestyle_declaration
// | showcancelled_declaration // | showcancelled_declaration
@ -721,13 +998,13 @@ specparam_declaration:
// and the 'non_opt_range' rule allows index ranges not allowed by 1364-2005 // and the 'non_opt_range' rule allows index ranges not allowed by 1364-2005
// exxxxtending this for SV specparam would change this anyhow // exxxxtending this for SV specparam would change this anyhow
specparam_range: specparam_range:
'[' constant_expression ':' constant_expression ']' ; '[' ignspec_constant_expression ':' ignspec_constant_expression ']' ;
list_of_specparam_assignments: list_of_specparam_assignments:
specparam_assignment | list_of_specparam_assignments ',' specparam_assignment; specparam_assignment | list_of_specparam_assignments ',' specparam_assignment;
specparam_assignment: specparam_assignment:
TOK_ID '=' constant_mintypmax_expression ; ignspec_id '=' constant_mintypmax_expression ;
/* /*
pulsestyle_declaration : pulsestyle_declaration :
@ -802,19 +1079,19 @@ opt_polarity_operator :
// Good enough for the time being // Good enough for the time being
specify_input_terminal_descriptor : specify_input_terminal_descriptor :
TOK_ID ; ignspec_id ;
// Good enough for the time being // Good enough for the time being
specify_output_terminal_descriptor : specify_output_terminal_descriptor :
TOK_ID ; ignspec_id ;
system_timing_declaration : system_timing_declaration :
TOK_ID '(' system_timing_args ')' ';' ; ignspec_id '(' system_timing_args ')' ';' ;
system_timing_arg : system_timing_arg :
TOK_POSEDGE TOK_ID | TOK_POSEDGE ignspec_id |
TOK_NEGEDGE TOK_ID | TOK_NEGEDGE ignspec_id |
expr ; ignspec_expr ;
system_timing_args : system_timing_args :
system_timing_arg | system_timing_arg |
@ -871,19 +1148,27 @@ tzx_path_delay_expression :
*/ */
path_delay_expression : path_delay_expression :
constant_expression; ignspec_constant_expression;
constant_mintypmax_expression : constant_mintypmax_expression :
constant_expression ignspec_constant_expression
| constant_expression ':' constant_expression ':' constant_expression | ignspec_constant_expression ':' ignspec_constant_expression ':' ignspec_constant_expression
; ;
// for the time being this is OK, but we may write our own expr here. // for the time being this is OK, but we may write our own expr here.
// as I'm not sure it is legal to use a full expr here (probably not) // as I'm not sure it is legal to use a full expr here (probably not)
// On the other hand, other rules requiring constant expressions also use 'expr' // On the other hand, other rules requiring constant expressions also use 'expr'
// (such as param assignment), so we may leave this as-is, perhaps adding runtime checks for constant-ness // (such as param assignment), so we may leave this as-is, perhaps adding runtime checks for constant-ness
constant_expression: ignspec_constant_expression:
expr ; expr { delete $1; };
ignspec_expr:
expr { delete $1; };
ignspec_id:
TOK_ID { delete $1; };
/**********************************************************************/
param_signed: param_signed:
TOK_SIGNED { TOK_SIGNED {
@ -917,7 +1202,7 @@ param_range:
}; };
param_decl: param_decl:
TOK_PARAMETER { attr TOK_PARAMETER {
astbuf1 = new AstNode(AST_PARAMETER); astbuf1 = new AstNode(AST_PARAMETER);
astbuf1->children.push_back(AstNode::mkconst_int(0, true)); astbuf1->children.push_back(AstNode::mkconst_int(0, true));
} param_signed param_integer param_real param_range param_decl_list ';' { } param_signed param_integer param_real param_range param_decl_list ';' {
@ -925,7 +1210,7 @@ param_decl:
}; };
localparam_decl: localparam_decl:
TOK_LOCALPARAM { attr TOK_LOCALPARAM {
astbuf1 = new AstNode(AST_LOCALPARAM); astbuf1 = new AstNode(AST_LOCALPARAM);
astbuf1->children.push_back(AstNode::mkconst_int(0, true)); astbuf1->children.push_back(AstNode::mkconst_int(0, true));
} param_signed param_integer param_real param_range param_decl_list ';' { } param_signed param_integer param_real param_range param_decl_list ';' {
@ -1341,6 +1626,9 @@ opt_property:
TOK_PROPERTY { TOK_PROPERTY {
$$ = true; $$ = true;
} | } |
TOK_FINAL {
$$ = false;
} |
/* empty */ { /* empty */ {
$$ = false; $$ = false;
}; };
@ -2139,4 +2427,3 @@ concat_list:
$$ = $3; $$ = $3;
$$->children.push_back($1); $$->children.push_back($1);
}; };

View File

@ -85,6 +85,8 @@ struct CellTypes
setup_internals_eval(); setup_internals_eval();
IdString A = "\\A", B = "\\B", EN = "\\EN", Y = "\\Y"; IdString A = "\\A", B = "\\B", EN = "\\EN", Y = "\\Y";
IdString SRC = "\\SRC", DST = "\\DST", DAT = "\\DAT";
IdString EN_SRC = "\\EN_SRC", EN_DST = "\\EN_DST";
setup_type("$tribuf", {A, EN}, {Y}, true); setup_type("$tribuf", {A, EN}, {Y}, true);
@ -99,6 +101,9 @@ struct CellTypes
setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true); setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true); setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$equiv", {A, B}, {Y}, true); setup_type("$equiv", {A, B}, {Y}, true);
setup_type("$specify2", {EN, SRC, DST}, pool<RTLIL::IdString>(), true);
setup_type("$specify3", {EN, SRC, DST, DAT}, pool<RTLIL::IdString>(), true);
setup_type("$specrule", {EN_SRC, EN_DST, SRC, DST}, pool<RTLIL::IdString>(), true);
} }
void setup_internals_eval() void setup_internals_eval()

View File

@ -218,15 +218,19 @@ void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value)
{ {
if (value) if (value)
attributes[id] = RTLIL::Const(1); attributes[id] = RTLIL::Const(1);
else if (attributes.count(id)) else {
attributes.erase(id); const auto it = attributes.find(id);
if (it != attributes.end())
attributes.erase(it);
}
} }
bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const
{ {
if (attributes.count(id) == 0) const auto it = attributes.find(id);
if (it == attributes.end())
return false; return false;
return attributes.at(id).as_bool(); return it->second.as_bool();
} }
void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool<string> &data) void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool<string> &data)
@ -1194,6 +1198,46 @@ namespace {
return; return;
} }
if (cell->type.in("$specify2", "$specify3")) {
param_bool("\\FULL");
param_bool("\\SRC_DST_PEN");
param_bool("\\SRC_DST_POL");
param("\\T_RISE_MIN");
param("\\T_RISE_TYP");
param("\\T_RISE_MAX");
param("\\T_FALL_MIN");
param("\\T_FALL_TYP");
param("\\T_FALL_MAX");
port("\\EN", 1);
port("\\SRC", param("\\SRC_WIDTH"));
port("\\DST", param("\\DST_WIDTH"));
if (cell->type == "$specify3") {
param_bool("\\EDGE_EN");
param_bool("\\EDGE_POL");
param_bool("\\DAT_DST_PEN");
param_bool("\\DAT_DST_POL");
port("\\DAT", param("\\DST_WIDTH"));
}
check_expected();
return;
}
if (cell->type == "$specrule") {
param("\\TYPE");
param_bool("\\SRC_PEN");
param_bool("\\SRC_POL");
param_bool("\\DST_PEN");
param_bool("\\DST_POL");
param("\\T_LIMIT");
param("\\T_LIMIT2");
port("\\SRC_EN", 1);
port("\\DST_EN", 1);
port("\\SRC", param("\\SRC_WIDTH"));
port("\\DST", param("\\DST_WIDTH"));
check_expected();
return;
}
if (cell->type == "$_BUF_") { check_gate("AY"); return; } if (cell->type == "$_BUF_") { check_gate("AY"); return; }
if (cell->type == "$_NOT_") { check_gate("AY"); return; } if (cell->type == "$_NOT_") { check_gate("AY"); return; }
if (cell->type == "$_AND_") { check_gate("ABY"); return; } if (cell->type == "$_AND_") { check_gate("ABY"); return; }
@ -1470,7 +1514,10 @@ void RTLIL::Module::add(RTLIL::Cell *cell)
cell->module = this; cell->module = this;
} }
namespace { void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
{
log_assert(refcount_wires_ == 0);
struct DeleteWireWorker struct DeleteWireWorker
{ {
RTLIL::Module *module; RTLIL::Module *module;
@ -1485,17 +1532,29 @@ namespace {
} }
sig = chunks; sig = chunks;
} }
};
}
void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires) void operator()(RTLIL::SigSpec &lhs, RTLIL::SigSpec &rhs) {
{ log_assert(GetSize(lhs) == GetSize(rhs));
log_assert(refcount_wires_ == 0); RTLIL::SigSpec new_lhs, new_rhs;
for (int i = 0; i < GetSize(lhs); i++) {
RTLIL::SigBit lhs_bit = lhs[i];
if (lhs_bit.wire != nullptr && wires_p->count(lhs_bit.wire))
continue;
RTLIL::SigBit rhs_bit = rhs[i];
if (rhs_bit.wire != nullptr && wires_p->count(rhs_bit.wire))
continue;
new_lhs.append(lhs_bit);
new_rhs.append(rhs_bit);
}
lhs = new_lhs;
rhs = new_rhs;
}
};
DeleteWireWorker delete_wire_worker; DeleteWireWorker delete_wire_worker;
delete_wire_worker.module = this; delete_wire_worker.module = this;
delete_wire_worker.wires_p = &wires; delete_wire_worker.wires_p = &wires;
rewrite_sigspecs(delete_wire_worker); rewrite_sigspecs2(delete_wire_worker);
for (auto &it : wires) { for (auto &it : wires) {
log_assert(wires_.count(it->name) != 0); log_assert(wires_.count(it->name) != 0);

View File

@ -50,7 +50,7 @@ namespace RTLIL
CONST_FLAG_NONE = 0, CONST_FLAG_NONE = 0,
CONST_FLAG_STRING = 1, CONST_FLAG_STRING = 1,
CONST_FLAG_SIGNED = 2, // only used for parameters CONST_FLAG_SIGNED = 2, // only used for parameters
CONST_FLAG_REAL = 4 // unused -- to be used for parameters CONST_FLAG_REAL = 4 // only used for parameters
}; };
struct Const; struct Const;
@ -518,6 +518,7 @@ struct RTLIL::Const
Const(const std::vector<RTLIL::State> &bits) : bits(bits) { flags = CONST_FLAG_NONE; } Const(const std::vector<RTLIL::State> &bits) : bits(bits) { flags = CONST_FLAG_NONE; }
Const(const std::vector<bool> &bits); Const(const std::vector<bool> &bits);
Const(const RTLIL::Const &c); Const(const RTLIL::Const &c);
RTLIL::Const &operator =(const RTLIL::Const &other) = default;
bool operator <(const RTLIL::Const &other) const; bool operator <(const RTLIL::Const &other) const;
bool operator ==(const RTLIL::Const &other) const; bool operator ==(const RTLIL::Const &other) const;
@ -597,6 +598,7 @@ struct RTLIL::SigChunk
SigChunk(RTLIL::State bit, int width = 1); SigChunk(RTLIL::State bit, int width = 1);
SigChunk(RTLIL::SigBit bit); SigChunk(RTLIL::SigBit bit);
SigChunk(const RTLIL::SigChunk &sigchunk); SigChunk(const RTLIL::SigChunk &sigchunk);
RTLIL::SigChunk &operator =(const RTLIL::SigChunk &other) = default;
RTLIL::SigChunk extract(int offset, int length) const; RTLIL::SigChunk extract(int offset, int length) const;
@ -622,6 +624,7 @@ struct RTLIL::SigBit
SigBit(const RTLIL::SigChunk &chunk, int index); SigBit(const RTLIL::SigChunk &chunk, int index);
SigBit(const RTLIL::SigSpec &sig); SigBit(const RTLIL::SigSpec &sig);
SigBit(const RTLIL::SigBit &sigbit); SigBit(const RTLIL::SigBit &sigbit);
RTLIL::SigBit &operator =(const RTLIL::SigBit &other) = default;
bool operator <(const RTLIL::SigBit &other) const; bool operator <(const RTLIL::SigBit &other) const;
bool operator ==(const RTLIL::SigBit &other) const; bool operator ==(const RTLIL::SigBit &other) const;
@ -998,6 +1001,7 @@ public:
void fixup_ports(); void fixup_ports();
template<typename T> void rewrite_sigspecs(T &functor); template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
void cloneInto(RTLIL::Module *new_mod) const; void cloneInto(RTLIL::Module *new_mod) const;
virtual RTLIL::Module *clone() const; virtual RTLIL::Module *clone() const;
@ -1303,6 +1307,7 @@ public:
} }
template<typename T> void rewrite_sigspecs(T &functor); template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
#ifdef WITH_PYTHON #ifdef WITH_PYTHON
static std::map<unsigned int, RTLIL::Cell*> *get_all_cells(void); static std::map<unsigned int, RTLIL::Cell*> *get_all_cells(void);
@ -1321,6 +1326,7 @@ struct RTLIL::CaseRule
bool empty() const; bool empty() const;
template<typename T> void rewrite_sigspecs(T &functor); template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
RTLIL::CaseRule *clone() const; RTLIL::CaseRule *clone() const;
}; };
@ -1334,6 +1340,7 @@ struct RTLIL::SwitchRule : public RTLIL::AttrObject
bool empty() const; bool empty() const;
template<typename T> void rewrite_sigspecs(T &functor); template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
RTLIL::SwitchRule *clone() const; RTLIL::SwitchRule *clone() const;
}; };
@ -1344,6 +1351,7 @@ struct RTLIL::SyncRule
std::vector<RTLIL::SigSig> actions; std::vector<RTLIL::SigSig> actions;
template<typename T> void rewrite_sigspecs(T &functor); template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
RTLIL::SyncRule *clone() const; RTLIL::SyncRule *clone() const;
}; };
@ -1356,6 +1364,7 @@ struct RTLIL::Process : public RTLIL::AttrObject
~Process(); ~Process();
template<typename T> void rewrite_sigspecs(T &functor); template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
RTLIL::Process *clone() const; RTLIL::Process *clone() const;
}; };
@ -1417,12 +1426,30 @@ void RTLIL::Module::rewrite_sigspecs(T &functor)
} }
} }
template<typename T>
void RTLIL::Module::rewrite_sigspecs2(T &functor)
{
for (auto &it : cells_)
it.second->rewrite_sigspecs2(functor);
for (auto &it : processes)
it.second->rewrite_sigspecs2(functor);
for (auto &it : connections_) {
functor(it.first, it.second);
}
}
template<typename T> template<typename T>
void RTLIL::Cell::rewrite_sigspecs(T &functor) { void RTLIL::Cell::rewrite_sigspecs(T &functor) {
for (auto &it : connections_) for (auto &it : connections_)
functor(it.second); functor(it.second);
} }
template<typename T>
void RTLIL::Cell::rewrite_sigspecs2(T &functor) {
for (auto &it : connections_)
functor(it.second);
}
template<typename T> template<typename T>
void RTLIL::CaseRule::rewrite_sigspecs(T &functor) { void RTLIL::CaseRule::rewrite_sigspecs(T &functor) {
for (auto &it : compare) for (auto &it : compare)
@ -1435,6 +1462,17 @@ void RTLIL::CaseRule::rewrite_sigspecs(T &functor) {
it->rewrite_sigspecs(functor); it->rewrite_sigspecs(functor);
} }
template<typename T>
void RTLIL::CaseRule::rewrite_sigspecs2(T &functor) {
for (auto &it : compare)
functor(it);
for (auto &it : actions) {
functor(it.first, it.second);
}
for (auto it : switches)
it->rewrite_sigspecs2(functor);
}
template<typename T> template<typename T>
void RTLIL::SwitchRule::rewrite_sigspecs(T &functor) void RTLIL::SwitchRule::rewrite_sigspecs(T &functor)
{ {
@ -1443,6 +1481,14 @@ void RTLIL::SwitchRule::rewrite_sigspecs(T &functor)
it->rewrite_sigspecs(functor); it->rewrite_sigspecs(functor);
} }
template<typename T>
void RTLIL::SwitchRule::rewrite_sigspecs2(T &functor)
{
functor(signal);
for (auto it : cases)
it->rewrite_sigspecs2(functor);
}
template<typename T> template<typename T>
void RTLIL::SyncRule::rewrite_sigspecs(T &functor) void RTLIL::SyncRule::rewrite_sigspecs(T &functor)
{ {
@ -1453,6 +1499,15 @@ void RTLIL::SyncRule::rewrite_sigspecs(T &functor)
} }
} }
template<typename T>
void RTLIL::SyncRule::rewrite_sigspecs2(T &functor)
{
functor(signal);
for (auto &it : actions) {
functor(it.first, it.second);
}
}
template<typename T> template<typename T>
void RTLIL::Process::rewrite_sigspecs(T &functor) void RTLIL::Process::rewrite_sigspecs(T &functor)
{ {
@ -1461,6 +1516,14 @@ void RTLIL::Process::rewrite_sigspecs(T &functor)
it->rewrite_sigspecs(functor); it->rewrite_sigspecs(functor);
} }
template<typename T>
void RTLIL::Process::rewrite_sigspecs2(T &functor)
{
root_case.rewrite_sigspecs2(functor);
for (auto it : syncs)
it->rewrite_sigspecs2(functor);
}
YOSYS_NAMESPACE_END YOSYS_NAMESPACE_END
#endif #endif

View File

@ -151,14 +151,16 @@ void yosys_banner()
int ceil_log2(int x) int ceil_log2(int x)
{ {
#if defined(__GNUC__)
return x > 1 ? (8*sizeof(int)) - __builtin_clz(x-1) : 0;
#else
if (x <= 0) if (x <= 0)
return 0; return 0;
for (int i = 0; i < 32; i++) for (int i = 0; i < 32; i++)
if (((x-1) >> i) == 0) if (((x-1) >> i) == 0)
return i; return i;
log_abort(); log_abort();
#endif
} }
std::string stringf(const char *fmt, ...) std::string stringf(const char *fmt, ...)

View File

@ -244,7 +244,7 @@ extern bool memhasher_active;
inline void memhasher() { if (memhasher_active) memhasher_do(); } inline void memhasher() { if (memhasher_active) memhasher_do(); }
void yosys_banner(); void yosys_banner();
int ceil_log2(int x); int ceil_log2(int x) YS_ATTRIBUTE(const);
std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)); std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2));
std::string vstringf(const char *fmt, va_list ap); std::string vstringf(const char *fmt, va_list ap);
int readsome(std::istream &f, char *s, int n); int readsome(std::istream &f, char *s, int n);

View File

@ -465,6 +465,10 @@ Add information about {\tt \$assert}, {\tt \$assume}, {\tt \$live}, {\tt \$fair}
{\tt \$initstate}, {\tt \$anyconst}, {\tt \$anyseq}, {\tt \$allconst}, {\tt \$allseq} cells. {\tt \$initstate}, {\tt \$anyconst}, {\tt \$anyseq}, {\tt \$allconst}, {\tt \$allseq} cells.
\end{fixme} \end{fixme}
\begin{fixme}
Add information about {\tt \$specify2}, {\tt \$specify3}, and {\tt \$specrule} cells.
\end{fixme}
\begin{fixme} \begin{fixme}
Add information about {\tt \$slice} and {\tt \$concat} cells. Add information about {\tt \$slice} and {\tt \$concat} cells.
\end{fixme} \end{fixme}

View File

@ -281,6 +281,9 @@ struct BugpointPass : public Pass {
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
if (script.empty())
log_cmd_error("Missing -script option.\n");
if (!has_part) if (!has_part)
{ {
modules = true; modules = true;
@ -298,7 +301,7 @@ struct BugpointPass : public Pass {
if (!check_logfile(grep)) if (!check_logfile(grep))
log_cmd_error("The provided grep string is not found in the log file!\n"); log_cmd_error("The provided grep string is not found in the log file!\n");
int seed = 0, crashing_seed = seed; int seed = 0;
bool found_something = false, stage2 = false; bool found_something = false, stage2 = false;
while (true) while (true)
{ {
@ -324,7 +327,6 @@ struct BugpointPass : public Pass {
if (crashing_design != design) if (crashing_design != design)
delete crashing_design; delete crashing_design;
crashing_design = simplified; crashing_design = simplified;
crashing_seed = seed;
found_something = true; found_something = true;
} }
else else

View File

@ -98,21 +98,23 @@ struct CoverPass : public Pass {
} }
if ((args[argidx] == "-o" || args[argidx] == "-a" || args[argidx] == "-d") && argidx+1 < args.size()) { if ((args[argidx] == "-o" || args[argidx] == "-a" || args[argidx] == "-d") && argidx+1 < args.size()) {
const char *open_mode = args[argidx] == "-a" ? "a+" : "w"; const char *open_mode = args[argidx] == "-a" ? "a+" : "w";
std::string filename = args[++argidx]; const std::string &filename = args[++argidx];
FILE *f = nullptr;
if (args[argidx-1] == "-d") { if (args[argidx-1] == "-d") {
#ifdef _WIN32 #ifdef _WIN32
log_cmd_error("The 'cover -d' option is not supported on win32.\n"); log_cmd_error("The 'cover -d' option is not supported on win32.\n");
#else #else
char filename_buffer[4096]; char filename_buffer[4096];
snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", filename.c_str(), getpid()); snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", filename.c_str(), getpid());
filename = mkstemps(filename_buffer, 4); f = fdopen(mkstemps(filename_buffer, 4), "w");
#endif #endif
} else {
f = fopen(filename.c_str(), open_mode);
} }
FILE *f = fopen(filename.c_str(), open_mode);
if (f == NULL) { if (f == NULL) {
for (auto f : out_files) for (auto f : out_files)
fclose(f); fclose(f);
log_cmd_error("Can't create file %s.\n", args[argidx].c_str()); log_cmd_error("Can't create file %s%s.\n", args[argidx-1] == "-d" ? "in directory " : "", args[argidx].c_str());
} }
out_files.push_back(f); out_files.push_back(f);
continue; continue;

View File

@ -37,7 +37,9 @@ struct statdata_t
STAT_INT_MEMBERS STAT_INT_MEMBERS
#undef X #undef X
double area; double area;
string tech;
std::map<RTLIL::IdString, int> techinfo;
std::map<RTLIL::IdString, int, RTLIL::sort_by_id_str> num_cells_by_type; std::map<RTLIL::IdString, int, RTLIL::sort_by_id_str> num_cells_by_type;
std::set<RTLIL::IdString> unknown_cell_area; std::set<RTLIL::IdString> unknown_cell_area;
@ -70,8 +72,10 @@ struct statdata_t
#undef X #undef X
} }
statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode, const dict<IdString, double> &cell_area) statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode, const dict<IdString, double> &cell_area, string techname)
{ {
tech = techname;
#define X(_name) _name = 0; #define X(_name) _name = 0;
STAT_NUMERIC_MEMBERS STAT_NUMERIC_MEMBERS
#undef X #undef X
@ -153,7 +157,8 @@ struct statdata_t
log(" Number of processes: %6d\n", num_processes); log(" Number of processes: %6d\n", num_processes);
log(" Number of cells: %6d\n", num_cells); log(" Number of cells: %6d\n", num_cells);
for (auto &it : num_cells_by_type) for (auto &it : num_cells_by_type)
log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second); if (it.second)
log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second);
if (!unknown_cell_area.empty()) { if (!unknown_cell_area.empty()) {
log("\n"); log("\n");
@ -165,6 +170,59 @@ struct statdata_t
log("\n"); log("\n");
log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area); log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area);
} }
if (tech == "xilinx")
{
int lut6_cnt = num_cells_by_type["\\LUT6"];
int lut5_cnt = num_cells_by_type["\\LUT5"];
int lut4_cnt = num_cells_by_type["\\LUT4"];
int lut3_cnt = num_cells_by_type["\\LUT3"];
int lut2_cnt = num_cells_by_type["\\LUT2"];
int lut1_cnt = num_cells_by_type["\\LUT1"];
int lc_cnt = 0;
lc_cnt += lut6_cnt;
lc_cnt += lut5_cnt;
if (lut1_cnt) {
int cnt = std::min(lut5_cnt, lut1_cnt);
lut5_cnt -= cnt;
lut1_cnt -= cnt;
}
lc_cnt += lut4_cnt;
if (lut1_cnt) {
int cnt = std::min(lut4_cnt, lut1_cnt);
lut4_cnt -= cnt;
lut1_cnt -= cnt;
}
if (lut2_cnt) {
int cnt = std::min(lut4_cnt, lut2_cnt);
lut4_cnt -= cnt;
lut2_cnt -= cnt;
}
lc_cnt += lut3_cnt;
if (lut1_cnt) {
int cnt = std::min(lut3_cnt, lut1_cnt);
lut3_cnt -= cnt;
lut1_cnt -= cnt;
}
if (lut2_cnt) {
int cnt = std::min(lut3_cnt, lut2_cnt);
lut3_cnt -= cnt;
lut2_cnt -= cnt;
}
if (lut3_cnt) {
int cnt = (lut3_cnt + 1) / 2;
lut3_cnt -= cnt;
}
lc_cnt += (lut2_cnt + lut1_cnt + 1) / 2;
log("\n");
log(" Estimated number of LCs: %10d\n", lc_cnt);
}
} }
}; };
@ -226,6 +284,10 @@ struct StatPass : public Pass {
log(" -liberty <liberty_file>\n"); log(" -liberty <liberty_file>\n");
log(" use cell area information from the provided liberty file\n"); log(" use cell area information from the provided liberty file\n");
log("\n"); log("\n");
log(" -tech <technology>\n");
log(" print area estemate for the specified technology. Corrently supported\n");
log(" calues for <technology>: xilinx\n");
log("\n");
log(" -width\n"); log(" -width\n");
log(" annotate internal cell types with their word width.\n"); log(" annotate internal cell types with their word width.\n");
log(" e.g. $add_8 for an 8 bit wide $add cell.\n"); log(" e.g. $add_8 for an 8 bit wide $add cell.\n");
@ -239,6 +301,7 @@ struct StatPass : public Pass {
RTLIL::Module *top_mod = NULL; RTLIL::Module *top_mod = NULL;
std::map<RTLIL::IdString, statdata_t> mod_stat; std::map<RTLIL::IdString, statdata_t> mod_stat;
dict<IdString, double> cell_area; dict<IdString, double> cell_area;
string techname;
size_t argidx; size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) for (argidx = 1; argidx < args.size(); argidx++)
@ -253,6 +316,10 @@ struct StatPass : public Pass {
read_liberty_cellarea(cell_area, liberty_file); read_liberty_cellarea(cell_area, liberty_file);
continue; continue;
} }
if (args[argidx] == "-tech" && argidx+1 < args.size()) {
techname = args[++argidx];
continue;
}
if (args[argidx] == "-top" && argidx+1 < args.size()) { if (args[argidx] == "-top" && argidx+1 < args.size()) {
if (design->modules_.count(RTLIL::escape_id(args[argidx+1])) == 0) if (design->modules_.count(RTLIL::escape_id(args[argidx+1])) == 0)
log_cmd_error("Can't find module %s.\n", args[argidx+1].c_str()); log_cmd_error("Can't find module %s.\n", args[argidx+1].c_str());
@ -263,13 +330,16 @@ struct StatPass : public Pass {
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
if (techname != "" && techname != "xilinx")
log_cmd_error("Unsupported technology: '%s'\n", techname.c_str());
for (auto mod : design->selected_modules()) for (auto mod : design->selected_modules())
{ {
if (!top_mod && design->full_selection()) if (!top_mod && design->full_selection())
if (mod->get_bool_attribute("\\top")) if (mod->get_bool_attribute("\\top"))
top_mod = mod; top_mod = mod;
statdata_t data(design, mod, width_mode, cell_area); statdata_t data(design, mod, width_mode, cell_area, techname);
mod_stat[mod->name] = data; mod_stat[mod->name] = data;
log("\n"); log("\n");

View File

@ -570,7 +570,7 @@ struct HierarchyPass : public Pass {
log("\n"); log("\n");
log(" -simcheck\n"); log(" -simcheck\n");
log(" like -check, but also throw an error if blackbox modules are\n"); log(" like -check, but also throw an error if blackbox modules are\n");
log(" instantiated, and throw an error if the design has no top module\n"); log(" instantiated, and throw an error if the design has no top module.\n");
log("\n"); log("\n");
log(" -purge_lib\n"); log(" -purge_lib\n");
log(" by default the hierarchy command will not remove library (blackbox)\n"); log(" by default the hierarchy command will not remove library (blackbox)\n");
@ -583,20 +583,20 @@ struct HierarchyPass : public Pass {
log("\n"); log("\n");
log(" -keep_positionals\n"); log(" -keep_positionals\n");
log(" per default this pass also converts positional arguments in cells\n"); log(" per default this pass also converts positional arguments in cells\n");
log(" to arguments using port names. this option disables this behavior.\n"); log(" to arguments using port names. This option disables this behavior.\n");
log("\n"); log("\n");
log(" -keep_portwidths\n"); log(" -keep_portwidths\n");
log(" per default this pass adjusts the port width on cells that are\n"); log(" per default this pass adjusts the port width on cells that are\n");
log(" module instances when the width does not match the module port. this\n"); log(" module instances when the width does not match the module port. This\n");
log(" option disables this behavior.\n"); log(" option disables this behavior.\n");
log("\n"); log("\n");
log(" -nokeep_asserts\n"); log(" -nokeep_asserts\n");
log(" per default this pass sets the \"keep\" attribute on all modules\n"); log(" per default this pass sets the \"keep\" attribute on all modules\n");
log(" that directly or indirectly contain one or more $assert cells. this\n"); log(" that directly or indirectly contain one or more formal properties.\n");
log(" option disables this behavior.\n"); log(" This option disables this behavior.\n");
log("\n"); log("\n");
log(" -top <module>\n"); log(" -top <module>\n");
log(" use the specified top module to built a design hierarchy. modules\n"); log(" use the specified top module to build the design hierarchy. Modules\n");
log(" outside this tree (unused modules) are removed.\n"); log(" outside this tree (unused modules) are removed.\n");
log("\n"); log("\n");
log(" when the -top option is used, the 'top' attribute will be set on the\n"); log(" when the -top option is used, the 'top' attribute will be set on the\n");
@ -606,6 +606,12 @@ struct HierarchyPass : public Pass {
log(" -auto-top\n"); log(" -auto-top\n");
log(" automatically determine the top of the design hierarchy and mark it.\n"); log(" automatically determine the top of the design hierarchy and mark it.\n");
log("\n"); log("\n");
log(" -chparam name value \n");
log(" elaborate the top module using this parameter value. Modules on which\n");
log(" this parameter does not exist may cause a warning message to be output.\n");
log(" This option can be specified multiple times to override multiple\n");
log(" parameters. String values must be passed in double quotes (\").\n");
log("\n");
log("In -generate mode this pass generates blackbox modules for the given cell\n"); log("In -generate mode this pass generates blackbox modules for the given cell\n");
log("types (wildcards supported). For this the design is searched for cells that\n"); log("types (wildcards supported). For this the design is searched for cells that\n");
log("match the given types and then the given port declarations are used to\n"); log("match the given types and then the given port declarations are used to\n");
@ -641,6 +647,7 @@ struct HierarchyPass : public Pass {
bool nokeep_asserts = false; bool nokeep_asserts = false;
std::vector<std::string> generate_cells; std::vector<std::string> generate_cells;
std::vector<generate_port_decl_t> generate_ports; std::vector<generate_port_decl_t> generate_ports;
std::map<std::string, std::string> parameters;
size_t argidx; size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) for (argidx = 1; argidx < args.size(); argidx++)
@ -715,28 +722,61 @@ struct HierarchyPass : public Pass {
if (args[argidx] == "-top") { if (args[argidx] == "-top") {
if (++argidx >= args.size()) if (++argidx >= args.size())
log_cmd_error("Option -top requires an additional argument!\n"); log_cmd_error("Option -top requires an additional argument!\n");
top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL; load_top_mod = args[argidx];
if (top_mod == NULL && design->modules_.count("$abstract" + RTLIL::escape_id(args[argidx]))) {
dict<RTLIL::IdString, RTLIL::Const> empty_parameters;
design->modules_.at("$abstract" + RTLIL::escape_id(args[argidx]))->derive(design, empty_parameters);
top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
}
if (top_mod == NULL)
load_top_mod = args[argidx];
continue; continue;
} }
if (args[argidx] == "-auto-top") { if (args[argidx] == "-auto-top") {
auto_top_mode = true; auto_top_mode = true;
continue; continue;
} }
if (args[argidx] == "-chparam" && argidx+2 < args.size()) {
const std::string &key = args[++argidx];
const std::string &value = args[++argidx];
auto r = parameters.emplace(key, value);
if (!r.second) {
log_warning("-chparam %s already specified: overwriting.\n", key.c_str());
r.first->second = value;
}
continue;
}
break; break;
} }
extra_args(args, argidx, design, false); extra_args(args, argidx, design, false);
if (!load_top_mod.empty()) { if (!load_top_mod.empty())
{
IdString top_name = RTLIL::escape_id(load_top_mod);
IdString abstract_id = "$abstract" + RTLIL::escape_id(load_top_mod);
top_mod = design->module(top_name);
dict<RTLIL::IdString, RTLIL::Const> top_parameters;
for (auto &para : parameters) {
SigSpec sig_value;
if (!RTLIL::SigSpec::parse(sig_value, NULL, para.second))
log_cmd_error("Can't decode value '%s'!\n", para.second.c_str());
top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const();
}
if (top_mod == nullptr && design->module(abstract_id))
top_mod = design->module(design->module(abstract_id)->derive(design, top_parameters));
else if (top_mod != nullptr && !top_parameters.empty())
top_mod = design->module(top_mod->derive(design, top_parameters));
if (top_mod != nullptr && top_mod->name != top_name) {
Module *m = top_mod->clone();
m->name = top_name;
Module *old_mod = design->module(top_name);
if (old_mod)
design->remove(old_mod);
design->add(m);
top_mod = m;
}
}
if (top_mod == nullptr && !load_top_mod.empty()) {
#ifdef YOSYS_ENABLE_VERIFIC #ifdef YOSYS_ENABLE_VERIFIC
if (verific_import_pending) { if (verific_import_pending) {
verific_import(design, load_top_mod); verific_import(design, parameters, load_top_mod);
top_mod = design->module(RTLIL::escape_id(load_top_mod)); top_mod = design->module(RTLIL::escape_id(load_top_mod));
} }
#endif #endif
@ -745,7 +785,7 @@ struct HierarchyPass : public Pass {
} else { } else {
#ifdef YOSYS_ENABLE_VERIFIC #ifdef YOSYS_ENABLE_VERIFIC
if (verific_import_pending) if (verific_import_pending)
verific_import(design); verific_import(design, parameters);
#endif #endif
} }
@ -846,7 +886,7 @@ struct HierarchyPass : public Pass {
std::map<RTLIL::Module*, bool> cache; std::map<RTLIL::Module*, bool> cache;
for (auto mod : design->modules()) for (auto mod : design->modules())
if (set_keep_assert(cache, mod)) { if (set_keep_assert(cache, mod)) {
log("Module %s directly or indirectly contains $assert cells -> setting \"keep\" attribute.\n", log_id(mod)); log("Module %s directly or indirectly contains formal properties -> setting \"keep\" attribute.\n", log_id(mod));
mod->set_bool_attribute("\\keep"); mod->set_bool_attribute("\\keep");
} }
} }

View File

@ -64,7 +64,7 @@ struct keep_cache_t
bool query(Cell *cell) bool query(Cell *cell)
{ {
if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover")) if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover", "$specify2", "$specify3", "$specrule"))
return true; return true;
if (cell->has_keep_attr()) if (cell->has_keep_attr())
@ -85,22 +85,34 @@ void rmunused_module_cells(Module *module, bool verbose)
{ {
SigMap sigmap(module); SigMap sigmap(module);
pool<Cell*> queue, unused; pool<Cell*> queue, unused;
pool<SigBit> used_raw_bits;
dict<SigBit, pool<Cell*>> wire2driver; dict<SigBit, pool<Cell*>> wire2driver;
dict<SigBit, vector<string>> driver_driver_logs;
SigMap raw_sigmap;
for (auto &it : module->connections_) {
for (int i = 0; i < GetSize(it.second); i++) {
if (it.second[i].wire != nullptr)
raw_sigmap.add(it.first[i], it.second[i]);
}
}
for (auto &it : module->cells_) { for (auto &it : module->cells_) {
Cell *cell = it.second; Cell *cell = it.second;
for (auto &it2 : cell->connections()) { for (auto &it2 : cell->connections()) {
if (!ct_all.cell_known(cell->type) || ct_all.cell_output(cell->type, it2.first)) if (ct_all.cell_known(cell->type) && !ct_all.cell_output(cell->type, it2.first))
for (auto raw_bit : it2.second) { continue;
if (raw_bit.wire == nullptr) for (auto raw_bit : it2.second) {
continue; if (raw_bit.wire == nullptr)
auto bit = sigmap(raw_bit); continue;
if (bit.wire == nullptr) auto bit = sigmap(raw_bit);
log_warning("Driver-driver conflict for %s between cell %s.%s and constant %s in %s: Resolved using constant.\n", if (bit.wire == nullptr)
log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module)); driver_driver_logs[raw_sigmap(raw_bit)].push_back(stringf("Driver-driver conflict "
if (bit.wire != nullptr) "for %s between cell %s.%s and constant %s in %s: Resolved using constant.",
wire2driver[bit].insert(cell); log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module)));
} if (bit.wire != nullptr)
wire2driver[bit].insert(cell);
}
} }
if (keep_cache.query(cell)) if (keep_cache.query(cell))
queue.insert(cell); queue.insert(cell);
@ -114,6 +126,8 @@ void rmunused_module_cells(Module *module, bool verbose)
for (auto bit : sigmap(wire)) for (auto bit : sigmap(wire))
for (auto c : wire2driver[bit]) for (auto c : wire2driver[bit])
queue.insert(c), unused.erase(c); queue.insert(c), unused.erase(c);
for (auto raw_bit : SigSpec(wire))
used_raw_bits.insert(raw_sigmap(raw_bit));
} }
} }
@ -142,6 +156,22 @@ void rmunused_module_cells(Module *module, bool verbose)
module->remove(cell); module->remove(cell);
count_rm_cells++; count_rm_cells++;
} }
for (auto &it : module->cells_) {
Cell *cell = it.second;
for (auto &it2 : cell->connections()) {
if (ct_all.cell_known(cell->type) && !ct_all.cell_input(cell->type, it2.first))
continue;
for (auto raw_bit : raw_sigmap(it2.second))
used_raw_bits.insert(raw_bit);
}
}
for (auto it : driver_driver_logs) {
if (used_raw_bits.count(it.first))
for (auto msg : it.second)
log_warning("%s\n", msg.c_str());
}
} }
int count_nontrivial_wire_attrs(RTLIL::Wire *w) int count_nontrivial_wire_attrs(RTLIL::Wire *w)
@ -202,7 +232,7 @@ bool check_public_name(RTLIL::IdString id)
return true; return true;
} }
void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose) bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose)
{ {
SigPool register_signals; SigPool register_signals;
SigPool connected_signals; SigPool connected_signals;
@ -245,11 +275,13 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
module->connections_.clear(); module->connections_.clear();
SigPool used_signals; SigPool used_signals;
SigPool raw_used_signals;
SigPool used_signals_nodrivers; SigPool used_signals_nodrivers;
for (auto &it : module->cells_) { for (auto &it : module->cells_) {
RTLIL::Cell *cell = it.second; RTLIL::Cell *cell = it.second;
for (auto &it2 : cell->connections_) { for (auto &it2 : cell->connections_) {
assign_map.apply(it2.second); assign_map.apply(it2.second);
raw_used_signals.add(it2.second);
used_signals.add(it2.second); used_signals.add(it2.second);
if (!ct_all.cell_output(cell->type, it2.first)) if (!ct_all.cell_output(cell->type, it2.first))
used_signals_nodrivers.add(it2.second); used_signals_nodrivers.add(it2.second);
@ -259,6 +291,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
RTLIL::Wire *wire = it.second; RTLIL::Wire *wire = it.second;
if (wire->port_id > 0) { if (wire->port_id > 0) {
RTLIL::SigSpec sig = RTLIL::SigSpec(wire); RTLIL::SigSpec sig = RTLIL::SigSpec(wire);
raw_used_signals.add(sig);
assign_map.apply(sig); assign_map.apply(sig);
used_signals.add(sig); used_signals.add(sig);
if (!wire->port_input) if (!wire->port_input)
@ -271,85 +304,102 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
} }
} }
std::vector<RTLIL::Wire*> maybe_del_wires; pool<RTLIL::Wire*> del_wires_queue;
for (auto wire : module->wires()) for (auto wire : module->wires())
{ {
if ((!purge_mode && check_public_name(wire->name)) || wire->port_id != 0 || wire->get_bool_attribute("\\keep") || wire->attributes.count("\\init")) { SigSpec s1 = SigSpec(wire), s2 = assign_map(s1);
RTLIL::SigSpec s1 = RTLIL::SigSpec(wire), s2 = s1; log_assert(GetSize(s1) == GetSize(s2));
assign_map.apply(s2);
if (!used_signals.check_any(s2) && wire->port_id == 0 && !wire->get_bool_attribute("\\keep")) { Const initval;
maybe_del_wires.push_back(wire); if (wire->attributes.count("\\init"))
} else { initval = wire->attributes.at("\\init");
log_assert(GetSize(s1) == GetSize(s2)); if (GetSize(initval) != GetSize(wire))
Const initval; initval.bits.resize(GetSize(wire), State::Sx);
if (wire->attributes.count("\\init")) if (initval.is_fully_undef())
initval = wire->attributes.at("\\init"); wire->attributes.erase("\\init");
if (GetSize(initval) != GetSize(wire))
initval.bits.resize(GetSize(wire), State::Sx); if (GetSize(wire) == 0) {
RTLIL::SigSig new_conn; // delete zero-width wires
for (int i = 0; i < GetSize(s1); i++) goto delete_this_wire;
if (s1[i] != s2[i]) { } else
if (s2[i] == State::Sx && (initval[i] == State::S0 || initval[i] == State::S1)) { if (wire->port_id != 0 || wire->get_bool_attribute("\\keep") || !initval.is_fully_undef()) {
s2[i] = initval[i]; // do not delete anything with "keep" or module ports or initialized wires
initval[i] = State::Sx; } else
} if (!purge_mode && check_public_name(wire->name)) {
new_conn.first.append_bit(s1[i]); // do not get rid of public names unless in purge mode
new_conn.second.append_bit(s2[i]); } else
} if (!raw_used_signals.check_any(s1)) {
if (new_conn.first.size() > 0) { // delete wires that aren't used by anything directly
if (initval.is_fully_undef()) goto delete_this_wire;
wire->attributes.erase("\\init"); } else
else if (!used_signals.check_any(s2)) {
wire->attributes.at("\\init") = initval; // delete wires that aren't used by anything indirectly, even though other wires may alias it
used_signals.add(new_conn.first); goto delete_this_wire;
used_signals.add(new_conn.second);
module->connect(new_conn);
}
}
} else {
if (!used_signals.check_any(RTLIL::SigSpec(wire)))
maybe_del_wires.push_back(wire);
} }
RTLIL::SigSpec sig = assign_map(RTLIL::SigSpec(wire)); if (0)
if (!used_signals_nodrivers.check_any(sig)) { {
std::string unused_bits; delete_this_wire:
for (int i = 0; i < GetSize(sig); i++) { del_wires_queue.insert(wire);
if (sig[i].wire == NULL) }
continue; else
if (!used_signals_nodrivers.check(sig[i])) { {
if (!unused_bits.empty()) RTLIL::SigSig new_conn;
unused_bits += " "; for (int i = 0; i < GetSize(s1); i++)
unused_bits += stringf("%d", i); if (s1[i] != s2[i]) {
if (s2[i] == State::Sx && (initval[i] == State::S0 || initval[i] == State::S1)) {
s2[i] = initval[i];
initval[i] = State::Sx;
}
new_conn.first.append_bit(s1[i]);
new_conn.second.append_bit(s2[i]);
} }
if (new_conn.first.size() > 0) {
if (initval.is_fully_undef())
wire->attributes.erase("\\init");
else
wire->attributes.at("\\init") = initval;
used_signals.add(new_conn.first);
used_signals.add(new_conn.second);
module->connect(new_conn);
} }
if (unused_bits.empty() || wire->port_id != 0)
if (!used_signals_nodrivers.check_all(s2)) {
std::string unused_bits;
for (int i = 0; i < GetSize(s2); i++) {
if (s2[i].wire == NULL)
continue;
if (!used_signals_nodrivers.check(s2[i])) {
if (!unused_bits.empty())
unused_bits += " ";
unused_bits += stringf("%d", i);
}
}
if (unused_bits.empty() || wire->port_id != 0)
wire->attributes.erase("\\unused_bits");
else
wire->attributes["\\unused_bits"] = RTLIL::Const(unused_bits);
} else {
wire->attributes.erase("\\unused_bits"); wire->attributes.erase("\\unused_bits");
else }
wire->attributes["\\unused_bits"] = RTLIL::Const(unused_bits);
} else {
wire->attributes.erase("\\unused_bits");
} }
} }
int del_temp_wires_count = 0;
for (auto wire : del_wires_queue) {
if (ys_debug() || (check_public_name(wire->name) && verbose))
log_debug(" removing unused non-port wire %s.\n", wire->name.c_str());
else
del_temp_wires_count++;
}
pool<RTLIL::Wire*> del_wires; module->remove(del_wires_queue);
count_rm_wires += GetSize(del_wires_queue);
int del_wires_count = 0; if (verbose && del_temp_wires_count)
for (auto wire : maybe_del_wires) log_debug(" removed %d unused temporary wires.\n", del_temp_wires_count);
if (!used_signals.check_any(RTLIL::SigSpec(wire))) {
if (check_public_name(wire->name) && verbose) {
log_debug(" removing unused non-port wire %s.\n", wire->name.c_str());
}
del_wires.insert(wire);
del_wires_count++;
}
module->remove(del_wires); return !del_wires_queue.empty();
count_rm_wires += del_wires.size();
if (verbose && del_wires_count > 0)
log_debug(" removed %d unused temporary wires.\n", del_wires_count);
} }
bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
@ -447,10 +497,10 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool
module->design->scratchpad_set_bool("opt.did_something", true); module->design->scratchpad_set_bool("opt.did_something", true);
rmunused_module_cells(module, verbose); rmunused_module_cells(module, verbose);
rmunused_module_signals(module, purge_mode, verbose); while (rmunused_module_signals(module, purge_mode, verbose)) { }
if (rminit && rmunused_module_init(module, purge_mode, verbose)) if (rminit && rmunused_module_init(module, purge_mode, verbose))
rmunused_module_signals(module, purge_mode, verbose); while (rmunused_module_signals(module, purge_mode, verbose)) { }
} }
struct OptCleanPass : public Pass { struct OptCleanPass : public Pass {
@ -496,6 +546,9 @@ struct OptCleanPass : public Pass {
ct_all.setup(design); ct_all.setup(design);
count_rm_cells = 0;
count_rm_wires = 0;
for (auto module : design->selected_whole_modules_warn()) { for (auto module : design->selected_whole_modules_warn()) {
if (module->has_processes_warn()) if (module->has_processes_warn())
continue; continue;
@ -561,7 +614,7 @@ struct CleanPass : public Pass {
for (auto module : design->selected_whole_modules()) { for (auto module : design->selected_whole_modules()) {
if (module->has_processes()) if (module->has_processes())
continue; continue;
rmunused_module(module, purge_mode, false, false); rmunused_module(module, purge_mode, ys_debug(), false);
} }
log_suppressed(); log_suppressed();

View File

@ -61,7 +61,7 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
} }
if (wire->port_input) if (wire->port_input)
driven_signals.add(sigmap(wire)); driven_signals.add(sigmap(wire));
if (wire->port_output) if (wire->port_output || wire->get_bool_attribute("\\keep"))
used_signals.add(sigmap(wire)); used_signals.add(sigmap(wire));
all_signals.add(sigmap(wire)); all_signals.add(sigmap(wire));
} }
@ -88,7 +88,7 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
} }
} }
log_debug("Setting undriven signal in %s to constant: %s = %s\n", RTLIL::id2cstr(module->name), log_signal(sig), log_signal(val)); log_debug("Setting undriven signal in %s to constant: %s = %s\n", log_id(module), log_signal(sig), log_signal(val));
module->connect(sig, val); module->connect(sig, val);
did_something = true; did_something = true;
} }
@ -104,10 +104,15 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
if (SigBit(initval[i]) == sig[i]) if (SigBit(initval[i]) == sig[i])
initval[i] = State::Sx; initval[i] = State::Sx;
} }
if (initval.is_fully_undef()) if (initval.is_fully_undef()) {
log_debug("Removing init attribute from %s/%s.\n", log_id(module), log_id(wire));
wire->attributes.erase("\\init"); wire->attributes.erase("\\init");
else did_something = true;
} else if (initval != wire->attributes.at("\\init")) {
log_debug("Updating init attribute on %s/%s: %s\n", log_id(module), log_id(wire), log_signal(initval));
wire->attributes["\\init"] = initval; wire->attributes["\\init"] = initval;
did_something = true;
}
} }
} }
} }

View File

@ -184,6 +184,10 @@ struct OptMuxtreeWorker
log_debug(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : ""); log_debug(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : "");
root_mux_rerun.erase(mux_idx); root_mux_rerun.erase(mux_idx);
eval_root_mux(mux_idx); eval_root_mux(mux_idx);
if (glob_abort_cnt == 0) {
log(" Giving up (too many iterations)\n");
return;
}
} }
while (!root_mux_rerun.empty()) { while (!root_mux_rerun.empty()) {
@ -192,9 +196,14 @@ struct OptMuxtreeWorker
log_assert(root_enable_muxes.at(mux_idx)); log_assert(root_enable_muxes.at(mux_idx));
root_mux_rerun.erase(mux_idx); root_mux_rerun.erase(mux_idx);
eval_root_mux(mux_idx); eval_root_mux(mux_idx);
if (glob_abort_cnt == 0) {
log(" Giving up (too many iterations)\n");
return;
}
} }
log(" Analyzing evaluation results.\n"); log(" Analyzing evaluation results.\n");
log_assert(glob_abort_cnt > 0);
for (auto &mi : mux2info) for (auto &mi : mux2info)
{ {
@ -397,10 +406,8 @@ struct OptMuxtreeWorker
void eval_mux(knowledge_t &knowledge, int mux_idx, bool do_replace_known, bool do_enable_ports, int abort_count) void eval_mux(knowledge_t &knowledge, int mux_idx, bool do_replace_known, bool do_enable_ports, int abort_count)
{ {
if (glob_abort_cnt == 0) { if (glob_abort_cnt == 0)
log(" Giving up (too many iterations)\n");
return; return;
}
glob_abort_cnt--; glob_abort_cnt--;
muxinfo_t &muxinfo = mux2info[mux_idx]; muxinfo_t &muxinfo = mux2info[mux_idx];
@ -454,6 +461,7 @@ struct OptMuxtreeWorker
void eval_root_mux(int mux_idx) void eval_root_mux(int mux_idx)
{ {
log_assert(glob_abort_cnt > 0);
knowledge_t knowledge; knowledge_t knowledge;
knowledge.known_inactive.resize(GetSize(bit2info)); knowledge.known_inactive.resize(GetSize(bit2info));
knowledge.known_active.resize(GetSize(bit2info)); knowledge.known_active.resize(GetSize(bit2info));

View File

@ -531,6 +531,42 @@ struct WreducePass : public Pass {
module->connect(sig, Const(0, GetSize(sig))); module->connect(sig, Const(0, GetSize(sig)));
} }
} }
if (c->type.in("$div", "$mod", "$pow"))
{
SigSpec A = c->getPort("\\A");
int original_a_width = GetSize(A);
if (c->getParam("\\A_SIGNED").as_bool()) {
while (GetSize(A) > 1 && A[GetSize(A)-1] == State::S0 && A[GetSize(A)-2] == State::S0)
A.remove(GetSize(A)-1, 1);
} else {
while (GetSize(A) > 0 && A[GetSize(A)-1] == State::S0)
A.remove(GetSize(A)-1, 1);
}
if (original_a_width != GetSize(A)) {
log("Removed top %d bits (of %d) from port A of cell %s.%s (%s).\n",
original_a_width-GetSize(A), original_a_width, log_id(module), log_id(c), log_id(c->type));
c->setPort("\\A", A);
c->setParam("\\A_WIDTH", GetSize(A));
}
SigSpec B = c->getPort("\\B");
int original_b_width = GetSize(B);
if (c->getParam("\\B_SIGNED").as_bool()) {
while (GetSize(B) > 1 && B[GetSize(B)-1] == State::S0 && B[GetSize(B)-2] == State::S0)
B.remove(GetSize(B)-1, 1);
} else {
while (GetSize(B) > 0 && B[GetSize(B)-1] == State::S0)
B.remove(GetSize(B)-1, 1);
}
if (original_b_width != GetSize(B)) {
log("Removed top %d bits (of %d) from port B of cell %s.%s (%s).\n",
original_b_width-GetSize(B), original_b_width, log_id(module), log_id(c), log_id(c->type));
c->setPort("\\B", B);
c->setParam("\\B_WIDTH", GetSize(B));
}
}
if (!opt_memx && c->type.in("$memrd", "$memwr", "$meminit")) { if (!opt_memx && c->type.in("$memrd", "$memwr", "$meminit")) {
IdString memid = c->getParam("\\MEMID").decode_string(); IdString memid = c->getParam("\\MEMID").decode_string();
RTLIL::Memory *mem = module->memories.at(memid); RTLIL::Memory *mem = module->memories.at(memid);

View File

@ -1 +1,2 @@
/ice40_dsp_pm.h /ice40_dsp_pm.h
/peepopt_pm.h

View File

@ -1,8 +1,23 @@
OBJS += passes/pmgen/ice40_dsp.o OBJS += passes/pmgen/ice40_dsp.o
OBJS += passes/pmgen/peepopt.o
# --------------------------------------
passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h
EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h
.SECONDARY: passes/pmgen/ice40_dsp_pm.h .SECONDARY: passes/pmgen/ice40_dsp_pm.h
passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg
$(P) mkdir -p passes/pmgen && python3 $^ $@ $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p ice40_dsp $(filter-out $<,$^)
# --------------------------------------
passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h
EXTRA_OBJS += passes/pmgen/peepopt_pm.h
.SECONDARY: passes/pmgen/peepopt_pm.h
PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul.pmg
PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg
passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
$(P) mkdir -p passes/pmgen && python3 $< -o $@ -p peepopt $(filter-out $<,$^)

View File

@ -29,19 +29,25 @@ up in any future matches:
pm.blacklist(some_cell); pm.blacklist(some_cell);
The `.run(callback_function)` method searches for all matches and calls the The `.run_<pattern_name>(callback_function)` method searches for all matches
callback function for each found match: for the pattern`<pattern_name>` and calls the callback function for each found
match:
pm.run([&](){ pm.run_foobar([&](){
log("found matching 'foo' cell: %s\n", log_id(pm.st.foo)); log("found matching 'foo' cell: %s\n", log_id(pm.st.foo));
log(" with 'bar' cell: %s\n", log_id(pm.st.bar)); log(" with 'bar' cell: %s\n", log_id(pm.st.bar));
}); });
The `.pmg` file declares matcher state variables that are accessible via the The `.pmg` file declares matcher state variables that are accessible via the
`.st.<state_name>` members. (The `.st` member is of type `foobar_pm::state_t`.) `.st_<pattern_name>.<state_name>` members. (The `.st_<pattern_name>` member is
of type `foobar_pm::state_<pattern_name>_t`.)
Similarly the `.pmg` file declares user data variables that become members of Similarly the `.pmg` file declares user data variables that become members of
`.ud`, a struct of type `foobar_pm::udata_t`. `.ud_<pattern_name>`, a struct of type `foobar_pm::udata_<pattern_name>_t`.
There are four versions of the `run_<pattern_name>()` method: Without callback,
callback without arguments, callback with reference to `pm`, and callback with
reference to `pm.st_<pattern_name>`.
The .pmg File Format The .pmg File Format
@ -52,6 +58,12 @@ lines consist of whitespace-separated tokens.
Lines in `.pmg` files starting with `//` are comments. Lines in `.pmg` files starting with `//` are comments.
Declaring a pattern
-------------------
A `.pmg` file contains one or more patterns. Each pattern starts with a line
with the `pattern` keyword followed by the name of the pattern.
Declaring state variables Declaring state variables
------------------------- -------------------------
@ -66,7 +78,7 @@ State variables are automatically managed by the generated backtracking algorith
and saved and restored as needed. and saved and restored as needed.
They are automatically initialized to the default constructed value of their type They are automatically initialized to the default constructed value of their type
when `.run(callback_function)` is called. when `.run_<pattern_name>(callback_function)` is called.
Declaring udata variables Declaring udata variables
------------------------- -------------------------

View File

@ -19,47 +19,50 @@
#include "kernel/yosys.h" #include "kernel/yosys.h"
#include "kernel/sigtools.h" #include "kernel/sigtools.h"
#include "passes/pmgen/ice40_dsp_pm.h"
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
#include "passes/pmgen/ice40_dsp_pm.h"
void create_ice40_dsp(ice40_dsp_pm &pm) void create_ice40_dsp(ice40_dsp_pm &pm)
{ {
auto &st = pm.st_ice40_dsp;
#if 0 #if 0
log("\n"); log("\n");
log("ffA: %s\n", log_id(pm.st.ffA, "--")); log("ffA: %s\n", log_id(st.ffA, "--"));
log("ffB: %s\n", log_id(pm.st.ffB, "--")); log("ffB: %s\n", log_id(st.ffB, "--"));
log("mul: %s\n", log_id(pm.st.mul, "--")); log("mul: %s\n", log_id(st.mul, "--"));
log("ffY: %s\n", log_id(pm.st.ffY, "--")); log("ffY: %s\n", log_id(st.ffY, "--"));
log("addAB: %s\n", log_id(pm.st.addAB, "--")); log("addAB: %s\n", log_id(st.addAB, "--"));
log("muxAB: %s\n", log_id(pm.st.muxAB, "--")); log("muxAB: %s\n", log_id(st.muxAB, "--"));
log("ffS: %s\n", log_id(pm.st.ffS, "--")); log("ffS: %s\n", log_id(st.ffS, "--"));
#endif #endif
log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(pm.st.mul)); log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(st.mul));
if (GetSize(pm.st.sigA) > 16) { if (GetSize(st.sigA) > 16) {
log(" input A (%s) is too large (%d > 16).\n", log_signal(pm.st.sigA), GetSize(pm.st.sigA)); log(" input A (%s) is too large (%d > 16).\n", log_signal(st.sigA), GetSize(st.sigA));
return; return;
} }
if (GetSize(pm.st.sigB) > 16) { if (GetSize(st.sigB) > 16) {
log(" input B (%s) is too large (%d > 16).\n", log_signal(pm.st.sigB), GetSize(pm.st.sigB)); log(" input B (%s) is too large (%d > 16).\n", log_signal(st.sigB), GetSize(st.sigB));
return; return;
} }
if (GetSize(pm.st.sigS) > 32) { if (GetSize(st.sigS) > 32) {
log(" accumulator (%s) is too large (%d > 32).\n", log_signal(pm.st.sigS), GetSize(pm.st.sigS)); log(" accumulator (%s) is too large (%d > 32).\n", log_signal(st.sigS), GetSize(st.sigS));
return; return;
} }
if (GetSize(pm.st.sigY) > 32) { if (GetSize(st.sigY) > 32) {
log(" output (%s) is too large (%d > 32).\n", log_signal(pm.st.sigY), GetSize(pm.st.sigY)); log(" output (%s) is too large (%d > 32).\n", log_signal(st.sigY), GetSize(st.sigY));
return; return;
} }
bool mul_signed = pm.st.mul->getParam("\\A_SIGNED").as_bool(); bool mul_signed = st.mul->getParam("\\A_SIGNED").as_bool();
if (mul_signed) { if (mul_signed) {
log(" inference of signed iCE40 DSP arithmetic is currently not supported.\n"); log(" inference of signed iCE40 DSP arithmetic is currently not supported.\n");
@ -69,21 +72,21 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
log(" replacing $mul with SB_MAC16 cell.\n"); log(" replacing $mul with SB_MAC16 cell.\n");
Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16"); Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16");
pm.module->swap_names(cell, pm.st.mul); pm.module->swap_names(cell, st.mul);
// SB_MAC16 Input Interface // SB_MAC16 Input Interface
SigSpec A = pm.st.sigA; SigSpec A = st.sigA;
A.extend_u0(16, mul_signed); A.extend_u0(16, mul_signed);
SigSpec B = pm.st.sigB; SigSpec B = st.sigB;
B.extend_u0(16, mul_signed); B.extend_u0(16, mul_signed);
SigSpec CD; SigSpec CD;
if (pm.st.muxA) if (st.muxA)
CD = pm.st.muxA->getPort("\\B"); CD = st.muxA->getPort("\\B");
if (pm.st.muxB) if (st.muxB)
CD = pm.st.muxB->getPort("\\A"); CD = st.muxB->getPort("\\A");
CD.extend_u0(32, mul_signed); CD.extend_u0(32, mul_signed);
cell->setPort("\\A", A); cell->setPort("\\A", A);
@ -91,8 +94,8 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setPort("\\C", CD.extract(0, 16)); cell->setPort("\\C", CD.extract(0, 16));
cell->setPort("\\D", CD.extract(16, 16)); cell->setPort("\\D", CD.extract(16, 16));
cell->setParam("\\A_REG", pm.st.ffA ? State::S1 : State::S0); cell->setParam("\\A_REG", st.ffA ? State::S1 : State::S0);
cell->setParam("\\B_REG", pm.st.ffB ? State::S1 : State::S0); cell->setParam("\\B_REG", st.ffB ? State::S1 : State::S0);
cell->setPort("\\AHOLD", State::S0); cell->setPort("\\AHOLD", State::S0);
cell->setPort("\\BHOLD", State::S0); cell->setPort("\\BHOLD", State::S0);
@ -102,25 +105,25 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setPort("\\IRSTTOP", State::S0); cell->setPort("\\IRSTTOP", State::S0);
cell->setPort("\\IRSTBOT", State::S0); cell->setPort("\\IRSTBOT", State::S0);
if (pm.st.clock_vld) if (st.clock_vld)
{ {
cell->setPort("\\CLK", pm.st.clock); cell->setPort("\\CLK", st.clock);
cell->setPort("\\CE", State::S1); cell->setPort("\\CE", State::S1);
cell->setParam("\\NEG_TRIGGER", pm.st.clock_pol ? State::S0 : State::S1); cell->setParam("\\NEG_TRIGGER", st.clock_pol ? State::S0 : State::S1);
log(" clock: %s (%s)", log_signal(pm.st.clock), pm.st.clock_pol ? "posedge" : "negedge"); log(" clock: %s (%s)", log_signal(st.clock), st.clock_pol ? "posedge" : "negedge");
if (pm.st.ffA) if (st.ffA)
log(" ffA:%s", log_id(pm.st.ffA)); log(" ffA:%s", log_id(st.ffA));
if (pm.st.ffB) if (st.ffB)
log(" ffB:%s", log_id(pm.st.ffB)); log(" ffB:%s", log_id(st.ffB));
if (pm.st.ffY) if (st.ffY)
log(" ffY:%s", log_id(pm.st.ffY)); log(" ffY:%s", log_id(st.ffY));
if (pm.st.ffS) if (st.ffS)
log(" ffS:%s", log_id(pm.st.ffS)); log(" ffS:%s", log_id(st.ffS));
log("\n"); log("\n");
} }
@ -144,16 +147,16 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
// SB_MAC16 Output Interface // SB_MAC16 Output Interface
SigSpec O = pm.st.ffS ? pm.st.sigS : pm.st.sigY; SigSpec O = st.ffS ? st.sigS : st.sigY;
if (GetSize(O) < 32) if (GetSize(O) < 32)
O.append(pm.module->addWire(NEW_ID, 32-GetSize(O))); O.append(pm.module->addWire(NEW_ID, 32-GetSize(O)));
cell->setPort("\\O", O); cell->setPort("\\O", O);
if (pm.st.addAB) { if (st.addAB) {
log(" accumulator %s (%s)\n", log_id(pm.st.addAB), log_id(pm.st.addAB->type)); log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type));
cell->setPort("\\ADDSUBTOP", pm.st.addAB->type == "$add" ? State::S0 : State::S1); cell->setPort("\\ADDSUBTOP", st.addAB->type == "$add" ? State::S0 : State::S1);
cell->setPort("\\ADDSUBBOT", pm.st.addAB->type == "$add" ? State::S0 : State::S1); cell->setPort("\\ADDSUBBOT", st.addAB->type == "$add" ? State::S0 : State::S1);
} else { } else {
cell->setPort("\\ADDSUBTOP", State::S0); cell->setPort("\\ADDSUBTOP", State::S0);
cell->setPort("\\ADDSUBBOT", State::S0); cell->setPort("\\ADDSUBBOT", State::S0);
@ -166,10 +169,10 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setPort("\\OHOLDBOT", State::S0); cell->setPort("\\OHOLDBOT", State::S0);
SigSpec acc_reset = State::S0; SigSpec acc_reset = State::S0;
if (pm.st.muxA) if (st.muxA)
acc_reset = pm.st.muxA->getPort("\\S"); acc_reset = st.muxA->getPort("\\S");
if (pm.st.muxB) if (st.muxB)
acc_reset = pm.module->Not(NEW_ID, pm.st.muxB->getPort("\\S")); acc_reset = pm.module->Not(NEW_ID, st.muxB->getPort("\\S"));
cell->setPort("\\OLOADTOP", acc_reset); cell->setPort("\\OLOADTOP", acc_reset);
cell->setPort("\\OLOADBOT", acc_reset); cell->setPort("\\OLOADBOT", acc_reset);
@ -179,17 +182,17 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setParam("\\C_REG", State::S0); cell->setParam("\\C_REG", State::S0);
cell->setParam("\\D_REG", State::S0); cell->setParam("\\D_REG", State::S0);
cell->setParam("\\TOP_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0); cell->setParam("\\TOP_8x8_MULT_REG", st.ffY ? State::S1 : State::S0);
cell->setParam("\\BOT_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0); cell->setParam("\\BOT_8x8_MULT_REG", st.ffY ? State::S1 : State::S0);
cell->setParam("\\PIPELINE_16x16_MULT_REG1", pm.st.ffY ? State::S1 : State::S0); cell->setParam("\\PIPELINE_16x16_MULT_REG1", st.ffY ? State::S1 : State::S0);
cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0); cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0);
cell->setParam("\\TOPOUTPUT_SELECT", Const(pm.st.ffS ? 1 : 3, 2)); cell->setParam("\\TOPOUTPUT_SELECT", Const(st.ffS ? 1 : 3, 2));
cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2)); cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2));
cell->setParam("\\TOPADDSUB_UPPERINPUT", State::S0); cell->setParam("\\TOPADDSUB_UPPERINPUT", State::S0);
cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2)); cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2));
cell->setParam("\\BOTOUTPUT_SELECT", Const(pm.st.ffS ? 1 : 3, 2)); cell->setParam("\\BOTOUTPUT_SELECT", Const(st.ffS ? 1 : 3, 2));
cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2)); cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2));
cell->setParam("\\BOTADDSUB_UPPERINPUT", State::S0); cell->setParam("\\BOTADDSUB_UPPERINPUT", State::S0);
cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2)); cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2));
@ -198,9 +201,9 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
cell->setParam("\\A_SIGNED", mul_signed ? State::S1 : State::S0); cell->setParam("\\A_SIGNED", mul_signed ? State::S1 : State::S0);
cell->setParam("\\B_SIGNED", mul_signed ? State::S1 : State::S0); cell->setParam("\\B_SIGNED", mul_signed ? State::S1 : State::S0);
pm.autoremove(pm.st.mul); pm.autoremove(st.mul);
pm.autoremove(pm.st.ffY); pm.autoremove(st.ffY);
pm.autoremove(pm.st.ffS); pm.autoremove(st.ffS);
} }
struct Ice40DspPass : public Pass { struct Ice40DspPass : public Pass {
@ -230,7 +233,7 @@ struct Ice40DspPass : public Pass {
extra_args(args, argidx, design); extra_args(args, argidx, design);
for (auto module : design->selected_modules()) for (auto module : design->selected_modules())
ice40_dsp_pm(module, module->selected_cells()).run(create_ice40_dsp); ice40_dsp_pm(module, module->selected_cells()).run_ice40_dsp(create_ice40_dsp);
} }
} Ice40DspPass; } Ice40DspPass;

View File

@ -1,3 +1,5 @@
pattern ice40_dsp
state <SigBit> clock state <SigBit> clock
state <bool> clock_pol clock_vld state <bool> clock_pol clock_vld
state <SigSpec> sigA sigB sigY sigS state <SigSpec> sigA sigB sigY sigS

68
passes/pmgen/peepopt.cc Normal file
View File

@ -0,0 +1,68 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
bool did_something;
#include "passes/pmgen/peepopt_pm.h"
struct PeepoptPass : public Pass {
PeepoptPass() : Pass("peepopt", "collection of peephole optimizers") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" peepopt [options] [selection]\n");
log("\n");
log("This pass applies a collection of peephole optimizers to the current design.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing PEEPOPT pass (run peephole optimizers).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
// if (args[argidx] == "-singleton") {
// singleton_mode = true;
// continue;
// }
break;
}
extra_args(args, argidx, design);
for (auto module : design->selected_modules()) {
did_something = true;
while (did_something) {
did_something = false;
peepopt_pm pm(module, module->selected_cells());
pm.run_shiftmul();
pm.run_muldiv();
}
}
}
} PeepoptPass;
PRIVATE_NAMESPACE_END

View File

@ -0,0 +1,36 @@
pattern muldiv
state <SigSpec> t x y
match mul
select mul->type == $mul
select GetSize(port(mul, \A)) + GetSize(port(mul, \B)) <= GetSize(port(mul, \Y))
endmatch
code t x y
t = port(mul, \Y);
x = port(mul, \A);
y = port(mul, \B);
branch;
std::swap(x, y);
endcode
match div
select div->type.in($div)
index <SigSpec> port(div, \A) === t
index <SigSpec> port(div, \B) === x
endmatch
code
SigSpec div_y = port(div, \Y);
SigSpec val_y = y;
if (GetSize(div_y) != GetSize(val_y))
val_y.extend_u0(GetSize(div_y), param(div, \A_SIGNED).as_bool());
did_something = true;
log("muldiv pattern in %s: mul=%s, div=%s\n", log_id(module), log_id(mul), log_id(div));
module->connect(div_y, val_y);
autoremove(div);
reject;
endcode

View File

@ -0,0 +1,87 @@
pattern shiftmul
state <SigSpec> shamt
match shift
select shift->type.in($shift, $shiftx, $shr)
endmatch
code shamt
shamt = port(shift, \B);
if (shamt.empty())
reject;
if (shamt[GetSize(shamt)-1] == State::S0) {
do {
shamt.remove(GetSize(shamt)-1);
if (shamt.empty())
reject;
} while (shamt[GetSize(shamt)-1] == State::S0);
} else
if (shift->type.in($shift, $shiftx) && param(shift, \B_SIGNED).as_bool()) {
reject;
}
if (GetSize(shamt) > 20)
reject;
endcode
match mul
select mul->type.in($mul)
select port(mul, \A).is_fully_const() || port(mul, \B).is_fully_const()
index <SigSpec> port(mul, \Y) === shamt
endmatch
code
IdString const_factor_port = port(mul, \A).is_fully_const() ? \A : \B;
IdString const_factor_signed = const_factor_port == \A ? \A_SIGNED : \B_SIGNED;
Const const_factor_cnst = port(mul, const_factor_port).as_const();
int const_factor = const_factor_cnst.as_int();
if (GetSize(const_factor_cnst) == 0)
reject;
if (const_factor_cnst.bits[GetSize(const_factor_cnst)-1] != State::S0 &&
param(mul, const_factor_signed).as_bool())
reject;
if (GetSize(const_factor_cnst) > 20)
reject;
if (GetSize(port(shift, \Y)) > const_factor)
reject;
did_something = true;
log("shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul));
int new_const_factor_log2 = ceil_log2(const_factor);
int new_const_factor = 1 << new_const_factor_log2;
SigSpec padding(State::Sx, new_const_factor-const_factor);
SigSpec old_a = port(shift, \A), new_a;
int trunc = 0;
if (GetSize(old_a) % const_factor != 0) {
trunc = const_factor - GetSize(old_a) % const_factor;
old_a.append(SigSpec(State::Sx, trunc));
}
for (int i = 0; i*const_factor < GetSize(old_a); i++) {
SigSpec slice = old_a.extract(i*const_factor, const_factor);
new_a.append(slice);
new_a.append(padding);
}
if (trunc > 0)
new_a.remove(GetSize(new_a)-trunc, trunc);
SigSpec new_b = {port(mul, const_factor_port == \A ? \B : \A), SigSpec(State::S0, new_const_factor_log2)};
if (param(shift, \B_SIGNED).as_bool())
new_b.append(State::S0);
shift->setPort(\A, new_a);
shift->setParam(\A_WIDTH, GetSize(new_a));
shift->setPort(\B, new_b);
shift->setParam(\B_WIDTH, GetSize(new_b));
blacklist(shift);
reject;
endcode

View File

@ -3,15 +3,42 @@
import re import re
import sys import sys
import pprint import pprint
import getopt
pp = pprint.PrettyPrinter(indent=4) pp = pprint.PrettyPrinter(indent=4)
pmgfile = sys.argv[1] prefix = None
assert pmgfile.endswith(".pmg") pmgfiles = list()
prefix = pmgfile[0:-4] outfile = None
prefix = prefix.split('/')[-1] debug = False
outfile = sys.argv[2] genhdr = False
opts, args = getopt.getopt(sys.argv[1:], "p:o:dg")
for o, a in opts:
if o == "-p":
prefix = a
elif o == "-o":
outfile = a
elif o == "-d":
debug = True
elif o == "-g":
genhdr = True
if outfile is None:
outfile = "/dev/stdout"
for a in args:
assert a.endswith(".pmg")
if prefix is None and len(args) == 1:
prefix = a[0:-4]
prefix = prefix.split('/')[-1]
pmgfiles.append(a)
assert prefix is not None
current_pattern = None
patterns = dict()
state_types = dict() state_types = dict()
udata_types = dict() udata_types = dict()
blocks = list() blocks = list()
@ -77,7 +104,8 @@ def rewrite_cpp(s):
return "".join(t) return "".join(t)
with open(pmgfile, "r") as f: def process_pmgfile(f):
global current_pattern
while True: while True:
line = f.readline() line = f.readline()
if line == "": break if line == "": break
@ -87,14 +115,31 @@ with open(pmgfile, "r") as f:
if len(cmd) == 0 or cmd[0].startswith("//"): continue if len(cmd) == 0 or cmd[0].startswith("//"): continue
cmd = cmd[0] cmd = cmd[0]
if cmd == "pattern":
if current_pattern is not None:
block = dict()
block["type"] = "final"
block["pattern"] = current_pattern
blocks.append(block)
line = line.split()
assert len(line) == 2
assert line[1] not in patterns
current_pattern = line[1]
patterns[current_pattern] = len(blocks)
state_types[current_pattern] = dict()
udata_types[current_pattern] = dict()
continue
assert current_pattern is not None
if cmd == "state": if cmd == "state":
m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line) m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line)
assert m assert m
type_str = m.group(1) type_str = m.group(1)
states_str = m.group(2) states_str = m.group(2)
for s in re.split(r"\s+", states_str): for s in re.split(r"\s+", states_str):
assert s not in state_types assert s not in state_types[current_pattern]
state_types[s] = type_str state_types[current_pattern][s] = type_str
continue continue
if cmd == "udata": if cmd == "udata":
@ -103,19 +148,20 @@ with open(pmgfile, "r") as f:
type_str = m.group(1) type_str = m.group(1)
udatas_str = m.group(2) udatas_str = m.group(2)
for s in re.split(r"\s+", udatas_str): for s in re.split(r"\s+", udatas_str):
assert s not in udata_types assert s not in udata_types[current_pattern]
udata_types[s] = type_str udata_types[current_pattern][s] = type_str
continue continue
if cmd == "match": if cmd == "match":
block = dict() block = dict()
block["type"] = "match" block["type"] = "match"
block["pattern"] = current_pattern
line = line.split() line = line.split()
assert len(line) == 2 assert len(line) == 2
assert line[1] not in state_types assert line[1] not in state_types[current_pattern]
block["cell"] = line[1] block["cell"] = line[1]
state_types[line[1]] = "Cell*"; state_types[current_pattern][line[1]] = "Cell*";
block["if"] = list() block["if"] = list()
block["select"] = list() block["select"] = list()
@ -158,15 +204,18 @@ with open(pmgfile, "r") as f:
assert False assert False
blocks.append(block) blocks.append(block)
continue
if cmd == "code": if cmd == "code":
block = dict() block = dict()
block["type"] = "code" block["type"] = "code"
block["pattern"] = current_pattern
block["code"] = list() block["code"] = list()
block["states"] = set() block["states"] = set()
for s in line.split()[1:]: for s in line.split()[1:]:
assert s in state_types assert s in state_types[current_pattern]
block["states"].add(s) block["states"].add(s)
while True: while True:
@ -179,17 +228,36 @@ with open(pmgfile, "r") as f:
block["code"].append(rewrite_cpp(l.rstrip())) block["code"].append(rewrite_cpp(l.rstrip()))
blocks.append(block) blocks.append(block)
continue
assert False
for fn in pmgfiles:
with open(fn, "r") as f:
process_pmgfile(f)
if current_pattern is not None:
block = dict()
block["type"] = "final"
block["pattern"] = current_pattern
blocks.append(block)
current_pattern = None
if debug:
pp.pprint(blocks)
with open(outfile, "w") as f: with open(outfile, "w") as f:
print("// Generated by pmgen.py from {}.pgm".format(prefix), file=f) for fn in pmgfiles:
print("// Generated by pmgen.py from {}".format(fn), file=f)
print("", file=f) print("", file=f)
print("#include \"kernel/yosys.h\"", file=f) if genhdr:
print("#include \"kernel/sigtools.h\"", file=f) print("#include \"kernel/yosys.h\"", file=f)
print("", file=f) print("#include \"kernel/sigtools.h\"", file=f)
print("", file=f)
print("YOSYS_NAMESPACE_BEGIN", file=f) print("YOSYS_NAMESPACE_BEGIN", file=f)
print("", file=f) print("", file=f)
print("struct {}_pm {{".format(prefix), file=f) print("struct {}_pm {{".format(prefix), file=f)
print(" Module *module;", file=f) print(" Module *module;", file=f)
@ -212,17 +280,19 @@ with open(outfile, "w") as f:
print(" int rollback;", file=f) print(" int rollback;", file=f)
print("", file=f) print("", file=f)
print(" struct state_t {", file=f) for current_pattern in sorted(patterns.keys()):
for s, t in sorted(state_types.items()): print(" struct state_{}_t {{".format(current_pattern), file=f)
print(" {} {};".format(t, s), file=f) for s, t in sorted(state_types[current_pattern].items()):
print(" } st;", file=f) print(" {} {};".format(t, s), file=f)
print("", file=f) print(" }} st_{};".format(current_pattern), file=f)
print("", file=f)
print(" struct udata_t {", file=f) print(" struct udata_{}_t {{".format(current_pattern), file=f)
for s, t in sorted(udata_types.items()): for s, t in sorted(udata_types[current_pattern].items()):
print(" {} {};".format(t, s), file=f) print(" {} {};".format(t, s), file=f)
print(" } ud;", file=f) print(" }} ud_{};".format(current_pattern), file=f)
print("", file=f) print("", file=f)
current_pattern = None
for v, n in sorted(ids.items()): for v, n in sorted(ids.items()):
if n[0] == "\\": if n[0] == "\\":
@ -258,20 +328,24 @@ with open(outfile, "w") as f:
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
print(" void check_blacklist() {", file=f) for current_pattern in sorted(patterns.keys()):
print(" if (!blacklist_dirty)", file=f) print(" void check_blacklist_{}() {{".format(current_pattern), file=f)
print(" return;", file=f) print(" if (!blacklist_dirty)", file=f)
print(" blacklist_dirty = false;", file=f) print(" return;", file=f)
for index in range(len(blocks)): print(" blacklist_dirty = false;", file=f)
block = blocks[index] for index in range(len(blocks)):
if block["type"] == "match": block = blocks[index]
print(" if (st.{} != nullptr && blacklist_cells.count(st.{})) {{".format(block["cell"], block["cell"]), file=f) if block["pattern"] != current_pattern:
print(" rollback = {};".format(index+1), file=f) continue
print(" return;", file=f) if block["type"] == "match":
print(" }", file=f) print(" if (st_{}.{} != nullptr && blacklist_cells.count(st_{}.{})) {{".format(current_pattern, block["cell"], current_pattern, block["cell"]), file=f)
print(" rollback = 0;", file=f) print(" rollback = {};".format(index+1), file=f)
print(" }", file=f) print(" return;", file=f)
print("", file=f) print(" }", file=f)
print(" rollback = 0;", file=f)
print(" }", file=f)
print("", file=f)
current_pattern = None
print(" SigSpec port(Cell *cell, IdString portname) {", file=f) print(" SigSpec port(Cell *cell, IdString portname) {", file=f)
print(" return sigmap(cell->getPort(portname));", file=f) print(" return sigmap(cell->getPort(portname));", file=f)
@ -294,11 +368,13 @@ with open(outfile, "w") as f:
print(" {}_pm(Module *module, const vector<Cell*> &cells) :".format(prefix), file=f) print(" {}_pm(Module *module, const vector<Cell*> &cells) :".format(prefix), file=f)
print(" module(module), sigmap(module) {", file=f) print(" module(module), sigmap(module) {", file=f)
for s, t in sorted(udata_types.items()): for current_pattern in sorted(patterns.keys()):
if t.endswith("*"): for s, t in sorted(udata_types[current_pattern].items()):
print(" ud.{} = nullptr;".format(s), file=f) if t.endswith("*"):
else: print(" ud_{}.{} = nullptr;".format(current_pattern,s), file=f)
print(" ud.{} = {}();".format(s, t), file=f) else:
print(" ud_{}.{} = {}();".format(current_pattern, s, t), file=f)
current_pattern = None
print(" for (auto cell : module->cells()) {", file=f) print(" for (auto cell : module->cells()) {", file=f)
print(" for (auto &conn : cell->connections())", file=f) print(" for (auto &conn : cell->connections())", file=f)
print(" add_siguser(conn.second, cell);", file=f) print(" add_siguser(conn.second, cell);", file=f)
@ -328,34 +404,52 @@ with open(outfile, "w") as f:
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
print(" void run(std::function<void()> on_accept_f) {", file=f) for current_pattern in sorted(patterns.keys()):
print(" on_accept = on_accept_f;", file=f) print(" void run_{}(std::function<void()> on_accept_f) {{".format(current_pattern), file=f)
print(" rollback = 0;", file=f) print(" on_accept = on_accept_f;", file=f)
print(" blacklist_dirty = false;", file=f) print(" rollback = 0;", file=f)
for s, t in sorted(state_types.items()): print(" blacklist_dirty = false;", file=f)
if t.endswith("*"): for s, t in sorted(state_types[current_pattern].items()):
print(" st.{} = nullptr;".format(s), file=f) if t.endswith("*"):
else: print(" st_{}.{} = nullptr;".format(current_pattern, s), file=f)
print(" st.{} = {}();".format(s, t), file=f) else:
print(" block_0();", file=f) print(" st_{}.{} = {}();".format(current_pattern, s, t), file=f)
print(" }", file=f) print(" block_{}();".format(patterns[current_pattern]), file=f)
print("", file=f) print(" }", file=f)
print("", file=f)
print(" void run(std::function<void({}_pm&)> on_accept_f) {{".format(prefix), file=f) print(" void run_{}(std::function<void({}_pm&)> on_accept_f) {{".format(current_pattern, prefix), file=f)
print(" run([&](){on_accept_f(*this);});", file=f) print(" run_{}([&](){{on_accept_f(*this);}});".format(current_pattern), file=f)
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
print(" void run_{}(std::function<void(state_{}_t&)> on_accept_f) {{".format(current_pattern, current_pattern), file=f)
print(" run_{}([&](){{on_accept_f(st_{});}});".format(current_pattern, current_pattern), file=f)
print(" }", file=f)
print("", file=f)
print(" void run_{}() {{".format(current_pattern), file=f)
print(" run_{}([](){{}});".format(current_pattern, current_pattern), file=f)
print(" }", file=f)
print("", file=f)
current_pattern = None
for index in range(len(blocks)): for index in range(len(blocks)):
block = blocks[index] block = blocks[index]
print(" void block_{}() {{".format(index), file=f) print(" void block_{}() {{".format(index), file=f)
current_pattern = block["pattern"]
if block["type"] == "final":
print(" on_accept();", file=f)
print(" check_blacklist_{}();".format(current_pattern), file=f)
print(" }", file=f)
if index+1 != len(blocks):
print("", file=f)
continue
const_st = set() const_st = set()
nonconst_st = set() nonconst_st = set()
restore_st = set() restore_st = set()
for i in range(index): for i in range(patterns[current_pattern], index):
if blocks[i]["type"] == "code": if blocks[i]["type"] == "code":
for s in blocks[i]["states"]: for s in blocks[i]["states"]:
const_st.add(s) const_st.add(s)
@ -378,27 +472,27 @@ with open(outfile, "w") as f:
assert False assert False
for s in sorted(const_st): for s in sorted(const_st):
t = state_types[s] t = state_types[current_pattern][s]
if t.endswith("*"): if t.endswith("*"):
print(" {} const &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f) print(" {} const &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f)
else: else:
print(" const {} &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f) print(" const {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f)
for s in sorted(nonconst_st): for s in sorted(nonconst_st):
t = state_types[s] t = state_types[current_pattern][s]
print(" {} &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f) print(" {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f)
if len(restore_st): if len(restore_st):
print("", file=f) print("", file=f)
for s in sorted(restore_st): for s in sorted(restore_st):
t = state_types[s] t = state_types[current_pattern][s]
print(" {} backup_{} = {};".format(t, s, s), file=f) print(" {} backup_{} = {};".format(t, s, s), file=f)
if block["type"] == "code": if block["type"] == "code":
print("", file=f) print("", file=f)
print(" do {", file=f) print(" do {", file=f)
print("#define reject do { check_blacklist(); goto rollback_label; } while(0)", file=f) print("#define reject do {{ check_blacklist_{}(); goto rollback_label; }} while(0)".format(current_pattern), file=f)
print("#define accept do { on_accept(); check_blacklist(); if (rollback) goto rollback_label; } while(0)", file=f) print("#define accept do {{ on_accept(); check_blacklist_{}(); if (rollback) goto rollback_label; }} while(0)".format(current_pattern), file=f)
print("#define branch do {{ block_{}(); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f) print("#define branch do {{ block_{}(); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f)
for line in block["code"]: for line in block["code"]:
@ -417,11 +511,11 @@ with open(outfile, "w") as f:
if len(restore_st) or len(nonconst_st): if len(restore_st) or len(nonconst_st):
print("", file=f) print("", file=f)
for s in sorted(restore_st): for s in sorted(restore_st):
t = state_types[s] t = state_types[current_pattern][s]
print(" {} = backup_{};".format(s, s), file=f) print(" {} = backup_{};".format(s, s), file=f)
for s in sorted(nonconst_st): for s in sorted(nonconst_st):
if s not in restore_st: if s not in restore_st:
t = state_types[s] t = state_types[current_pattern][s]
if t.endswith("*"): if t.endswith("*"):
print(" {} = nullptr;".format(s), file=f) print(" {} = nullptr;".format(s), file=f)
else: else:
@ -470,17 +564,12 @@ with open(outfile, "w") as f:
else: else:
assert False assert False
current_pattern = None
print(" }", file=f) print(" }", file=f)
print("", file=f) print("", file=f)
print(" void block_{}() {{".format(len(blocks)), file=f)
print(" on_accept();", file=f)
print(" check_blacklist();", file=f)
print(" }", file=f)
print("};", file=f) print("};", file=f)
print("", file=f) if genhdr:
print("YOSYS_NAMESPACE_END", file=f) print("", file=f)
print("YOSYS_NAMESPACE_END", file=f)
# pp.pprint(blocks)

View File

@ -508,7 +508,7 @@ struct ExposePass : public Pass {
} }
for (auto &conn : module->connections_) for (auto &conn : module->connections_)
conn.first = out_to_in_map(sigmap(conn.first)); conn.first = out_to_in_map(conn.first);
} }
if (flag_cut) if (flag_cut)

View File

@ -26,6 +26,8 @@ PRIVATE_NAMESPACE_BEGIN
struct opts_t struct opts_t
{ {
bool initeq = false;
bool anyeq = false;
bool fwd = false; bool fwd = false;
bool bwd = false; bool bwd = false;
bool nop = false; bool nop = false;
@ -56,7 +58,7 @@ struct FmcombineWorker
return newsig; return newsig;
} }
void import_prim_cell(Cell *cell, const string &suffix) Cell *import_prim_cell(Cell *cell, const string &suffix)
{ {
Cell *c = module->addCell(cell->name.str() + suffix, cell->type); Cell *c = module->addCell(cell->name.str() + suffix, cell->type);
c->parameters = cell->parameters; c->parameters = cell->parameters;
@ -64,6 +66,8 @@ struct FmcombineWorker
for (auto &conn : cell->connections()) for (auto &conn : cell->connections())
c->setPort(conn.first, import_sig(conn.second, suffix)); c->setPort(conn.first, import_sig(conn.second, suffix));
return c;
} }
void import_hier_cell(Cell *cell) void import_hier_cell(Cell *cell)
@ -102,8 +106,24 @@ struct FmcombineWorker
for (auto cell : original->cells()) { for (auto cell : original->cells()) {
if (design->module(cell->type) == nullptr) { if (design->module(cell->type) == nullptr) {
import_prim_cell(cell, "_gold"); if (opts.anyeq && cell->type.in("$anyseq", "$anyconst")) {
import_prim_cell(cell, "_gate"); Cell *gold = import_prim_cell(cell, "_gold");
for (auto &conn : cell->connections())
module->connect(import_sig(conn.second, "_gate"), gold->getPort(conn.first));
} else {
Cell *gold = import_prim_cell(cell, "_gold");
Cell *gate = import_prim_cell(cell, "_gate");
if (opts.initeq) {
if (cell->type.in("$ff", "$dff", "$dffe",
"$dffsr", "$adff", "$dlatch", "$dlatchsr")) {
SigSpec gold_q = gold->getPort("\\Q");
SigSpec gate_q = gate->getPort("\\Q");
SigSpec en = module->Initstate(NEW_ID);
SigSpec eq = module->Eq(NEW_ID, gold_q, gate_q);
module->addAssume(NEW_ID, eq, en);
}
}
}
} else { } else {
import_hier_cell(cell); import_hier_cell(cell);
} }
@ -229,6 +249,13 @@ struct FmcombinePass : public Pass {
log("This is useful for formal test benches that check what differences in behavior\n"); log("This is useful for formal test benches that check what differences in behavior\n");
log("a slight difference in input causes in a module.\n"); log("a slight difference in input causes in a module.\n");
log("\n"); log("\n");
log(" -initeq\n");
log(" Insert assumptions that initially all FFs in both circuits have the\n");
log(" same initial values.\n");
log("\n");
log(" -anyeq\n");
log(" Do not duplicate $anyseq/$anyconst cells.\n");
log("\n");
log(" -fwd\n"); log(" -fwd\n");
log(" Insert forward hint assumptions into the combined module.\n"); log(" Insert forward hint assumptions into the combined module.\n");
log("\n"); log("\n");
@ -261,6 +288,14 @@ struct FmcombinePass : public Pass {
// filename = args[++argidx]; // filename = args[++argidx];
// continue; // continue;
// } // }
if (args[argidx] == "-initeq") {
opts.initeq = true;
continue;
}
if (args[argidx] == "-anyeq") {
opts.anyeq = true;
continue;
}
if (args[argidx] == "-fwd") { if (args[argidx] == "-fwd") {
opts.fwd = true; opts.fwd = true;
continue; continue;

View File

@ -330,20 +330,33 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr) std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr)
{ {
std::string abc_sname = abc_name.substr(1); std::string abc_sname = abc_name.substr(1);
if (abc_sname.substr(0, 5) == "ys__n") { bool isnew = false;
bool inv = abc_sname.back() == 'v'; if (abc_sname.substr(0, 4) == "new_")
if (inv) abc_sname.pop_back(); {
abc_sname.erase(0, 4);
isnew = true;
}
if (abc_sname.substr(0, 5) == "ys__n")
{
abc_sname.erase(0, 5); abc_sname.erase(0, 5);
if (abc_sname.find_last_not_of("012345689") == std::string::npos) { if (std::isdigit(abc_sname.at(0)))
{
int sid = std::stoi(abc_sname); int sid = std::stoi(abc_sname);
for (auto sig : signal_list) { size_t postfix_start = abc_sname.find_first_not_of("0123456789");
if (sig.id == sid && sig.bit.wire != nullptr) { std::string postfix = postfix_start != std::string::npos ? abc_sname.substr(postfix_start) : "";
if (sid < GetSize(signal_list))
{
auto sig = signal_list.at(sid);
if (sig.bit.wire != nullptr)
{
std::stringstream sstr; std::stringstream sstr;
sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1); sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1);
if (sig.bit.wire->width != 1) if (sig.bit.wire->width != 1)
sstr << "[" << sig.bit.offset << "]"; sstr << "[" << sig.bit.offset << "]";
if (inv) if (isnew)
sstr << "_inv"; sstr << "_new";
sstr << postfix;
if (orig_wire != nullptr) if (orig_wire != nullptr)
*orig_wire = sig.bit.wire; *orig_wire = sig.bit.wire;
return sstr.str(); return sstr.str();

View File

@ -102,7 +102,8 @@ struct DffinitPass : public Pass {
if (wire->attributes.count("\\init")) { if (wire->attributes.count("\\init")) {
Const value = wire->attributes.at("\\init"); Const value = wire->attributes.at("\\init");
for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++)
init_bits[sigmap(SigBit(wire, i))] = value[i]; if (value[i] != State::Sx)
init_bits[sigmap(SigBit(wire, i))] = value[i];
} }
if (wire->port_output) if (wire->port_output)
for (auto bit : sigmap(wire)) for (auto bit : sigmap(wire))

View File

@ -397,7 +397,6 @@ struct FlowGraph
pool<RTLIL::SigBit> x, xi; pool<RTLIL::SigBit> x, xi;
NodePrime source_prime = {source, true}; NodePrime source_prime = {source, true};
NodePrime sink_prime = {sink, false};
pool<NodePrime> visited; pool<NodePrime> visited;
vector<NodePrime> worklist = {source_prime}; vector<NodePrime> worklist = {source_prime};
while (!worklist.empty()) while (!worklist.empty())
@ -1382,7 +1381,8 @@ struct FlowmapWorker
vector<RTLIL::SigBit> input_nodes(lut_edges_bw[node].begin(), lut_edges_bw[node].end()); vector<RTLIL::SigBit> input_nodes(lut_edges_bw[node].begin(), lut_edges_bw[node].end());
RTLIL::Const lut_table(State::Sx, max(1 << input_nodes.size(), 1 << minlut)); RTLIL::Const lut_table(State::Sx, max(1 << input_nodes.size(), 1 << minlut));
for (unsigned i = 0; i < (1 << input_nodes.size()); i++) unsigned const mask = 1 << input_nodes.size();
for (unsigned i = 0; i < mask; i++)
{ {
ce.push(); ce.push();
for (size_t n = 0; n < input_nodes.size(); n++) for (size_t n = 0; n < input_nodes.size(); n++)

View File

@ -94,7 +94,7 @@ int LibertyParser::lexer(std::string &str)
// search for identifiers, numbers, plus or minus. // search for identifiers, numbers, plus or minus.
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') { if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') {
str = c; str = static_cast<char>(c);
while (1) { while (1) {
c = f.get(); c = f.get();
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.')

View File

@ -46,7 +46,7 @@ struct ZinitPass : public Pass {
size_t argidx; size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) for (argidx = 1; argidx < args.size(); argidx++)
{ {
if (args[argidx] == "-singleton") { if (args[argidx] == "-all") {
all_mode = true; all_mode = true;
continue; continue;
} }

View File

@ -1271,6 +1271,181 @@ endmodule
// -------------------------------------------------------- // --------------------------------------------------------
module \$specify2 (EN, SRC, DST);
parameter FULL = 0;
parameter SRC_WIDTH = 1;
parameter DST_WIDTH = 1;
parameter SRC_DST_PEN = 0;
parameter SRC_DST_POL = 0;
parameter T_RISE_MIN = 0;
parameter T_RISE_TYP = 0;
parameter T_RISE_MAX = 0;
parameter T_FALL_MIN = 0;
parameter T_FALL_TYP = 0;
parameter T_FALL_MAX = 0;
input EN;
input [SRC_WIDTH-1:0] SRC;
input [DST_WIDTH-1:0] DST;
localparam SD = SRC_DST_PEN ? (SRC_DST_POL ? 1 : 2) : 0;
`ifdef SIMLIB_SPECIFY
specify
if (EN && SD==0 && !FULL) (SRC => DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && SD==0 && FULL) (SRC *> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && SD==1 && !FULL) (SRC +=> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && SD==1 && FULL) (SRC +*> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && SD==2 && !FULL) (SRC -=> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && SD==2 && FULL) (SRC -*> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
endspecify
`endif
endmodule
// --------------------------------------------------------
module \$specify3 (EN, SRC, DST, DAT);
parameter FULL = 0;
parameter SRC_WIDTH = 1;
parameter DST_WIDTH = 1;
parameter EDGE_EN = 0;
parameter EDGE_POL = 0;
parameter SRC_DST_PEN = 0;
parameter SRC_DST_POL = 0;
parameter DAT_DST_PEN = 0;
parameter DAT_DST_POL = 0;
parameter T_RISE_MIN = 0;
parameter T_RISE_TYP = 0;
parameter T_RISE_MAX = 0;
parameter T_FALL_MIN = 0;
parameter T_FALL_TYP = 0;
parameter T_FALL_MAX = 0;
input EN;
input [SRC_WIDTH-1:0] SRC;
input [DST_WIDTH-1:0] DST, DAT;
localparam ED = EDGE_EN ? (EDGE_POL ? 1 : 2) : 0;
localparam SD = SRC_DST_PEN ? (SRC_DST_POL ? 1 : 2) : 0;
localparam DD = DAT_DST_PEN ? (DAT_DST_POL ? 1 : 2) : 0;
`ifdef SIMLIB_SPECIFY
specify
// DD=0
if (EN && DD==0 && SD==0 && ED==0 && !FULL) ( SRC => (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==0 && ED==0 && FULL) ( SRC *> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==0 && ED==1 && !FULL) (posedge SRC => (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==0 && ED==1 && FULL) (posedge SRC *> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==0 && ED==2 && !FULL) (negedge SRC => (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==0 && ED==2 && FULL) (negedge SRC *> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==1 && ED==0 && !FULL) ( SRC +=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==1 && ED==0 && FULL) ( SRC +*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==1 && ED==1 && FULL) (posedge SRC +*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==1 && ED==2 && FULL) (negedge SRC +*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==2 && ED==0 && !FULL) ( SRC -=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==2 && ED==0 && FULL) ( SRC -*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==2 && ED==1 && FULL) (posedge SRC -*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==0 && SD==2 && ED==2 && FULL) (negedge SRC -*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
// DD=1
if (EN && DD==1 && SD==0 && ED==0 && !FULL) ( SRC => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==0 && ED==0 && FULL) ( SRC *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==0 && ED==1 && !FULL) (posedge SRC => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==0 && ED==1 && FULL) (posedge SRC *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==0 && ED==2 && !FULL) (negedge SRC => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==0 && ED==2 && FULL) (negedge SRC *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==1 && ED==0 && !FULL) ( SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==1 && ED==0 && FULL) ( SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==1 && ED==1 && FULL) (posedge SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==1 && ED==2 && FULL) (negedge SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==2 && ED==0 && !FULL) ( SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==2 && ED==0 && FULL) ( SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==2 && ED==1 && FULL) (posedge SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==1 && SD==2 && ED==2 && FULL) (negedge SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
// DD=2
if (EN && DD==2 && SD==0 && ED==0 && !FULL) ( SRC => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==0 && ED==0 && FULL) ( SRC *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==0 && ED==1 && !FULL) (posedge SRC => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==0 && ED==1 && FULL) (posedge SRC *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==0 && ED==2 && !FULL) (negedge SRC => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==0 && ED==2 && FULL) (negedge SRC *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==1 && ED==0 && !FULL) ( SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==1 && ED==0 && FULL) ( SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==1 && ED==1 && FULL) (posedge SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==1 && ED==2 && FULL) (negedge SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==2 && ED==0 && !FULL) ( SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==2 && ED==0 && FULL) ( SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==2 && ED==1 && FULL) (posedge SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
if (EN && DD==2 && SD==2 && ED==2 && FULL) (negedge SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX);
endspecify
`endif
endmodule
// --------------------------------------------------------
module \$specrule (EN_SRC, EN_DST, SRC, DST);
parameter TYPE = "";
parameter T_LIMIT = 0;
parameter T_LIMIT2 = 0;
parameter SRC_WIDTH = 1;
parameter DST_WIDTH = 1;
parameter SRC_PEN = 0;
parameter SRC_POL = 0;
parameter DST_PEN = 0;
parameter DST_POL = 0;
input EN_SRC, EN_DST;
input [SRC_WIDTH-1:0] SRC;
input [DST_WIDTH-1:0] DST;
`ifdef SIMLIB_SPECIFY
specify
// TBD
endspecify
`endif
endmodule
// --------------------------------------------------------
module \$assert (A, EN); module \$assert (A, EN);
input A, EN; input A, EN;
@ -1863,4 +2038,5 @@ end
endmodule endmodule
`endif `endif
// -------------------------------------------------------- // --------------------------------------------------------

View File

@ -201,6 +201,8 @@ struct SynthPass : public ScriptPass
run("check"); run("check");
run("opt"); run("opt");
run("wreduce"); run("wreduce");
run("peepopt");
run("opt_clean");
if (help_mode) if (help_mode)
run("techmap -map +/cmp2lut.v", " (if -lut)"); run("techmap -map +/cmp2lut.v", " (if -lut)");
else else

View File

@ -930,10 +930,21 @@ endmodule
(* blackbox *) (* blackbox *)
module SB_HFOSC( module SB_HFOSC(
input TRIM0,
input TRIM1,
input TRIM2,
input TRIM3,
input TRIM4,
input TRIM5,
input TRIM6,
input TRIM7,
input TRIM8,
input TRIM9,
input CLKHFPU, input CLKHFPU,
input CLKHFEN, input CLKHFEN,
output CLKHF output CLKHF
); );
parameter TRIM_EN = "0b0";
parameter CLKHF_DIV = "0b00"; parameter CLKHF_DIV = "0b00";
endmodule endmodule

View File

@ -241,6 +241,8 @@ struct SynthIce40Pass : public ScriptPass
run("check"); run("check");
run("opt"); run("opt");
run("wreduce"); run("wreduce");
run("peepopt");
run("opt_clean");
run("share"); run("share");
run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4"); run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4");
run("opt_expr"); run("opt_expr");

View File

@ -17,254 +17,243 @@
* *
*/ */
#include "kernel/register.h"
#include "kernel/celltypes.h" #include "kernel/celltypes.h"
#include "kernel/rtlil.h"
#include "kernel/log.h" #include "kernel/log.h"
#include "kernel/register.h"
#include "kernel/rtlil.h"
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN PRIVATE_NAMESPACE_BEGIN
struct SynthIntelPass : public ScriptPass { struct SynthIntelPass : public ScriptPass {
SynthIntelPass() : ScriptPass("synth_intel", "synthesis for Intel (Altera) FPGAs.") { } SynthIntelPass() : ScriptPass("synth_intel", "synthesis for Intel (Altera) FPGAs.") {}
void help() YS_OVERRIDE void help() YS_OVERRIDE
{ {
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n"); log("\n");
log(" synth_intel [options]\n"); log(" synth_intel [options]\n");
log("\n"); log("\n");
log("This command runs synthesis for Intel FPGAs.\n"); log("This command runs synthesis for Intel FPGAs.\n");
log("\n"); log("\n");
log(" -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>\n"); log(" -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>\n");
log(" generate the synthesis netlist for the specified family.\n"); log(" generate the synthesis netlist for the specified family.\n");
log(" MAX10 is the default target if not family argument specified.\n"); log(" MAX10 is the default target if not family argument specified.\n");
log(" For Cyclone GX devices, use cycloneiv argument; For Cyclone E, use cycloneive.\n"); log(" For Cyclone GX devices, use cycloneiv argument; For Cyclone E, use cycloneive.\n");
log(" Cyclone V and Arria 10 GX devices are experimental, use it with a10gx argument.\n"); log(" Cyclone V and Arria 10 GX devices are experimental, use it with a10gx argument.\n");
log("\n"); log("\n");
log(" -top <module>\n"); log(" -top <module>\n");
log(" use the specified module as top module (default='top')\n"); log(" use the specified module as top module (default='top')\n");
log("\n"); log("\n");
log(" -vqm <file>\n"); log(" -vqm <file>\n");
log(" write the design to the specified Verilog Quartus Mapping File. Writing of an\n"); log(" write the design to the specified Verilog Quartus Mapping File. Writing of an\n");
log(" output file is omitted if this parameter is not specified.\n"); log(" output file is omitted if this parameter is not specified.\n");
log("\n"); log("\n");
log(" -vpr <file>\n"); log(" -vpr <file>\n");
log(" write BLIF files for VPR flow experiments. The synthesized BLIF output file is not\n"); log(" write BLIF files for VPR flow experiments. The synthesized BLIF output file is not\n");
log(" compatible with the Quartus flow. Writing of an\n"); log(" compatible with the Quartus flow. Writing of an\n");
log(" output file is omitted if this parameter is not specified.\n"); log(" output file is omitted if this parameter is not specified.\n");
log("\n"); log("\n");
log(" -run <from_label>:<to_label>\n"); log(" -run <from_label>:<to_label>\n");
log(" only run the commands between the labels (see below). an empty\n"); log(" only run the commands between the labels (see below). an empty\n");
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(" -noiopads\n");
log(" do not use altsyncram cells in output netlist\n"); log(" do not use altsyncram cells in output netlist\n");
log("\n"); log("\n");
log(" -nobram\n"); log(" -nobram\n");
log(" do not use altsyncram cells in output netlist\n"); log(" do not use altsyncram cells in output netlist\n");
log("\n"); log("\n");
log(" -noflatten\n"); log(" -noflatten\n");
log(" do not flatten design before synthesis\n"); log(" do not flatten design before synthesis\n");
log("\n"); log("\n");
log(" -retime\n"); log(" -retime\n");
log(" run 'abc' with -dff option\n"); log(" run 'abc' with -dff option\n");
log("\n"); log("\n");
log("The following commands are executed by this synthesis command:\n"); log("The following commands are executed by this synthesis command:\n");
help_script(); help_script();
log("\n"); log("\n");
} }
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, noiopads;
void clear_flags() YS_OVERRIDE void clear_flags() YS_OVERRIDE
{ {
top_opt = "-auto-top"; top_opt = "-auto-top";
family_opt = "max10"; family_opt = "max10";
vout_file = ""; vout_file = "";
blif_file = ""; blif_file = "";
retime = false; retime = false;
flatten = true; flatten = true;
nobram = false; nobram = false;
noiopads = false; noiopads = 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
{ {
string run_from, run_to; string run_from, run_to;
clear_flags(); clear_flags();
size_t argidx; size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) for (argidx = 1; argidx < args.size(); argidx++) {
{ if (args[argidx] == "-family" && argidx + 1 < args.size()) {
if (args[argidx] == "-family" && argidx+1 < args.size()) { family_opt = args[++argidx];
family_opt = args[++argidx]; continue;
continue; }
} if (args[argidx] == "-top" && argidx + 1 < args.size()) {
if (args[argidx] == "-top" && argidx+1 < args.size()) { top_opt = "-top " + args[++argidx];
top_opt = "-top " + args[++argidx]; continue;
continue; }
} if (args[argidx] == "-vqm" && argidx + 1 < args.size()) {
if (args[argidx] == "-vqm" && argidx+1 < args.size()) { vout_file = args[++argidx];
vout_file = args[++argidx]; continue;
continue; }
} if (args[argidx] == "-vpr" && argidx + 1 < args.size()) {
if (args[argidx] == "-vpr" && argidx+1 < args.size()) { blif_file = args[++argidx];
blif_file = args[++argidx]; continue;
continue; }
} if (args[argidx] == "-run" && argidx + 1 < args.size()) {
if (args[argidx] == "-run" && argidx+1 < args.size()) { size_t pos = args[argidx + 1].find(':');
size_t pos = args[argidx+1].find(':'); if (pos == std::string::npos)
if (pos == std::string::npos) break;
break; run_from = args[++argidx].substr(0, pos);
run_from = args[++argidx].substr(0, pos); run_to = args[argidx].substr(pos + 1);
run_to = args[argidx].substr(pos+1); continue;
continue; }
} if (args[argidx] == "-noiopads") {
if (args[argidx] == "-noiopads") { noiopads = true;
noiopads = true; continue;
continue; }
} if (args[argidx] == "-nobram") {
if (args[argidx] == "-nobram") { nobram = true;
nobram = true; continue;
continue; }
} if (args[argidx] == "-noflatten") {
if (args[argidx] == "-noflatten") { flatten = false;
flatten = false; continue;
continue; }
} if (args[argidx] == "-retime") {
if (args[argidx] == "-retime") { retime = true;
retime = true; continue;
continue; }
} break;
break; }
} extra_args(args, argidx, design);
extra_args(args, argidx, design);
if (!design->full_selection()) if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n"); log_cmd_error("This command only operates on fully selected designs!\n");
if (family_opt != "max10" && family_opt !="a10gx" && family_opt != "cyclonev" && family_opt !="cycloneiv" && family_opt !="cycloneive" && family_opt != "cyclone10") if (family_opt != "max10" && family_opt != "a10gx" && family_opt != "cyclonev" && family_opt != "cycloneiv" &&
log_cmd_error("Invalid or not family specified: '%s'\n", family_opt.c_str()); family_opt != "cycloneive" && family_opt != "cyclone10")
log_cmd_error("Invalid or not family specified: '%s'\n", family_opt.c_str());
log_header(design, "Executing SYNTH_INTEL pass.\n"); log_header(design, "Executing SYNTH_INTEL pass.\n");
log_push(); log_push();
run_script(design, run_from, run_to); run_script(design, run_from, run_to);
log_pop(); log_pop();
} }
void script() YS_OVERRIDE void script() YS_OVERRIDE
{ {
if (check_label("begin")) if (check_label("begin")) {
{ if (check_label("family") && family_opt == "max10")
if(check_label("family") && family_opt=="max10") run("read_verilog -sv -lib +/intel/max10/cells_sim.v");
run("read_verilog -sv -lib +/intel/max10/cells_sim.v"); else if (check_label("family") && family_opt == "a10gx")
else if(check_label("family") && family_opt=="a10gx") run("read_verilog -sv -lib +/intel/a10gx/cells_sim.v");
run("read_verilog -sv -lib +/intel/a10gx/cells_sim.v"); else if (check_label("family") && family_opt == "cyclonev")
else if(check_label("family") && family_opt=="cyclonev") run("read_verilog -sv -lib +/intel/cyclonev/cells_sim.v");
run("read_verilog -sv -lib +/intel/cyclonev/cells_sim.v"); else if (check_label("family") && family_opt == "cyclone10")
else if(check_label("family") && family_opt=="cyclone10") run("read_verilog -sv -lib +/intel/cyclone10/cells_sim.v");
run("read_verilog -sv -lib +/intel/cyclone10/cells_sim.v"); else if (check_label("family") && family_opt == "cycloneiv")
else if(check_label("family") && family_opt=="cycloneiv") run("read_verilog -sv -lib +/intel/cycloneiv/cells_sim.v");
run("read_verilog -sv -lib +/intel/cycloneiv/cells_sim.v"); else
else run("read_verilog -sv -lib +/intel/cycloneive/cells_sim.v");
run("read_verilog -sv -lib +/intel/cycloneive/cells_sim.v"); // Misc and common cells
// Misc and common cells run("read_verilog -sv -lib +/intel/common/m9k_bb.v");
run("read_verilog -sv -lib +/intel/common/m9k_bb.v"); run("read_verilog -sv -lib +/intel/common/altpll_bb.v");
run("read_verilog -sv -lib +/intel/common/altpll_bb.v"); run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); }
}
if (flatten && check_label("flatten", "(unless -noflatten)")) if (flatten && check_label("flatten", "(unless -noflatten)")) {
{ run("proc");
run("proc"); run("flatten");
run("flatten"); run("tribuf -logic");
run("tribuf -logic"); run("deminout");
run("deminout"); }
}
if (check_label("coarse")) if (check_label("coarse")) {
{ run("synth -run coarse");
run("synth -run coarse"); }
}
if (!nobram && check_label("bram", "(skip if -nobram)")) if (!nobram && check_label("bram", "(skip if -nobram)")) {
{ run("memory_bram -rules +/intel/common/brams.txt");
run("memory_bram -rules +/intel/common/brams.txt"); run("techmap -map +/intel/common/brams_map.v");
run("techmap -map +/intel/common/brams_map.v"); }
}
if (check_label("fine")) if (check_label("fine")) {
{ run("opt -fast -mux_undef -undriven -fine -full");
run("opt -fast -mux_undef -undriven -fine -full"); run("memory_map");
run("memory_map"); run("opt -undriven -fine");
run("opt -undriven -fine"); run("dffsr2dff");
run("dffsr2dff"); run("dff2dffe -direct-match $_DFF_*");
run("dff2dffe -direct-match $_DFF_*"); run("opt -fine");
run("opt -fine"); run("techmap -map +/techmap.v");
run("techmap -map +/techmap.v"); run("opt -full");
run("opt -full"); run("clean -purge");
run("clean -purge"); run("setundef -undriven -zero");
run("setundef -undriven -zero"); if (retime || help_mode)
if (retime || help_mode) run("abc -markgroups -dff", "(only if -retime)");
run("abc -markgroups -dff", "(only if -retime)"); }
}
if (check_label("map_luts")) if (check_label("map_luts")) {
{ if (family_opt == "a10gx" || family_opt == "cyclonev")
if(family_opt=="a10gx" || family_opt=="cyclonev") run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : ""));
run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : "")); else
else run("abc -lut 4" + string(retime ? " -dff" : ""));
run("abc -lut 4" + string(retime ? " -dff" : "")); run("clean");
run("clean"); }
}
if (check_label("map_cells")) if (check_label("map_cells")) {
{ if (!noiopads)
if (!noiopads) run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)");
run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)"); if (family_opt == "max10")
if(family_opt=="max10") run("techmap -map +/intel/max10/cells_map.v");
run("techmap -map +/intel/max10/cells_map.v"); else if (family_opt == "a10gx")
else if(family_opt=="a10gx") run("techmap -map +/intel/a10gx/cells_map.v");
run("techmap -map +/intel/a10gx/cells_map.v"); else if (family_opt == "cyclonev")
else if(family_opt=="cyclonev") run("techmap -map +/intel/cyclonev/cells_map.v");
run("techmap -map +/intel/cyclonev/cells_map.v"); else if (family_opt == "cyclone10")
else if(family_opt=="cyclone10") run("techmap -map +/intel/cyclone10/cells_map.v");
run("techmap -map +/intel/cyclone10/cells_map.v"); else if (family_opt == "cycloneiv")
else if(family_opt=="cycloneiv") run("techmap -map +/intel/cycloneiv/cells_map.v");
run("techmap -map +/intel/cycloneiv/cells_map.v"); else
else run("techmap -map +/intel/cycloneive/cells_map.v");
run("techmap -map +/intel/cycloneive/cells_map.v"); run("dffinit -highlow -ff dffeas q power_up");
run("dffinit -highlow -ff dffeas q power_up"); run("clean -purge");
run("clean -purge"); }
}
if (check_label("check")) if (check_label("check")) {
{ run("hierarchy -check");
run("hierarchy -check"); run("stat");
run("stat"); run("check -noinit");
run("check -noinit"); }
}
if (check_label("vqm")) if (check_label("vqm")) {
{ if (!vout_file.empty() || help_mode)
if (!vout_file.empty() || help_mode) run(stringf("write_verilog -attr2comment -defparam -nohex -decimal -renameprefix syn_ %s",
run(stringf("write_verilog -attr2comment -defparam -nohex -decimal -renameprefix syn_ %s", help_mode ? "<file-name>" : vout_file.c_str()));
help_mode ? "<file-name>" : vout_file.c_str())); }
}
if (check_label("vpr")) if (check_label("vpr")) {
{ if (!blif_file.empty() || help_mode) {
if (!blif_file.empty() || help_mode) run(stringf("opt_clean -purge"));
{ run(stringf("write_blif %s", help_mode ? "<file-name>" : blif_file.c_str()));
run(stringf("opt_clean -purge")); }
run(stringf("write_blif %s", help_mode ? "<file-name>" : blif_file.c_str())); }
} }
}
}
} SynthIntelPass; } SynthIntelPass;
PRIVATE_NAMESPACE_END PRIVATE_NAMESPACE_END

View File

@ -18,12 +18,14 @@
*/ */
// Convert negative-polarity reset to positive-polarity // Convert negative-polarity reset to positive-polarity
module \$_DFF_NN0_ (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule (* techmap_celltype = "$_DFF_NN0_" *)
module \$_DFF_PN0_ (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule module _90_dff_nn0_to_np0 (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
(* techmap_celltype = "$_DFF_PN0_" *)
module \$_DFF_NN1_ (input D, C, R, output Q); \$_DFF_NP1 _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
module \$_DFF_PN1_ (input D, C, R, output Q); \$_DFF_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule (* techmap_celltype = "$_DFF_NN1_" *)
module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
(* 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 \$__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

@ -42,6 +42,10 @@ struct SynthXilinxPass : public ScriptPass
log(" -top <module>\n"); log(" -top <module>\n");
log(" use the specified module as top module\n"); log(" use the specified module as top module\n");
log("\n"); log("\n");
log(" -arch {xcup|xcu|xc7|xc6s}\n");
log(" run synthesis for the specified Xilinx architecture\n");
log(" default: xc7\n");
log("\n");
log(" -edif <file>\n"); log(" -edif <file>\n");
log(" write the design to the specified edif file. writing of an output file\n"); log(" write the design to the specified edif file. writing of an output file\n");
log(" is omitted if this parameter is not specified.\n"); log(" is omitted if this parameter is not specified.\n");
@ -80,7 +84,7 @@ struct SynthXilinxPass : public ScriptPass
log("\n"); log("\n");
} }
std::string top_opt, edif_file, blif_file; std::string top_opt, edif_file, blif_file, arch;
bool flatten, retime, vpr, nobram, nodram, nosrl; bool flatten, retime, vpr, nobram, nodram, nosrl;
void clear_flags() YS_OVERRIDE void clear_flags() YS_OVERRIDE
@ -94,6 +98,7 @@ struct SynthXilinxPass : public ScriptPass
nobram = false; nobram = false;
nodram = false; nodram = false;
nosrl = false; nosrl = false;
arch = "xc7";
} }
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@ -108,6 +113,10 @@ struct SynthXilinxPass : public ScriptPass
top_opt = "-top " + args[++argidx]; top_opt = "-top " + args[++argidx];
continue; continue;
} }
if (args[argidx] == "-arch" && argidx+1 < args.size()) {
arch = args[++argidx];
continue;
}
if (args[argidx] == "-edif" && argidx+1 < args.size()) { if (args[argidx] == "-edif" && argidx+1 < args.size()) {
edif_file = args[++argidx]; edif_file = args[++argidx];
continue; continue;
@ -152,6 +161,9 @@ struct SynthXilinxPass : public ScriptPass
} }
extra_args(args, argidx, design); extra_args(args, argidx, design);
if (arch != "xcup" && arch != "xcu" && arch != "xc7" && arch != "xc6s")
log_cmd_error("Invalid Xilinx -arch setting: %s\n", arch.c_str());
if (!design->full_selection()) if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n"); log_cmd_error("This command only operates on fully selected designs!\n");
@ -257,7 +269,7 @@ struct SynthXilinxPass : public ScriptPass
if (check_label("check")) { if (check_label("check")) {
run("hierarchy -check"); run("hierarchy -check");
run("stat"); run("stat -tech xilinx");
run("check -noinit"); run("check -noinit");
} }

View File

@ -40,3 +40,15 @@ module dff1a_test(n1, n1_inv, clk);
n1 <= n1_inv; n1 <= n1_inv;
assign n1_inv = ~n1; assign n1_inv = ~n1;
endmodule endmodule
module dff_test_997 (y, clk, wire4);
// https://github.com/YosysHQ/yosys/issues/997
output wire [1:0] y;
input clk;
input signed wire4;
reg [1:0] reg10 = 0;
always @(posedge clk) begin
reg10 <= wire4;
end
assign y = reg10;
endmodule

25
tests/simple/forloops.v Normal file
View File

@ -0,0 +1,25 @@
module forloops01 (input clk, a, b, output reg [3:0] p, q, x, y);
integer k;
always @(posedge clk) begin
for (k=0; k<2; k=k+1)
p[2*k +: 2] = {a, b} ^ {2{k}};
x <= k + {a, b};
end
always @* begin
for (k=0; k<4; k=k+1)
q[k] = {~a, ~b, a, b} >> k[1:0];
y = k - {a, b};
end
endmodule
module forloops02 (input clk, a, b, output reg [3:0] q, x, output [3:0] y);
integer k;
always @* begin
for (k=0; k<4; k=k+1)
q[k] = {~a, ~b, a, b} >> k[1:0];
end
always @* begin
x = k + {a, b};
end
assign y = k - {a, b};
endmodule

View File

@ -0,0 +1,11 @@
module uut_localparam_attr (I, O);
(* LOCALPARAM_ATTRIBUTE = "attribute_content" *)
localparam WIDTH = 1;
input wire [WIDTH-1:0] I;
output wire [WIDTH-1:0] O;
assign O = I;
endmodule

View File

@ -92,3 +92,25 @@ module mem2reg_test5(input ctrl, output out);
assign out = bar[foo[0]]; assign out = bar[foo[0]];
endmodule endmodule
// ------------------------------------------------------
module mem2reg_test6 (din, dout);
input wire [3:0] din;
output reg [3:0] dout;
reg [1:0] din_array [1:0];
reg [1:0] dout_array [1:0];
always @* begin
din_array[0] = din[0 +: 2];
din_array[1] = din[2 +: 2];
dout_array[0] = din_array[0];
dout_array[1] = din_array[1];
{dout_array[0][1], dout_array[0][0]} = dout_array[0][0] + dout_array[1][0];
dout[0 +: 2] = dout_array[0];
dout[2 +: 2] = dout_array[1];
end
endmodule

11
tests/simple/param_attr.v Normal file
View File

@ -0,0 +1,11 @@
module uut_param_attr (I, O);
(* PARAMETER_ATTRIBUTE = "attribute_content" *)
parameter WIDTH = 1;
input wire [WIDTH-1:0] I;
output wire [WIDTH-1:0] O;
assign O = I;
endmodule

9
tests/simple/peepopt.v Normal file
View File

@ -0,0 +1,9 @@
module peepopt_shiftmul_0 #(parameter N=3, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output [W-1:0] o);
assign o = i[s*W+:W];
endmodule
module peepopt_muldiv_0(input [1:0] i, output [1:0] o);
wire [3:0] t;
assign t = i * 3;
assign o = t / 3;
endmodule

View File

@ -11,13 +11,13 @@ echo "" > $STDERRFILE
echo -n "Test: ${TESTNAME} -> " echo -n "Test: ${TESTNAME} -> "
$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}.sv ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_syn.v" >> $STDOUTFILE >> $STDERRFILE set -e
$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}_ref.v ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_ref_syn.v" >> $STDOUTFILE >> $STDERRFILE
$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}.sv ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_syn.v" >> $STDOUTFILE 2>> $STDERRFILE
$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}_ref.v ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_ref_syn.v" >> $STDOUTFILE 2>> $STDERRFILE
rm -f a.out reference_result.txt dut_result.txt rm -f a.out reference_result.txt dut_result.txt
set -e
iverilog -g2012 ${TESTNAME}_syn.v iverilog -g2012 ${TESTNAME}_syn.v
iverilog -g2012 ${TESTNAME}_ref_syn.v iverilog -g2012 ${TESTNAME}_ref_syn.v

View File

@ -147,7 +147,8 @@ do
fi fi
if $genvcd; then sed -i 's,// \$dump,$dump,g' ${bn}_tb.v; fi if $genvcd; then sed -i 's,// \$dump,$dump,g' ${bn}_tb.v; fi
compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.v $libs \ compile_and_run ${bn}_tb_ref ${bn}_out_ref ${bn}_tb.v ${bn}_ref.v $libs \
"$toolsdir"/../../techlibs/common/simlib.v "$toolsdir"/../../techlibs/common/simlib.v \
"$toolsdir"/../../techlibs/common/simcells.v
if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi if $genvcd; then mv testbench.vcd ${bn}_ref.vcd; fi
test_count=0 test_count=0

52
tests/various/chparam.sh Normal file
View File

@ -0,0 +1,52 @@
#!/bin/bash
trap 'echo "ERROR in chparam.sh" >&2; exit 1' ERR
cat > chparam1.sv << "EOT"
module top #(
parameter [31:0] X = 0
) (
input [31:0] din,
output [31:0] dout
);
assign dout = X-din;
endmodule
module top_props #(
parameter [31:0] X = 0
) (
input [31:0] dout
);
always @* assert (dout != X);
endmodule
bind top top_props #(.X(123456789)) props (.*);
EOT
cat > chparam2.sv << "EOT"
module top #(
parameter [31:0] X = 0
) (
input [31:0] din,
output [31:0] dout
);
assign dout = X-din;
always @* assert (dout != 123456789);
endmodule
EOT
if ../../yosys -q -p 'verific -sv chparam1.sv'; then
../../yosys -q -p 'verific -sv chparam1.sv; hierarchy -chparam X 123123123 -top top; prep -flatten' \
-p 'sat -verify -prove-asserts -show-ports -set din[0] 1' \
-p 'sat -falsify -prove-asserts -show-ports -set din[0] 0'
../../yosys -q -p 'verific -sv chparam2.sv; hierarchy -chparam X 123123123 -top top; prep -flatten' \
-p 'sat -verify -prove-asserts -show-ports -set din[0] 1' \
-p 'sat -falsify -prove-asserts -show-ports -set din[0] 0'
fi
../../yosys -q -p 'read_verilog -sv chparam2.sv; hierarchy -chparam X 123123123 -top top; prep -flatten' \
-p 'sat -verify -prove-asserts -show-ports -set din[0] 1' \
-p 'sat -falsify -prove-asserts -show-ports -set din[0] 0'
rm chparam1.sv
rm chparam2.sv

30
tests/various/specify.v Normal file
View File

@ -0,0 +1,30 @@
module test (
input EN, CLK,
input [3:0] D,
output reg [3:0] Q
);
always @(posedge CLK)
if (EN) Q <= D;
specify
if (EN) (CLK *> (Q : D)) = (1, 2:3:4);
$setup(D, posedge CLK &&& EN, 5);
$hold(posedge CLK, D &&& EN, 6);
endspecify
endmodule
module test2 (
input A, B,
output Q
);
xor (Q, A, B);
specify
//specparam T_rise = 1;
//specparam T_fall = 2;
`define T_rise 1
`define T_fall 2
(A => Q) = (`T_rise,`T_fall);
//(B => Q) = (`T_rise+`T_fall)/2.0;
(B => Q) = 1.5;
endspecify
endmodule

56
tests/various/specify.ys Normal file
View File

@ -0,0 +1,56 @@
read_verilog -specify specify.v
prep
cd test
select t:$specify2 -assert-count 0
select t:$specify3 -assert-count 1
select t:$specrule -assert-count 2
cd test2
select t:$specify2 -assert-count 2
select t:$specify3 -assert-count 0
select t:$specrule -assert-count 0
cd
write_verilog specify.out
design -stash gold
read_verilog -specify specify.out
prep
cd test
select t:$specify2 -assert-count 0
select t:$specify3 -assert-count 1
select t:$specrule -assert-count 2
cd test2
select t:$specify2 -assert-count 2
select t:$specify3 -assert-count 0
select t:$specrule -assert-count 0
cd
design -stash gate
design -copy-from gold -as gold test
design -copy-from gate -as gate test
rename -hide
rename -enumerate -pattern A_% t:$specify3
rename -enumerate -pattern B_% t:$specrule r:TYPE=$setup %i
rename -enumerate -pattern C_% t:$specrule r:TYPE=$hold %i
select n:A_* -assert-count 2
select n:B_* -assert-count 2
select n:C_* -assert-count 2
equiv_make gold gate equiv
hierarchy -top equiv
equiv_struct
equiv_induct -seq 5
equiv_status -assert
design -reset
design -copy-from gold -as gold test2
design -copy-from gate -as gate test2
rename -hide
rename -enumerate -pattern A_% t:$specify2 r:T_RISE_TYP=1 %i
rename -enumerate -pattern B_% t:$specify2 n:A_* %d
select n:A_* -assert-count 2
select n:B_* -assert-count 2
equiv_make gold gate equiv
hierarchy -top equiv
equiv_struct
equiv_induct -seq 5
equiv_status -assert
design -reset