mirror of https://github.com/YosysHQ/yosys.git
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
489c555b41
|
@ -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
|
11
Makefile
11
Makefile
|
@ -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_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"")
|
||||
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
|
||||
ENABLE_GCOV := 0
|
||||
|
@ -679,13 +680,13 @@ endif
|
|||
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR)
|
||||
$(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/.
|
||||
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) ldconfig
|
||||
ifeq ($(ENABLE_PYOSYS),1)
|
||||
$(INSTALL_SUDO) mkdir -p $(PYTHON_DESTDIR)/pyosys
|
||||
$(INSTALL_SUDO) cp libyosys.so $(PYTHON_DESTDIR)/pyosys
|
||||
$(INSTALL_SUDO) cp misc/__init__.py $(PYTHON_DESTDIR)/pyosys
|
||||
$(INSTALL_SUDO) cp libyosys.so $(PYTHON_DESTDIR)/pyosys/
|
||||
$(INSTALL_SUDO) cp misc/__init__.py $(PYTHON_DESTDIR)/pyosys/
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
18
README.md
18
README.md
|
@ -259,11 +259,7 @@ for them:
|
|||
|
||||
- The ``tri``, ``triand``, ``trior``, ``wand`` and ``wor`` net types
|
||||
|
||||
- The ``config`` keyword and library map files
|
||||
|
||||
- The ``disable``, ``primitive`` and ``specify`` statements
|
||||
|
||||
- Latched logic (is synthesized as logic with feedback loops)
|
||||
- The ``config`` and ``disable`` keywords and library map files
|
||||
|
||||
|
||||
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
|
||||
must be put in parentheses. Examples: ``WIDTH'd42``, ``(4+2)'b101010``
|
||||
|
||||
- The system tasks ``$finish`` and ``$display`` are supported in initial blocks
|
||||
in an unconditional context (only if/case statements on parameters
|
||||
and constant values). The intended use for this is synthesis-time DRC.
|
||||
- The system tasks ``$finish``, ``$stop`` and ``$display`` are supported in
|
||||
initial blocks in an unconditional context (only if/case statements on
|
||||
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
|
||||
|
|
|
@ -344,6 +344,7 @@ struct FirrtlWorker
|
|||
switch (dir) {
|
||||
case FD_INOUT:
|
||||
log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second));
|
||||
/* FALLTHRU */
|
||||
case FD_OUT:
|
||||
sourceExpr = firstName;
|
||||
sinkExpr = secondExpr;
|
||||
|
@ -351,7 +352,7 @@ struct FirrtlWorker
|
|||
break;
|
||||
case FD_NODIRECTION:
|
||||
log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second));
|
||||
/* FALL_THROUGH */
|
||||
/* FALLTHRU */
|
||||
case FD_IN:
|
||||
sourceExpr = secondExpr;
|
||||
sinkExpr = firstName;
|
||||
|
|
|
@ -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());
|
||||
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);
|
||||
f << stringf("\n");
|
||||
}
|
||||
|
|
|
@ -183,8 +183,9 @@ bool is_reg_wire(RTLIL::SigSpec sig, std::string ®_name)
|
|||
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)
|
||||
width = data.bits.size() - offset;
|
||||
if (width == 0) {
|
||||
|
@ -275,7 +276,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
|
|||
}
|
||||
}
|
||||
} else {
|
||||
f << stringf("\"");
|
||||
if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0)
|
||||
f << stringf("\"");
|
||||
std::string str = data.decode_string();
|
||||
for (size_t i = 0; i < str.size(); i++) {
|
||||
if (str[i] == '\n')
|
||||
|
@ -293,7 +295,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
|
|||
else
|
||||
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)))
|
||||
f << stringf(" 1 ");
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1242,6 +1245,118 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
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, $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())
|
||||
f << stringf(",");
|
||||
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, -1, 0, false, is_signed);
|
||||
dump_const(f, it->second);
|
||||
f << stringf(")");
|
||||
}
|
||||
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) {
|
||||
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());
|
||||
bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
|
||||
dump_const(f, it->second, -1, 0, false, is_signed);
|
||||
dump_const(f, it->second);
|
||||
f << stringf(";\n");
|
||||
}
|
||||
}
|
||||
|
@ -1505,7 +1618,8 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
|
|||
SigSpec sig = active_sigmap(wire);
|
||||
Const val = wire->attributes.at("\\init");
|
||||
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())
|
||||
|
|
|
@ -951,6 +951,9 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
|
|||
continue;
|
||||
if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
@ -1035,6 +1038,9 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
|
|||
child->delete_children();
|
||||
child->children.push_back(AstNode::mkconst_int(0, false, 0));
|
||||
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 {
|
||||
delete child;
|
||||
}
|
||||
|
|
|
@ -645,6 +645,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
|
|||
if (!id_ast->children[0]->range_valid)
|
||||
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;
|
||||
if (children.size() > 1)
|
||||
range = children[1];
|
||||
} else
|
||||
log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str());
|
||||
if (range) {
|
||||
|
@ -1490,10 +1492,12 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
continue;
|
||||
}
|
||||
if (child->type == AST_PARASET) {
|
||||
int extra_const_flags = 0;
|
||||
IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
|
||||
if (child->children[0]->type == AST_REALVALUE) {
|
||||
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);
|
||||
extra_const_flags = RTLIL::CONST_FLAG_REAL;
|
||||
auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue));
|
||||
strnode->cloneInto(child->children[0]);
|
||||
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_id(cell), log_id(paraname));
|
||||
cell->parameters[paraname] = child->children[0]->asParaConst();
|
||||
cell->parameters[paraname].flags |= extra_const_flags;
|
||||
continue;
|
||||
}
|
||||
if (child->type == AST_ARGUMENT) {
|
||||
|
@ -1521,9 +1526,29 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
|
|||
}
|
||||
for (auto &attr : attributes) {
|
||||
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();
|
||||
}
|
||||
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;
|
||||
|
||||
|
|
|
@ -1172,14 +1172,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
varbuf->children[0] = buf;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (type == AST_FOR) {
|
||||
AstNode *buf = next_ast->clone();
|
||||
delete buf->children[1];
|
||||
buf->children[1] = varbuf->children[0]->clone();
|
||||
current_block->children.insert(current_block->children.begin() + current_block_idx++, buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
current_scope[varbuf->str] = backup_scope_varbuf;
|
||||
delete varbuf;
|
||||
|
@ -1607,6 +1605,7 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
current_scope[wire_tmp->str] = wire_tmp;
|
||||
wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, 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);
|
||||
wire_tmp_id->str = wire_tmp->str;
|
||||
|
|
|
@ -53,6 +53,7 @@ USING_YOSYS_NAMESPACE
|
|||
"attribute" { return TOK_ATTRIBUTE; }
|
||||
"parameter" { return TOK_PARAMETER; }
|
||||
"signed" { return TOK_SIGNED; }
|
||||
"real" { return TOK_REAL; }
|
||||
"wire" { return TOK_WIRE; }
|
||||
"memory" { return TOK_MEMORY; }
|
||||
"width" { return TOK_WIDTH; }
|
||||
|
|
|
@ -45,7 +45,16 @@ YOSYS_NAMESPACE_END
|
|||
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 {
|
||||
char *string;
|
||||
|
@ -61,7 +70,7 @@ USING_YOSYS_NAMESPACE
|
|||
%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_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 <sigspec> sigspec sigspec_list
|
||||
|
@ -241,6 +250,12 @@ cell_body:
|
|||
free($4);
|
||||
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 {
|
||||
if (current_cell->hasPort($3))
|
||||
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell port %s.", $3).c_str());
|
||||
|
@ -445,4 +460,3 @@ conn_stmt:
|
|||
delete $2;
|
||||
delete $3;
|
||||
};
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ USING_YOSYS_NAMESPACE
|
|||
#include "VeriModule.h"
|
||||
#include "VeriWrite.h"
|
||||
#include "VhdlUnits.h"
|
||||
#include "Message.h"
|
||||
#include "VeriLibrary.h"
|
||||
|
||||
#ifdef __clang__
|
||||
#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)
|
||||
{
|
||||
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;
|
||||
|
||||
if (design->has(module_name)) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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> ¶meters, std::string top)
|
||||
{
|
||||
verific_sva_fsm_limit = 16;
|
||||
|
||||
std::set<Netlist*> nl_todo, nl_done;
|
||||
|
||||
{
|
||||
VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1);
|
||||
VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1);
|
||||
VhdlLibrary *vhdl_lib = vhdl_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;
|
||||
if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
|
||||
if (veri_lib) veri_libs.InsertLast(veri_lib);
|
||||
Map verific_params(STRING_HASH);
|
||||
for (const auto &i : parameters)
|
||||
verific_params.Insert(i.first.c_str(), i.second.c_str());
|
||||
|
||||
Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs);
|
||||
Netlist *nl;
|
||||
int i;
|
||||
if (top.empty()) {
|
||||
netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, &verific_params);
|
||||
}
|
||||
else {
|
||||
Array veri_modules, vhdl_units;
|
||||
|
||||
FOREACH_ARRAY_ITEM(netlists, i, nl) {
|
||||
if (top.empty() || nl->Owner()->Name() == top)
|
||||
nl_todo.insert(nl);
|
||||
if (veri_lib) {
|
||||
VeriModule *veri_module = veri_lib->GetModule(top.c_str(), 1);
|
||||
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())
|
||||
log_error("%s\n", verific_error_msg.c_str());
|
||||
|
||||
|
@ -2212,8 +2245,8 @@ struct VerificPass : public Pass {
|
|||
continue;
|
||||
}
|
||||
if (args[argidx] == "-chparam" && argidx+2 < GetSize(args)) {
|
||||
const std::string &key = args[++argidx];
|
||||
const std::string &value = args[++argidx];
|
||||
const std::string &key = args[++argidx];
|
||||
const std::string &value = args[++argidx];
|
||||
unsigned new_insertion = parameters.Insert(key.c_str(), value.c_str(),
|
||||
1 /* force_overwrite */);
|
||||
if (!new_insertion)
|
||||
|
@ -2270,12 +2303,22 @@ struct VerificPass : public Pass {
|
|||
for (; argidx < GetSize(args); argidx++)
|
||||
{
|
||||
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_module) {
|
||||
log("Adding Verilog module '%s' to elaboration queue.\n", name);
|
||||
veri_modules.InsertLast(veri_module);
|
||||
continue;
|
||||
if (veri_lib) {
|
||||
VeriModule *veri_module = veri_lib->GetModule(name, 1);
|
||||
if (veri_module) {
|
||||
log("Adding Verilog module '%s' to elaboration queue.\n", name);
|
||||
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);
|
||||
|
@ -2294,8 +2337,10 @@ struct VerificPass : public Pass {
|
|||
Netlist *nl;
|
||||
int i;
|
||||
|
||||
FOREACH_ARRAY_ITEM(netlists, i, nl)
|
||||
FOREACH_ARRAY_ITEM(netlists, i, nl) {
|
||||
nl->AddAtt(new Att(" \\top", NULL));
|
||||
nl_todo.insert(nl);
|
||||
}
|
||||
delete netlists;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ YOSYS_NAMESPACE_BEGIN
|
|||
extern int verific_verbose;
|
||||
|
||||
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> ¶meters, std::string top = std::string());
|
||||
|
||||
extern pool<int> verific_sva_prims;
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l
|
|||
$(Q) mkdir -p $(dir $@)
|
||||
$(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_lexer.o
|
||||
|
|
|
@ -158,6 +158,9 @@ struct VerilogFrontend : public Frontend {
|
|||
log(" delete (* whitebox *) and (* lib_whitebox *) attributes from\n");
|
||||
log(" all modules.\n");
|
||||
log("\n");
|
||||
log(" -specify\n");
|
||||
log(" parse and import specify blocks\n");
|
||||
log("\n");
|
||||
log(" -noopt\n");
|
||||
log(" don't perform basic optimizations (such as const folding) in the\n");
|
||||
log(" high-level front-end.\n");
|
||||
|
@ -228,6 +231,8 @@ struct VerilogFrontend : public Frontend {
|
|||
bool flag_nooverwrite = false;
|
||||
bool flag_overwrite = false;
|
||||
bool flag_defer = false;
|
||||
bool flag_noblackbox = false;
|
||||
bool flag_nowb = false;
|
||||
std::map<std::string, std::string> defines_map;
|
||||
std::list<std::string> include_dirs;
|
||||
std::list<std::string> attributes;
|
||||
|
@ -237,9 +242,8 @@ struct VerilogFrontend : public Frontend {
|
|||
formal_mode = false;
|
||||
norestrict_mode = false;
|
||||
assume_asserts_mode = false;
|
||||
noblackbox_mode = false;
|
||||
lib_mode = false;
|
||||
nowb_mode = false;
|
||||
specify_mode = false;
|
||||
default_nettype_wire = true;
|
||||
|
||||
args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end());
|
||||
|
@ -340,7 +344,7 @@ struct VerilogFrontend : public Frontend {
|
|||
continue;
|
||||
}
|
||||
if (arg == "-noblackbox") {
|
||||
noblackbox_mode = true;
|
||||
flag_noblackbox = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-lib") {
|
||||
|
@ -349,7 +353,11 @@ struct VerilogFrontend : public Frontend {
|
|||
continue;
|
||||
}
|
||||
if (arg == "-nowb") {
|
||||
nowb_mode = true;
|
||||
flag_nowb = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-specify") {
|
||||
specify_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-noopt") {
|
||||
|
@ -450,7 +458,7 @@ struct VerilogFrontend : public Frontend {
|
|||
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,
|
||||
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)
|
||||
delete lexin;
|
||||
|
|
|
@ -69,14 +69,11 @@ namespace VERILOG_FRONTEND
|
|||
// running in -assert-assumes mode
|
||||
extern bool assert_assumes_mode;
|
||||
|
||||
// running in -noblackbox mode
|
||||
extern bool noblackbox_mode;
|
||||
|
||||
// running in -lib mode
|
||||
extern bool lib_mode;
|
||||
|
||||
// running in -nowb mode
|
||||
extern bool nowb_mode;
|
||||
// running in -specify mode
|
||||
extern bool specify_mode;
|
||||
|
||||
// lexer input stream
|
||||
extern std::istream *lexin;
|
||||
|
|
|
@ -148,7 +148,7 @@ YOSYS_NAMESPACE_END
|
|||
"endfunction" { return TOK_ENDFUNCTION; }
|
||||
"task" { return TOK_TASK; }
|
||||
"endtask" { return TOK_ENDTASK; }
|
||||
"specify" { return TOK_SPECIFY; }
|
||||
"specify" { return specify_mode ? TOK_SPECIFY : TOK_IGNORED_SPECIFY; }
|
||||
"endspecify" { return TOK_ENDSPECIFY; }
|
||||
"specparam" { return TOK_SPECPARAM; }
|
||||
"package" { SV_KEYWORD(TOK_PACKAGE); }
|
||||
|
@ -206,7 +206,9 @@ YOSYS_NAMESPACE_END
|
|||
"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
|
||||
"checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); }
|
||||
"endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); }
|
||||
"final" { SV_KEYWORD(TOK_FINAL); }
|
||||
"logic" { SV_KEYWORD(TOK_LOGIC); }
|
||||
"var" { SV_KEYWORD(TOK_VAR); }
|
||||
"bit" { SV_KEYWORD(TOK_REG); }
|
||||
|
||||
"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
|
||||
|
@ -301,6 +303,12 @@ supply1 { return TOK_SUPPLY1; }
|
|||
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; }
|
||||
"$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_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); }
|
||||
<COMMENT>. /* ignore comment body */
|
||||
<COMMENT>\n /* ignore comment body */
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace VERILOG_FRONTEND {
|
|||
std::vector<char> case_type_stack;
|
||||
bool do_not_require_port_stubs;
|
||||
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 assume_asserts_mode, assert_assumes_mode;
|
||||
bool current_wire_rand, current_wire_const;
|
||||
|
@ -94,29 +94,58 @@ static void free_attr(std::map<std::string, AstNode*> *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 {
|
||||
std::string *string;
|
||||
struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast;
|
||||
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;
|
||||
char ch;
|
||||
}
|
||||
|
||||
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL
|
||||
%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER
|
||||
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
|
||||
%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 TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
|
||||
%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_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_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC
|
||||
%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_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
|
||||
%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 <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
|
||||
%left OP_LOR
|
||||
%left OP_LAND
|
||||
|
@ -456,6 +491,9 @@ wire_type_token:
|
|||
TOK_LOGIC {
|
||||
astbuf3->is_logic = true;
|
||||
} |
|
||||
TOK_VAR {
|
||||
astbuf3->is_logic = true;
|
||||
} |
|
||||
TOK_INTEGER {
|
||||
astbuf3->is_reg = true;
|
||||
astbuf3->range_left = 31;
|
||||
|
@ -539,7 +577,7 @@ module_body:
|
|||
|
||||
module_body_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:
|
||||
TOK_CHECKER TOK_ID ';' {
|
||||
|
@ -697,15 +735,254 @@ task_func_body:
|
|||
task_func_body behavioral_stmt |
|
||||
/* empty */;
|
||||
|
||||
specify_block:
|
||||
TOK_SPECIFY specify_item_opt TOK_ENDSPECIFY |
|
||||
TOK_SPECIFY TOK_ENDSPECIFY ;
|
||||
/*************************** specify parser ***************************/
|
||||
|
||||
specify_item_opt:
|
||||
specify_item_opt specify_item |
|
||||
specify_item ;
|
||||
specify_block:
|
||||
TOK_SPECIFY specify_item_list TOK_ENDSPECIFY;
|
||||
|
||||
specify_item_list:
|
||||
specify_item specify_item_list |
|
||||
/* empty */;
|
||||
|
||||
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
|
||||
// | pulsestyle_declaration
|
||||
// | showcancelled_declaration
|
||||
|
@ -721,13 +998,13 @@ specparam_declaration:
|
|||
// and the 'non_opt_range' rule allows index ranges not allowed by 1364-2005
|
||||
// exxxxtending this for SV specparam would change this anyhow
|
||||
specparam_range:
|
||||
'[' constant_expression ':' constant_expression ']' ;
|
||||
'[' ignspec_constant_expression ':' ignspec_constant_expression ']' ;
|
||||
|
||||
list_of_specparam_assignments:
|
||||
specparam_assignment | list_of_specparam_assignments ',' specparam_assignment;
|
||||
|
||||
specparam_assignment:
|
||||
TOK_ID '=' constant_mintypmax_expression ;
|
||||
ignspec_id '=' constant_mintypmax_expression ;
|
||||
|
||||
/*
|
||||
pulsestyle_declaration :
|
||||
|
@ -802,19 +1079,19 @@ opt_polarity_operator :
|
|||
|
||||
// Good enough for the time being
|
||||
specify_input_terminal_descriptor :
|
||||
TOK_ID ;
|
||||
ignspec_id ;
|
||||
|
||||
// Good enough for the time being
|
||||
specify_output_terminal_descriptor :
|
||||
TOK_ID ;
|
||||
ignspec_id ;
|
||||
|
||||
system_timing_declaration :
|
||||
TOK_ID '(' system_timing_args ')' ';' ;
|
||||
ignspec_id '(' system_timing_args ')' ';' ;
|
||||
|
||||
system_timing_arg :
|
||||
TOK_POSEDGE TOK_ID |
|
||||
TOK_NEGEDGE TOK_ID |
|
||||
expr ;
|
||||
TOK_POSEDGE ignspec_id |
|
||||
TOK_NEGEDGE ignspec_id |
|
||||
ignspec_expr ;
|
||||
|
||||
system_timing_args :
|
||||
system_timing_arg |
|
||||
|
@ -871,19 +1148,27 @@ tzx_path_delay_expression :
|
|||
*/
|
||||
|
||||
path_delay_expression :
|
||||
constant_expression;
|
||||
ignspec_constant_expression;
|
||||
|
||||
constant_mintypmax_expression :
|
||||
constant_expression
|
||||
| constant_expression ':' constant_expression ':' constant_expression
|
||||
ignspec_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.
|
||||
// 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'
|
||||
// (such as param assignment), so we may leave this as-is, perhaps adding runtime checks for constant-ness
|
||||
constant_expression:
|
||||
expr ;
|
||||
ignspec_constant_expression:
|
||||
expr { delete $1; };
|
||||
|
||||
ignspec_expr:
|
||||
expr { delete $1; };
|
||||
|
||||
ignspec_id:
|
||||
TOK_ID { delete $1; };
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
param_signed:
|
||||
TOK_SIGNED {
|
||||
|
@ -917,7 +1202,7 @@ param_range:
|
|||
};
|
||||
|
||||
param_decl:
|
||||
TOK_PARAMETER {
|
||||
attr TOK_PARAMETER {
|
||||
astbuf1 = new AstNode(AST_PARAMETER);
|
||||
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
|
||||
} param_signed param_integer param_real param_range param_decl_list ';' {
|
||||
|
@ -925,7 +1210,7 @@ param_decl:
|
|||
};
|
||||
|
||||
localparam_decl:
|
||||
TOK_LOCALPARAM {
|
||||
attr TOK_LOCALPARAM {
|
||||
astbuf1 = new AstNode(AST_LOCALPARAM);
|
||||
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
|
||||
} param_signed param_integer param_real param_range param_decl_list ';' {
|
||||
|
@ -1341,6 +1626,9 @@ opt_property:
|
|||
TOK_PROPERTY {
|
||||
$$ = true;
|
||||
} |
|
||||
TOK_FINAL {
|
||||
$$ = false;
|
||||
} |
|
||||
/* empty */ {
|
||||
$$ = false;
|
||||
};
|
||||
|
@ -2139,4 +2427,3 @@ concat_list:
|
|||
$$ = $3;
|
||||
$$->children.push_back($1);
|
||||
};
|
||||
|
||||
|
|
|
@ -85,6 +85,8 @@ struct CellTypes
|
|||
setup_internals_eval();
|
||||
|
||||
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);
|
||||
|
||||
|
@ -99,6 +101,9 @@ struct CellTypes
|
|||
setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true);
|
||||
setup_type("$allseq", pool<RTLIL::IdString>(), {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()
|
||||
|
|
|
@ -218,15 +218,19 @@ void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value)
|
|||
{
|
||||
if (value)
|
||||
attributes[id] = RTLIL::Const(1);
|
||||
else if (attributes.count(id))
|
||||
attributes.erase(id);
|
||||
else {
|
||||
const auto it = attributes.find(id);
|
||||
if (it != attributes.end())
|
||||
attributes.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
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 attributes.at(id).as_bool();
|
||||
return it->second.as_bool();
|
||||
}
|
||||
|
||||
void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool<string> &data)
|
||||
|
@ -1194,6 +1198,46 @@ namespace {
|
|||
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 == "$_NOT_") { check_gate("AY"); return; }
|
||||
if (cell->type == "$_AND_") { check_gate("ABY"); return; }
|
||||
|
@ -1470,7 +1514,10 @@ void RTLIL::Module::add(RTLIL::Cell *cell)
|
|||
cell->module = this;
|
||||
}
|
||||
|
||||
namespace {
|
||||
void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
|
||||
{
|
||||
log_assert(refcount_wires_ == 0);
|
||||
|
||||
struct DeleteWireWorker
|
||||
{
|
||||
RTLIL::Module *module;
|
||||
|
@ -1485,17 +1532,29 @@ namespace {
|
|||
}
|
||||
sig = chunks;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
|
||||
{
|
||||
log_assert(refcount_wires_ == 0);
|
||||
void operator()(RTLIL::SigSpec &lhs, RTLIL::SigSpec &rhs) {
|
||||
log_assert(GetSize(lhs) == GetSize(rhs));
|
||||
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;
|
||||
delete_wire_worker.module = this;
|
||||
delete_wire_worker.wires_p = &wires;
|
||||
rewrite_sigspecs(delete_wire_worker);
|
||||
rewrite_sigspecs2(delete_wire_worker);
|
||||
|
||||
for (auto &it : wires) {
|
||||
log_assert(wires_.count(it->name) != 0);
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace RTLIL
|
|||
CONST_FLAG_NONE = 0,
|
||||
CONST_FLAG_STRING = 1,
|
||||
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;
|
||||
|
@ -518,6 +518,7 @@ struct RTLIL::Const
|
|||
Const(const std::vector<RTLIL::State> &bits) : bits(bits) { flags = CONST_FLAG_NONE; }
|
||||
Const(const std::vector<bool> &bits);
|
||||
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;
|
||||
|
@ -597,6 +598,7 @@ struct RTLIL::SigChunk
|
|||
SigChunk(RTLIL::State bit, int width = 1);
|
||||
SigChunk(RTLIL::SigBit bit);
|
||||
SigChunk(const RTLIL::SigChunk &sigchunk);
|
||||
RTLIL::SigChunk &operator =(const RTLIL::SigChunk &other) = default;
|
||||
|
||||
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::SigSpec &sig);
|
||||
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;
|
||||
|
@ -998,6 +1001,7 @@ public:
|
|||
void fixup_ports();
|
||||
|
||||
template<typename T> void rewrite_sigspecs(T &functor);
|
||||
template<typename T> void rewrite_sigspecs2(T &functor);
|
||||
void cloneInto(RTLIL::Module *new_mod) const;
|
||||
virtual RTLIL::Module *clone() const;
|
||||
|
||||
|
@ -1303,6 +1307,7 @@ public:
|
|||
}
|
||||
|
||||
template<typename T> void rewrite_sigspecs(T &functor);
|
||||
template<typename T> void rewrite_sigspecs2(T &functor);
|
||||
|
||||
#ifdef WITH_PYTHON
|
||||
static std::map<unsigned int, RTLIL::Cell*> *get_all_cells(void);
|
||||
|
@ -1321,6 +1326,7 @@ struct RTLIL::CaseRule
|
|||
bool empty() const;
|
||||
|
||||
template<typename T> void rewrite_sigspecs(T &functor);
|
||||
template<typename T> void rewrite_sigspecs2(T &functor);
|
||||
RTLIL::CaseRule *clone() const;
|
||||
};
|
||||
|
||||
|
@ -1334,6 +1340,7 @@ struct RTLIL::SwitchRule : public RTLIL::AttrObject
|
|||
bool empty() const;
|
||||
|
||||
template<typename T> void rewrite_sigspecs(T &functor);
|
||||
template<typename T> void rewrite_sigspecs2(T &functor);
|
||||
RTLIL::SwitchRule *clone() const;
|
||||
};
|
||||
|
||||
|
@ -1344,6 +1351,7 @@ struct RTLIL::SyncRule
|
|||
std::vector<RTLIL::SigSig> actions;
|
||||
|
||||
template<typename T> void rewrite_sigspecs(T &functor);
|
||||
template<typename T> void rewrite_sigspecs2(T &functor);
|
||||
RTLIL::SyncRule *clone() const;
|
||||
};
|
||||
|
||||
|
@ -1356,6 +1364,7 @@ struct RTLIL::Process : public RTLIL::AttrObject
|
|||
~Process();
|
||||
|
||||
template<typename T> void rewrite_sigspecs(T &functor);
|
||||
template<typename T> void rewrite_sigspecs2(T &functor);
|
||||
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>
|
||||
void RTLIL::Cell::rewrite_sigspecs(T &functor) {
|
||||
for (auto &it : connections_)
|
||||
functor(it.second);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RTLIL::Cell::rewrite_sigspecs2(T &functor) {
|
||||
for (auto &it : connections_)
|
||||
functor(it.second);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RTLIL::CaseRule::rewrite_sigspecs(T &functor) {
|
||||
for (auto &it : compare)
|
||||
|
@ -1435,6 +1462,17 @@ void RTLIL::CaseRule::rewrite_sigspecs(T &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>
|
||||
void RTLIL::SwitchRule::rewrite_sigspecs(T &functor)
|
||||
{
|
||||
|
@ -1443,6 +1481,14 @@ void RTLIL::SwitchRule::rewrite_sigspecs(T &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>
|
||||
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>
|
||||
void RTLIL::Process::rewrite_sigspecs(T &functor)
|
||||
{
|
||||
|
@ -1461,6 +1516,14 @@ void RTLIL::Process::rewrite_sigspecs(T &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
|
||||
|
||||
#endif
|
||||
|
|
|
@ -151,14 +151,16 @@ void yosys_banner()
|
|||
|
||||
int ceil_log2(int x)
|
||||
{
|
||||
#if defined(__GNUC__)
|
||||
return x > 1 ? (8*sizeof(int)) - __builtin_clz(x-1) : 0;
|
||||
#else
|
||||
if (x <= 0)
|
||||
return 0;
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
if (((x-1) >> i) == 0)
|
||||
return i;
|
||||
|
||||
log_abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string stringf(const char *fmt, ...)
|
||||
|
|
|
@ -244,7 +244,7 @@ extern bool memhasher_active;
|
|||
inline void memhasher() { if (memhasher_active) memhasher_do(); }
|
||||
|
||||
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 vstringf(const char *fmt, va_list ap);
|
||||
int readsome(std::istream &f, char *s, int n);
|
||||
|
|
|
@ -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.
|
||||
\end{fixme}
|
||||
|
||||
\begin{fixme}
|
||||
Add information about {\tt \$specify2}, {\tt \$specify3}, and {\tt \$specrule} cells.
|
||||
\end{fixme}
|
||||
|
||||
\begin{fixme}
|
||||
Add information about {\tt \$slice} and {\tt \$concat} cells.
|
||||
\end{fixme}
|
||||
|
|
|
@ -281,6 +281,9 @@ struct BugpointPass : public Pass {
|
|||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
if (script.empty())
|
||||
log_cmd_error("Missing -script option.\n");
|
||||
|
||||
if (!has_part)
|
||||
{
|
||||
modules = true;
|
||||
|
@ -298,7 +301,7 @@ struct BugpointPass : public Pass {
|
|||
if (!check_logfile(grep))
|
||||
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;
|
||||
while (true)
|
||||
{
|
||||
|
@ -324,7 +327,6 @@ struct BugpointPass : public Pass {
|
|||
if (crashing_design != design)
|
||||
delete crashing_design;
|
||||
crashing_design = simplified;
|
||||
crashing_seed = seed;
|
||||
found_something = true;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -98,21 +98,23 @@ struct CoverPass : public Pass {
|
|||
}
|
||||
if ((args[argidx] == "-o" || args[argidx] == "-a" || args[argidx] == "-d") && argidx+1 < args.size()) {
|
||||
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") {
|
||||
#ifdef _WIN32
|
||||
log_cmd_error("The 'cover -d' option is not supported on win32.\n");
|
||||
#else
|
||||
char filename_buffer[4096];
|
||||
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
|
||||
} else {
|
||||
f = fopen(filename.c_str(), open_mode);
|
||||
}
|
||||
FILE *f = fopen(filename.c_str(), open_mode);
|
||||
if (f == NULL) {
|
||||
for (auto f : out_files)
|
||||
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);
|
||||
continue;
|
||||
|
|
|
@ -37,7 +37,9 @@ struct statdata_t
|
|||
STAT_INT_MEMBERS
|
||||
#undef X
|
||||
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::set<RTLIL::IdString> unknown_cell_area;
|
||||
|
||||
|
@ -70,8 +72,10 @@ struct statdata_t
|
|||
#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;
|
||||
STAT_NUMERIC_MEMBERS
|
||||
#undef X
|
||||
|
@ -153,7 +157,8 @@ struct statdata_t
|
|||
log(" Number of processes: %6d\n", num_processes);
|
||||
log(" Number of cells: %6d\n", num_cells);
|
||||
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()) {
|
||||
log("\n");
|
||||
|
@ -165,6 +170,59 @@ struct statdata_t
|
|||
log("\n");
|
||||
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(" use cell area information from the provided liberty file\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(" annotate internal cell types with their word width.\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;
|
||||
std::map<RTLIL::IdString, statdata_t> mod_stat;
|
||||
dict<IdString, double> cell_area;
|
||||
string techname;
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
|
@ -253,6 +316,10 @@ struct StatPass : public Pass {
|
|||
read_liberty_cellarea(cell_area, liberty_file);
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-tech" && argidx+1 < args.size()) {
|
||||
techname = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-top" && argidx+1 < args.size()) {
|
||||
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());
|
||||
|
@ -263,13 +330,16 @@ struct StatPass : public Pass {
|
|||
}
|
||||
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())
|
||||
{
|
||||
if (!top_mod && design->full_selection())
|
||||
if (mod->get_bool_attribute("\\top"))
|
||||
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;
|
||||
|
||||
log("\n");
|
||||
|
|
|
@ -570,7 +570,7 @@ struct HierarchyPass : public Pass {
|
|||
log("\n");
|
||||
log(" -simcheck\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(" -purge_lib\n");
|
||||
log(" by default the hierarchy command will not remove library (blackbox)\n");
|
||||
|
@ -583,20 +583,20 @@ struct HierarchyPass : public Pass {
|
|||
log("\n");
|
||||
log(" -keep_positionals\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(" -keep_portwidths\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("\n");
|
||||
log(" -nokeep_asserts\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(" option disables this behavior.\n");
|
||||
log(" that directly or indirectly contain one or more formal properties.\n");
|
||||
log(" This option disables this behavior.\n");
|
||||
log("\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("\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(" automatically determine the top of the design hierarchy and mark it.\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("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");
|
||||
|
@ -641,6 +647,7 @@ struct HierarchyPass : public Pass {
|
|||
bool nokeep_asserts = false;
|
||||
std::vector<std::string> generate_cells;
|
||||
std::vector<generate_port_decl_t> generate_ports;
|
||||
std::map<std::string, std::string> parameters;
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
|
@ -715,28 +722,61 @@ struct HierarchyPass : public Pass {
|
|||
if (args[argidx] == "-top") {
|
||||
if (++argidx >= args.size())
|
||||
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;
|
||||
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];
|
||||
load_top_mod = args[argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-auto-top") {
|
||||
auto_top_mode = true;
|
||||
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;
|
||||
}
|
||||
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 ¶ : 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
|
||||
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));
|
||||
}
|
||||
#endif
|
||||
|
@ -745,7 +785,7 @@ struct HierarchyPass : public Pass {
|
|||
} else {
|
||||
#ifdef YOSYS_ENABLE_VERIFIC
|
||||
if (verific_import_pending)
|
||||
verific_import(design);
|
||||
verific_import(design, parameters);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -846,7 +886,7 @@ struct HierarchyPass : public Pass {
|
|||
std::map<RTLIL::Module*, bool> cache;
|
||||
for (auto mod : design->modules())
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ struct keep_cache_t
|
|||
|
||||
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;
|
||||
|
||||
if (cell->has_keep_attr())
|
||||
|
@ -85,22 +85,34 @@ void rmunused_module_cells(Module *module, bool verbose)
|
|||
{
|
||||
SigMap sigmap(module);
|
||||
pool<Cell*> queue, unused;
|
||||
pool<SigBit> used_raw_bits;
|
||||
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_) {
|
||||
Cell *cell = it.second;
|
||||
for (auto &it2 : cell->connections()) {
|
||||
if (!ct_all.cell_known(cell->type) || ct_all.cell_output(cell->type, it2.first))
|
||||
for (auto raw_bit : it2.second) {
|
||||
if (raw_bit.wire == nullptr)
|
||||
continue;
|
||||
auto bit = sigmap(raw_bit);
|
||||
if (bit.wire == nullptr)
|
||||
log_warning("Driver-driver conflict for %s between cell %s.%s and constant %s in %s: Resolved using constant.\n",
|
||||
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 (ct_all.cell_known(cell->type) && !ct_all.cell_output(cell->type, it2.first))
|
||||
continue;
|
||||
for (auto raw_bit : it2.second) {
|
||||
if (raw_bit.wire == nullptr)
|
||||
continue;
|
||||
auto bit = sigmap(raw_bit);
|
||||
if (bit.wire == nullptr)
|
||||
driver_driver_logs[raw_sigmap(raw_bit)].push_back(stringf("Driver-driver conflict "
|
||||
"for %s between cell %s.%s and constant %s in %s: Resolved using constant.",
|
||||
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))
|
||||
queue.insert(cell);
|
||||
|
@ -114,6 +126,8 @@ void rmunused_module_cells(Module *module, bool verbose)
|
|||
for (auto bit : sigmap(wire))
|
||||
for (auto c : wire2driver[bit])
|
||||
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);
|
||||
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)
|
||||
|
@ -202,7 +232,7 @@ bool check_public_name(RTLIL::IdString id)
|
|||
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 connected_signals;
|
||||
|
@ -245,11 +275,13 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
|
|||
module->connections_.clear();
|
||||
|
||||
SigPool used_signals;
|
||||
SigPool raw_used_signals;
|
||||
SigPool used_signals_nodrivers;
|
||||
for (auto &it : module->cells_) {
|
||||
RTLIL::Cell *cell = it.second;
|
||||
for (auto &it2 : cell->connections_) {
|
||||
assign_map.apply(it2.second);
|
||||
raw_used_signals.add(it2.second);
|
||||
used_signals.add(it2.second);
|
||||
if (!ct_all.cell_output(cell->type, it2.first))
|
||||
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;
|
||||
if (wire->port_id > 0) {
|
||||
RTLIL::SigSpec sig = RTLIL::SigSpec(wire);
|
||||
raw_used_signals.add(sig);
|
||||
assign_map.apply(sig);
|
||||
used_signals.add(sig);
|
||||
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())
|
||||
{
|
||||
if ((!purge_mode && check_public_name(wire->name)) || wire->port_id != 0 || wire->get_bool_attribute("\\keep") || wire->attributes.count("\\init")) {
|
||||
RTLIL::SigSpec s1 = RTLIL::SigSpec(wire), s2 = s1;
|
||||
assign_map.apply(s2);
|
||||
if (!used_signals.check_any(s2) && wire->port_id == 0 && !wire->get_bool_attribute("\\keep")) {
|
||||
maybe_del_wires.push_back(wire);
|
||||
} else {
|
||||
log_assert(GetSize(s1) == GetSize(s2));
|
||||
Const initval;
|
||||
if (wire->attributes.count("\\init"))
|
||||
initval = wire->attributes.at("\\init");
|
||||
if (GetSize(initval) != GetSize(wire))
|
||||
initval.bits.resize(GetSize(wire), State::Sx);
|
||||
RTLIL::SigSig new_conn;
|
||||
for (int i = 0; i < GetSize(s1); 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);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!used_signals.check_any(RTLIL::SigSpec(wire)))
|
||||
maybe_del_wires.push_back(wire);
|
||||
SigSpec s1 = SigSpec(wire), s2 = assign_map(s1);
|
||||
log_assert(GetSize(s1) == GetSize(s2));
|
||||
|
||||
Const initval;
|
||||
if (wire->attributes.count("\\init"))
|
||||
initval = wire->attributes.at("\\init");
|
||||
if (GetSize(initval) != GetSize(wire))
|
||||
initval.bits.resize(GetSize(wire), State::Sx);
|
||||
if (initval.is_fully_undef())
|
||||
wire->attributes.erase("\\init");
|
||||
|
||||
if (GetSize(wire) == 0) {
|
||||
// delete zero-width wires
|
||||
goto delete_this_wire;
|
||||
} else
|
||||
if (wire->port_id != 0 || wire->get_bool_attribute("\\keep") || !initval.is_fully_undef()) {
|
||||
// do not delete anything with "keep" or module ports or initialized wires
|
||||
} else
|
||||
if (!purge_mode && check_public_name(wire->name)) {
|
||||
// do not get rid of public names unless in purge mode
|
||||
} else
|
||||
if (!raw_used_signals.check_any(s1)) {
|
||||
// delete wires that aren't used by anything directly
|
||||
goto delete_this_wire;
|
||||
} else
|
||||
if (!used_signals.check_any(s2)) {
|
||||
// delete wires that aren't used by anything indirectly, even though other wires may alias it
|
||||
goto delete_this_wire;
|
||||
}
|
||||
|
||||
RTLIL::SigSpec sig = assign_map(RTLIL::SigSpec(wire));
|
||||
if (!used_signals_nodrivers.check_any(sig)) {
|
||||
std::string unused_bits;
|
||||
for (int i = 0; i < GetSize(sig); i++) {
|
||||
if (sig[i].wire == NULL)
|
||||
continue;
|
||||
if (!used_signals_nodrivers.check(sig[i])) {
|
||||
if (!unused_bits.empty())
|
||||
unused_bits += " ";
|
||||
unused_bits += stringf("%d", i);
|
||||
if (0)
|
||||
{
|
||||
delete_this_wire:
|
||||
del_wires_queue.insert(wire);
|
||||
}
|
||||
else
|
||||
{
|
||||
RTLIL::SigSig new_conn;
|
||||
for (int i = 0; i < GetSize(s1); 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");
|
||||
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;
|
||||
for (auto wire : maybe_del_wires)
|
||||
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++;
|
||||
}
|
||||
if (verbose && del_temp_wires_count)
|
||||
log_debug(" removed %d unused temporary wires.\n", del_temp_wires_count);
|
||||
|
||||
module->remove(del_wires);
|
||||
count_rm_wires += del_wires.size();
|
||||
|
||||
if (verbose && del_wires_count > 0)
|
||||
log_debug(" removed %d unused temporary wires.\n", del_wires_count);
|
||||
return !del_wires_queue.empty();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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))
|
||||
rmunused_module_signals(module, purge_mode, verbose);
|
||||
while (rmunused_module_signals(module, purge_mode, verbose)) { }
|
||||
}
|
||||
|
||||
struct OptCleanPass : public Pass {
|
||||
|
@ -496,6 +546,9 @@ struct OptCleanPass : public Pass {
|
|||
|
||||
ct_all.setup(design);
|
||||
|
||||
count_rm_cells = 0;
|
||||
count_rm_wires = 0;
|
||||
|
||||
for (auto module : design->selected_whole_modules_warn()) {
|
||||
if (module->has_processes_warn())
|
||||
continue;
|
||||
|
@ -561,7 +614,7 @@ struct CleanPass : public Pass {
|
|||
for (auto module : design->selected_whole_modules()) {
|
||||
if (module->has_processes())
|
||||
continue;
|
||||
rmunused_module(module, purge_mode, false, false);
|
||||
rmunused_module(module, purge_mode, ys_debug(), false);
|
||||
}
|
||||
|
||||
log_suppressed();
|
||||
|
|
|
@ -61,7 +61,7 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
|
|||
}
|
||||
if (wire->port_input)
|
||||
driven_signals.add(sigmap(wire));
|
||||
if (wire->port_output)
|
||||
if (wire->port_output || wire->get_bool_attribute("\\keep"))
|
||||
used_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);
|
||||
did_something = true;
|
||||
}
|
||||
|
@ -104,10 +104,15 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
|
|||
if (SigBit(initval[i]) == sig[i])
|
||||
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");
|
||||
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;
|
||||
did_something = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)" : "");
|
||||
root_mux_rerun.erase(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()) {
|
||||
|
@ -192,9 +196,14 @@ struct OptMuxtreeWorker
|
|||
log_assert(root_enable_muxes.at(mux_idx));
|
||||
root_mux_rerun.erase(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_assert(glob_abort_cnt > 0);
|
||||
|
||||
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)
|
||||
{
|
||||
if (glob_abort_cnt == 0) {
|
||||
log(" Giving up (too many iterations)\n");
|
||||
if (glob_abort_cnt == 0)
|
||||
return;
|
||||
}
|
||||
glob_abort_cnt--;
|
||||
|
||||
muxinfo_t &muxinfo = mux2info[mux_idx];
|
||||
|
@ -454,6 +461,7 @@ struct OptMuxtreeWorker
|
|||
|
||||
void eval_root_mux(int mux_idx)
|
||||
{
|
||||
log_assert(glob_abort_cnt > 0);
|
||||
knowledge_t knowledge;
|
||||
knowledge.known_inactive.resize(GetSize(bit2info));
|
||||
knowledge.known_active.resize(GetSize(bit2info));
|
||||
|
|
|
@ -531,6 +531,42 @@ struct WreducePass : public Pass {
|
|||
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")) {
|
||||
IdString memid = c->getParam("\\MEMID").decode_string();
|
||||
RTLIL::Memory *mem = module->memories.at(memid);
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
/ice40_dsp_pm.h
|
||||
/peepopt_pm.h
|
||||
|
|
|
@ -1,8 +1,23 @@
|
|||
OBJS += passes/pmgen/ice40_dsp.o
|
||||
OBJS += passes/pmgen/peepopt.o
|
||||
|
||||
# --------------------------------------
|
||||
|
||||
passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h
|
||||
EXTRA_OBJS += 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
|
||||
$(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 $<,$^)
|
||||
|
|
|
@ -29,19 +29,25 @@ up in any future matches:
|
|||
|
||||
pm.blacklist(some_cell);
|
||||
|
||||
The `.run(callback_function)` method searches for all matches and calls the
|
||||
callback function for each found match:
|
||||
The `.run_<pattern_name>(callback_function)` method searches for all matches
|
||||
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(" with 'bar' cell: %s\n", log_id(pm.st.bar));
|
||||
});
|
||||
|
||||
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
|
||||
`.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
|
||||
|
@ -52,6 +58,12 @@ lines consist of whitespace-separated tokens.
|
|||
|
||||
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
|
||||
-------------------------
|
||||
|
||||
|
@ -66,7 +78,7 @@ State variables are automatically managed by the generated backtracking algorith
|
|||
and saved and restored as needed.
|
||||
|
||||
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
|
||||
-------------------------
|
||||
|
|
|
@ -19,47 +19,50 @@
|
|||
|
||||
#include "kernel/yosys.h"
|
||||
#include "kernel/sigtools.h"
|
||||
#include "passes/pmgen/ice40_dsp_pm.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
#include "passes/pmgen/ice40_dsp_pm.h"
|
||||
|
||||
void create_ice40_dsp(ice40_dsp_pm &pm)
|
||||
{
|
||||
auto &st = pm.st_ice40_dsp;
|
||||
|
||||
#if 0
|
||||
log("\n");
|
||||
log("ffA: %s\n", log_id(pm.st.ffA, "--"));
|
||||
log("ffB: %s\n", log_id(pm.st.ffB, "--"));
|
||||
log("mul: %s\n", log_id(pm.st.mul, "--"));
|
||||
log("ffY: %s\n", log_id(pm.st.ffY, "--"));
|
||||
log("addAB: %s\n", log_id(pm.st.addAB, "--"));
|
||||
log("muxAB: %s\n", log_id(pm.st.muxAB, "--"));
|
||||
log("ffS: %s\n", log_id(pm.st.ffS, "--"));
|
||||
log("ffA: %s\n", log_id(st.ffA, "--"));
|
||||
log("ffB: %s\n", log_id(st.ffB, "--"));
|
||||
log("mul: %s\n", log_id(st.mul, "--"));
|
||||
log("ffY: %s\n", log_id(st.ffY, "--"));
|
||||
log("addAB: %s\n", log_id(st.addAB, "--"));
|
||||
log("muxAB: %s\n", log_id(st.muxAB, "--"));
|
||||
log("ffS: %s\n", log_id(st.ffS, "--"));
|
||||
#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) {
|
||||
log(" input A (%s) is too large (%d > 16).\n", log_signal(pm.st.sigA), GetSize(pm.st.sigA));
|
||||
if (GetSize(st.sigA) > 16) {
|
||||
log(" input A (%s) is too large (%d > 16).\n", log_signal(st.sigA), GetSize(st.sigA));
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetSize(pm.st.sigB) > 16) {
|
||||
log(" input B (%s) is too large (%d > 16).\n", log_signal(pm.st.sigB), GetSize(pm.st.sigB));
|
||||
if (GetSize(st.sigB) > 16) {
|
||||
log(" input B (%s) is too large (%d > 16).\n", log_signal(st.sigB), GetSize(st.sigB));
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetSize(pm.st.sigS) > 32) {
|
||||
log(" accumulator (%s) is too large (%d > 32).\n", log_signal(pm.st.sigS), GetSize(pm.st.sigS));
|
||||
if (GetSize(st.sigS) > 32) {
|
||||
log(" accumulator (%s) is too large (%d > 32).\n", log_signal(st.sigS), GetSize(st.sigS));
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetSize(pm.st.sigY) > 32) {
|
||||
log(" output (%s) is too large (%d > 32).\n", log_signal(pm.st.sigY), GetSize(pm.st.sigY));
|
||||
if (GetSize(st.sigY) > 32) {
|
||||
log(" output (%s) is too large (%d > 32).\n", log_signal(st.sigY), GetSize(st.sigY));
|
||||
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) {
|
||||
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");
|
||||
|
||||
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
|
||||
|
||||
SigSpec A = pm.st.sigA;
|
||||
SigSpec A = st.sigA;
|
||||
A.extend_u0(16, mul_signed);
|
||||
|
||||
SigSpec B = pm.st.sigB;
|
||||
SigSpec B = st.sigB;
|
||||
B.extend_u0(16, mul_signed);
|
||||
|
||||
SigSpec CD;
|
||||
if (pm.st.muxA)
|
||||
CD = pm.st.muxA->getPort("\\B");
|
||||
if (pm.st.muxB)
|
||||
CD = pm.st.muxB->getPort("\\A");
|
||||
if (st.muxA)
|
||||
CD = st.muxA->getPort("\\B");
|
||||
if (st.muxB)
|
||||
CD = st.muxB->getPort("\\A");
|
||||
CD.extend_u0(32, mul_signed);
|
||||
|
||||
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("\\D", CD.extract(16, 16));
|
||||
|
||||
cell->setParam("\\A_REG", pm.st.ffA ? State::S1 : State::S0);
|
||||
cell->setParam("\\B_REG", pm.st.ffB ? State::S1 : State::S0);
|
||||
cell->setParam("\\A_REG", st.ffA ? State::S1 : State::S0);
|
||||
cell->setParam("\\B_REG", st.ffB ? State::S1 : State::S0);
|
||||
|
||||
cell->setPort("\\AHOLD", 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("\\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->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)
|
||||
log(" ffA:%s", log_id(pm.st.ffA));
|
||||
if (st.ffA)
|
||||
log(" ffA:%s", log_id(st.ffA));
|
||||
|
||||
if (pm.st.ffB)
|
||||
log(" ffB:%s", log_id(pm.st.ffB));
|
||||
if (st.ffB)
|
||||
log(" ffB:%s", log_id(st.ffB));
|
||||
|
||||
if (pm.st.ffY)
|
||||
log(" ffY:%s", log_id(pm.st.ffY));
|
||||
if (st.ffY)
|
||||
log(" ffY:%s", log_id(st.ffY));
|
||||
|
||||
if (pm.st.ffS)
|
||||
log(" ffS:%s", log_id(pm.st.ffS));
|
||||
if (st.ffS)
|
||||
log(" ffS:%s", log_id(st.ffS));
|
||||
|
||||
log("\n");
|
||||
}
|
||||
|
@ -144,16 +147,16 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
|
|||
|
||||
// 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)
|
||||
O.append(pm.module->addWire(NEW_ID, 32-GetSize(O)));
|
||||
|
||||
cell->setPort("\\O", O);
|
||||
|
||||
if (pm.st.addAB) {
|
||||
log(" accumulator %s (%s)\n", log_id(pm.st.addAB), log_id(pm.st.addAB->type));
|
||||
cell->setPort("\\ADDSUBTOP", pm.st.addAB->type == "$add" ? State::S0 : State::S1);
|
||||
cell->setPort("\\ADDSUBBOT", pm.st.addAB->type == "$add" ? State::S0 : State::S1);
|
||||
if (st.addAB) {
|
||||
log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type));
|
||||
cell->setPort("\\ADDSUBTOP", st.addAB->type == "$add" ? State::S0 : State::S1);
|
||||
cell->setPort("\\ADDSUBBOT", st.addAB->type == "$add" ? State::S0 : State::S1);
|
||||
} else {
|
||||
cell->setPort("\\ADDSUBTOP", State::S0);
|
||||
cell->setPort("\\ADDSUBBOT", State::S0);
|
||||
|
@ -166,10 +169,10 @@ void create_ice40_dsp(ice40_dsp_pm &pm)
|
|||
cell->setPort("\\OHOLDBOT", State::S0);
|
||||
|
||||
SigSpec acc_reset = State::S0;
|
||||
if (pm.st.muxA)
|
||||
acc_reset = pm.st.muxA->getPort("\\S");
|
||||
if (pm.st.muxB)
|
||||
acc_reset = pm.module->Not(NEW_ID, pm.st.muxB->getPort("\\S"));
|
||||
if (st.muxA)
|
||||
acc_reset = st.muxA->getPort("\\S");
|
||||
if (st.muxB)
|
||||
acc_reset = pm.module->Not(NEW_ID, st.muxB->getPort("\\S"));
|
||||
|
||||
cell->setPort("\\OLOADTOP", 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("\\D_REG", State::S0);
|
||||
|
||||
cell->setParam("\\TOP_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0);
|
||||
cell->setParam("\\BOT_8x8_MULT_REG", pm.st.ffY ? State::S1 : State::S0);
|
||||
cell->setParam("\\PIPELINE_16x16_MULT_REG1", 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", 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("\\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_UPPERINPUT", State::S0);
|
||||
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_UPPERINPUT", State::S0);
|
||||
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("\\B_SIGNED", mul_signed ? State::S1 : State::S0);
|
||||
|
||||
pm.autoremove(pm.st.mul);
|
||||
pm.autoremove(pm.st.ffY);
|
||||
pm.autoremove(pm.st.ffS);
|
||||
pm.autoremove(st.mul);
|
||||
pm.autoremove(st.ffY);
|
||||
pm.autoremove(st.ffS);
|
||||
}
|
||||
|
||||
struct Ice40DspPass : public Pass {
|
||||
|
@ -230,7 +233,7 @@ struct Ice40DspPass : public Pass {
|
|||
extra_args(args, argidx, design);
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
pattern ice40_dsp
|
||||
|
||||
state <SigBit> clock
|
||||
state <bool> clock_pol clock_vld
|
||||
state <SigSpec> sigA sigB sigY sigS
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -3,15 +3,42 @@
|
|||
import re
|
||||
import sys
|
||||
import pprint
|
||||
import getopt
|
||||
|
||||
pp = pprint.PrettyPrinter(indent=4)
|
||||
|
||||
pmgfile = sys.argv[1]
|
||||
assert pmgfile.endswith(".pmg")
|
||||
prefix = pmgfile[0:-4]
|
||||
prefix = prefix.split('/')[-1]
|
||||
outfile = sys.argv[2]
|
||||
prefix = None
|
||||
pmgfiles = list()
|
||||
outfile = None
|
||||
debug = False
|
||||
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()
|
||||
udata_types = dict()
|
||||
blocks = list()
|
||||
|
@ -77,7 +104,8 @@ def rewrite_cpp(s):
|
|||
|
||||
return "".join(t)
|
||||
|
||||
with open(pmgfile, "r") as f:
|
||||
def process_pmgfile(f):
|
||||
global current_pattern
|
||||
while True:
|
||||
line = f.readline()
|
||||
if line == "": break
|
||||
|
@ -87,14 +115,31 @@ with open(pmgfile, "r") as f:
|
|||
if len(cmd) == 0 or cmd[0].startswith("//"): continue
|
||||
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":
|
||||
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
|
||||
type_str = m.group(1)
|
||||
states_str = m.group(2)
|
||||
for s in re.split(r"\s+", states_str):
|
||||
assert s not in state_types
|
||||
state_types[s] = type_str
|
||||
assert s not in state_types[current_pattern]
|
||||
state_types[current_pattern][s] = type_str
|
||||
continue
|
||||
|
||||
if cmd == "udata":
|
||||
|
@ -103,19 +148,20 @@ with open(pmgfile, "r") as f:
|
|||
type_str = m.group(1)
|
||||
udatas_str = m.group(2)
|
||||
for s in re.split(r"\s+", udatas_str):
|
||||
assert s not in udata_types
|
||||
udata_types[s] = type_str
|
||||
assert s not in udata_types[current_pattern]
|
||||
udata_types[current_pattern][s] = type_str
|
||||
continue
|
||||
|
||||
if cmd == "match":
|
||||
block = dict()
|
||||
block["type"] = "match"
|
||||
block["pattern"] = current_pattern
|
||||
|
||||
line = line.split()
|
||||
assert len(line) == 2
|
||||
assert line[1] not in state_types
|
||||
assert line[1] not in state_types[current_pattern]
|
||||
block["cell"] = line[1]
|
||||
state_types[line[1]] = "Cell*";
|
||||
state_types[current_pattern][line[1]] = "Cell*";
|
||||
|
||||
block["if"] = list()
|
||||
block["select"] = list()
|
||||
|
@ -158,15 +204,18 @@ with open(pmgfile, "r") as f:
|
|||
assert False
|
||||
|
||||
blocks.append(block)
|
||||
continue
|
||||
|
||||
if cmd == "code":
|
||||
block = dict()
|
||||
block["type"] = "code"
|
||||
block["pattern"] = current_pattern
|
||||
|
||||
block["code"] = list()
|
||||
block["states"] = set()
|
||||
|
||||
for s in line.split()[1:]:
|
||||
assert s in state_types
|
||||
assert s in state_types[current_pattern]
|
||||
block["states"].add(s)
|
||||
|
||||
while True:
|
||||
|
@ -179,17 +228,36 @@ with open(pmgfile, "r") as f:
|
|||
block["code"].append(rewrite_cpp(l.rstrip()))
|
||||
|
||||
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:
|
||||
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("#include \"kernel/yosys.h\"", file=f)
|
||||
print("#include \"kernel/sigtools.h\"", file=f)
|
||||
print("", file=f)
|
||||
|
||||
print("YOSYS_NAMESPACE_BEGIN", file=f)
|
||||
print("", file=f)
|
||||
if genhdr:
|
||||
print("#include \"kernel/yosys.h\"", file=f)
|
||||
print("#include \"kernel/sigtools.h\"", file=f)
|
||||
print("", file=f)
|
||||
print("YOSYS_NAMESPACE_BEGIN", file=f)
|
||||
print("", file=f)
|
||||
|
||||
print("struct {}_pm {{".format(prefix), file=f)
|
||||
print(" Module *module;", file=f)
|
||||
|
@ -212,17 +280,19 @@ with open(outfile, "w") as f:
|
|||
print(" int rollback;", file=f)
|
||||
print("", file=f)
|
||||
|
||||
print(" struct state_t {", file=f)
|
||||
for s, t in sorted(state_types.items()):
|
||||
print(" {} {};".format(t, s), file=f)
|
||||
print(" } st;", file=f)
|
||||
print("", file=f)
|
||||
for current_pattern in sorted(patterns.keys()):
|
||||
print(" struct state_{}_t {{".format(current_pattern), file=f)
|
||||
for s, t in sorted(state_types[current_pattern].items()):
|
||||
print(" {} {};".format(t, s), file=f)
|
||||
print(" }} st_{};".format(current_pattern), file=f)
|
||||
print("", file=f)
|
||||
|
||||
print(" struct udata_t {", file=f)
|
||||
for s, t in sorted(udata_types.items()):
|
||||
print(" {} {};".format(t, s), file=f)
|
||||
print(" } ud;", file=f)
|
||||
print("", file=f)
|
||||
print(" struct udata_{}_t {{".format(current_pattern), file=f)
|
||||
for s, t in sorted(udata_types[current_pattern].items()):
|
||||
print(" {} {};".format(t, s), file=f)
|
||||
print(" }} ud_{};".format(current_pattern), file=f)
|
||||
print("", file=f)
|
||||
current_pattern = None
|
||||
|
||||
for v, n in sorted(ids.items()):
|
||||
if n[0] == "\\":
|
||||
|
@ -258,20 +328,24 @@ with open(outfile, "w") as f:
|
|||
print(" }", file=f)
|
||||
print("", file=f)
|
||||
|
||||
print(" void check_blacklist() {", file=f)
|
||||
print(" if (!blacklist_dirty)", file=f)
|
||||
print(" return;", file=f)
|
||||
print(" blacklist_dirty = false;", file=f)
|
||||
for index in range(len(blocks)):
|
||||
block = blocks[index]
|
||||
if block["type"] == "match":
|
||||
print(" if (st.{} != nullptr && blacklist_cells.count(st.{})) {{".format(block["cell"], block["cell"]), file=f)
|
||||
print(" rollback = {};".format(index+1), file=f)
|
||||
print(" return;", file=f)
|
||||
print(" }", file=f)
|
||||
print(" rollback = 0;", file=f)
|
||||
print(" }", file=f)
|
||||
print("", file=f)
|
||||
for current_pattern in sorted(patterns.keys()):
|
||||
print(" void check_blacklist_{}() {{".format(current_pattern), file=f)
|
||||
print(" if (!blacklist_dirty)", file=f)
|
||||
print(" return;", file=f)
|
||||
print(" blacklist_dirty = false;", file=f)
|
||||
for index in range(len(blocks)):
|
||||
block = blocks[index]
|
||||
if block["pattern"] != current_pattern:
|
||||
continue
|
||||
if block["type"] == "match":
|
||||
print(" if (st_{}.{} != nullptr && blacklist_cells.count(st_{}.{})) {{".format(current_pattern, block["cell"], current_pattern, block["cell"]), file=f)
|
||||
print(" rollback = {};".format(index+1), file=f)
|
||||
print(" return;", 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(" 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(" module(module), sigmap(module) {", file=f)
|
||||
for s, t in sorted(udata_types.items()):
|
||||
if t.endswith("*"):
|
||||
print(" ud.{} = nullptr;".format(s), file=f)
|
||||
else:
|
||||
print(" ud.{} = {}();".format(s, t), file=f)
|
||||
for current_pattern in sorted(patterns.keys()):
|
||||
for s, t in sorted(udata_types[current_pattern].items()):
|
||||
if t.endswith("*"):
|
||||
print(" ud_{}.{} = nullptr;".format(current_pattern,s), 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 &conn : cell->connections())", 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(" void run(std::function<void()> on_accept_f) {", file=f)
|
||||
print(" on_accept = on_accept_f;", file=f)
|
||||
print(" rollback = 0;", file=f)
|
||||
print(" blacklist_dirty = false;", file=f)
|
||||
for s, t in sorted(state_types.items()):
|
||||
if t.endswith("*"):
|
||||
print(" st.{} = nullptr;".format(s), file=f)
|
||||
else:
|
||||
print(" st.{} = {}();".format(s, t), file=f)
|
||||
print(" block_0();", file=f)
|
||||
print(" }", file=f)
|
||||
print("", file=f)
|
||||
|
||||
print(" void run(std::function<void({}_pm&)> on_accept_f) {{".format(prefix), file=f)
|
||||
print(" run([&](){on_accept_f(*this);});", file=f)
|
||||
print(" }", file=f)
|
||||
print("", file=f)
|
||||
for current_pattern in sorted(patterns.keys()):
|
||||
print(" void run_{}(std::function<void()> on_accept_f) {{".format(current_pattern), file=f)
|
||||
print(" on_accept = on_accept_f;", file=f)
|
||||
print(" rollback = 0;", file=f)
|
||||
print(" blacklist_dirty = false;", file=f)
|
||||
for s, t in sorted(state_types[current_pattern].items()):
|
||||
if t.endswith("*"):
|
||||
print(" st_{}.{} = nullptr;".format(current_pattern, s), file=f)
|
||||
else:
|
||||
print(" st_{}.{} = {}();".format(current_pattern, s, t), file=f)
|
||||
print(" block_{}();".format(patterns[current_pattern]), file=f)
|
||||
print(" }", file=f)
|
||||
print("", file=f)
|
||||
print(" void run_{}(std::function<void({}_pm&)> on_accept_f) {{".format(current_pattern, prefix), file=f)
|
||||
print(" run_{}([&](){{on_accept_f(*this);}});".format(current_pattern), 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)):
|
||||
block = blocks[index]
|
||||
|
||||
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()
|
||||
nonconst_st = set()
|
||||
restore_st = set()
|
||||
|
||||
for i in range(index):
|
||||
for i in range(patterns[current_pattern], index):
|
||||
if blocks[i]["type"] == "code":
|
||||
for s in blocks[i]["states"]:
|
||||
const_st.add(s)
|
||||
|
@ -378,27 +472,27 @@ with open(outfile, "w") as f:
|
|||
assert False
|
||||
|
||||
for s in sorted(const_st):
|
||||
t = state_types[s]
|
||||
t = state_types[current_pattern][s]
|
||||
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:
|
||||
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):
|
||||
t = state_types[s]
|
||||
print(" {} &{} YS_ATTRIBUTE(unused) = st.{};".format(t, s, s), file=f)
|
||||
t = state_types[current_pattern][s]
|
||||
print(" {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f)
|
||||
|
||||
if len(restore_st):
|
||||
print("", file=f)
|
||||
for s in sorted(restore_st):
|
||||
t = state_types[s]
|
||||
t = state_types[current_pattern][s]
|
||||
print(" {} backup_{} = {};".format(t, s, s), file=f)
|
||||
|
||||
if block["type"] == "code":
|
||||
print("", file=f)
|
||||
print(" do {", file=f)
|
||||
print("#define reject do { check_blacklist(); goto rollback_label; } while(0)", file=f)
|
||||
print("#define accept do { on_accept(); check_blacklist(); if (rollback) 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)".format(current_pattern), file=f)
|
||||
print("#define branch do {{ block_{}(); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f)
|
||||
|
||||
for line in block["code"]:
|
||||
|
@ -417,11 +511,11 @@ with open(outfile, "w") as f:
|
|||
if len(restore_st) or len(nonconst_st):
|
||||
print("", file=f)
|
||||
for s in sorted(restore_st):
|
||||
t = state_types[s]
|
||||
t = state_types[current_pattern][s]
|
||||
print(" {} = backup_{};".format(s, s), file=f)
|
||||
for s in sorted(nonconst_st):
|
||||
if s not in restore_st:
|
||||
t = state_types[s]
|
||||
t = state_types[current_pattern][s]
|
||||
if t.endswith("*"):
|
||||
print(" {} = nullptr;".format(s), file=f)
|
||||
else:
|
||||
|
@ -470,17 +564,12 @@ with open(outfile, "w") as f:
|
|||
else:
|
||||
assert False
|
||||
|
||||
|
||||
current_pattern = None
|
||||
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("YOSYS_NAMESPACE_END", file=f)
|
||||
|
||||
# pp.pprint(blocks)
|
||||
if genhdr:
|
||||
print("", file=f)
|
||||
print("YOSYS_NAMESPACE_END", file=f)
|
||||
|
|
|
@ -508,7 +508,7 @@ struct ExposePass : public Pass {
|
|||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -26,6 +26,8 @@ PRIVATE_NAMESPACE_BEGIN
|
|||
|
||||
struct opts_t
|
||||
{
|
||||
bool initeq = false;
|
||||
bool anyeq = false;
|
||||
bool fwd = false;
|
||||
bool bwd = false;
|
||||
bool nop = false;
|
||||
|
@ -56,7 +58,7 @@ struct FmcombineWorker
|
|||
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);
|
||||
c->parameters = cell->parameters;
|
||||
|
@ -64,6 +66,8 @@ struct FmcombineWorker
|
|||
|
||||
for (auto &conn : cell->connections())
|
||||
c->setPort(conn.first, import_sig(conn.second, suffix));
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void import_hier_cell(Cell *cell)
|
||||
|
@ -102,8 +106,24 @@ struct FmcombineWorker
|
|||
|
||||
for (auto cell : original->cells()) {
|
||||
if (design->module(cell->type) == nullptr) {
|
||||
import_prim_cell(cell, "_gold");
|
||||
import_prim_cell(cell, "_gate");
|
||||
if (opts.anyeq && cell->type.in("$anyseq", "$anyconst")) {
|
||||
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 {
|
||||
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("a slight difference in input causes in a module.\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(" Insert forward hint assumptions into the combined module.\n");
|
||||
log("\n");
|
||||
|
@ -261,6 +288,14 @@ struct FmcombinePass : public Pass {
|
|||
// filename = args[++argidx];
|
||||
// continue;
|
||||
// }
|
||||
if (args[argidx] == "-initeq") {
|
||||
opts.initeq = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-anyeq") {
|
||||
opts.anyeq = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-fwd") {
|
||||
opts.fwd = true;
|
||||
continue;
|
||||
|
|
|
@ -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 abc_sname = abc_name.substr(1);
|
||||
if (abc_sname.substr(0, 5) == "ys__n") {
|
||||
bool inv = abc_sname.back() == 'v';
|
||||
if (inv) abc_sname.pop_back();
|
||||
bool isnew = false;
|
||||
if (abc_sname.substr(0, 4) == "new_")
|
||||
{
|
||||
abc_sname.erase(0, 4);
|
||||
isnew = true;
|
||||
}
|
||||
if (abc_sname.substr(0, 5) == "ys__n")
|
||||
{
|
||||
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);
|
||||
for (auto sig : signal_list) {
|
||||
if (sig.id == sid && sig.bit.wire != nullptr) {
|
||||
size_t postfix_start = abc_sname.find_first_not_of("0123456789");
|
||||
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;
|
||||
sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1);
|
||||
if (sig.bit.wire->width != 1)
|
||||
sstr << "[" << sig.bit.offset << "]";
|
||||
if (inv)
|
||||
sstr << "_inv";
|
||||
if (isnew)
|
||||
sstr << "_new";
|
||||
sstr << postfix;
|
||||
if (orig_wire != nullptr)
|
||||
*orig_wire = sig.bit.wire;
|
||||
return sstr.str();
|
||||
|
|
|
@ -102,7 +102,8 @@ struct DffinitPass : public Pass {
|
|||
if (wire->attributes.count("\\init")) {
|
||||
Const value = wire->attributes.at("\\init");
|
||||
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)
|
||||
for (auto bit : sigmap(wire))
|
||||
|
|
|
@ -397,7 +397,6 @@ struct FlowGraph
|
|||
pool<RTLIL::SigBit> x, xi;
|
||||
|
||||
NodePrime source_prime = {source, true};
|
||||
NodePrime sink_prime = {sink, false};
|
||||
pool<NodePrime> visited;
|
||||
vector<NodePrime> worklist = {source_prime};
|
||||
while (!worklist.empty())
|
||||
|
@ -1382,7 +1381,8 @@ struct FlowmapWorker
|
|||
|
||||
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));
|
||||
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();
|
||||
for (size_t n = 0; n < input_nodes.size(); n++)
|
||||
|
|
|
@ -94,7 +94,7 @@ int LibertyParser::lexer(std::string &str)
|
|||
|
||||
// search for identifiers, numbers, plus or minus.
|
||||
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) {
|
||||
c = f.get();
|
||||
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.')
|
||||
|
|
|
@ -46,7 +46,7 @@ struct ZinitPass : public Pass {
|
|||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
{
|
||||
if (args[argidx] == "-singleton") {
|
||||
if (args[argidx] == "-all") {
|
||||
all_mode = true;
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
input A, EN;
|
||||
|
@ -1863,4 +2038,5 @@ end
|
|||
endmodule
|
||||
|
||||
`endif
|
||||
|
||||
// --------------------------------------------------------
|
||||
|
|
|
@ -201,6 +201,8 @@ struct SynthPass : public ScriptPass
|
|||
run("check");
|
||||
run("opt");
|
||||
run("wreduce");
|
||||
run("peepopt");
|
||||
run("opt_clean");
|
||||
if (help_mode)
|
||||
run("techmap -map +/cmp2lut.v", " (if -lut)");
|
||||
else
|
||||
|
|
|
@ -930,10 +930,21 @@ endmodule
|
|||
|
||||
(* blackbox *)
|
||||
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 CLKHFEN,
|
||||
output CLKHF
|
||||
);
|
||||
parameter TRIM_EN = "0b0";
|
||||
parameter CLKHF_DIV = "0b00";
|
||||
endmodule
|
||||
|
||||
|
|
|
@ -241,6 +241,8 @@ struct SynthIce40Pass : public ScriptPass
|
|||
run("check");
|
||||
run("opt");
|
||||
run("wreduce");
|
||||
run("peepopt");
|
||||
run("opt_clean");
|
||||
run("share");
|
||||
run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4");
|
||||
run("opt_expr");
|
||||
|
|
|
@ -17,254 +17,243 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/celltypes.h"
|
||||
#include "kernel/rtlil.h"
|
||||
#include "kernel/log.h"
|
||||
#include "kernel/register.h"
|
||||
#include "kernel/rtlil.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
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
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" synth_intel [options]\n");
|
||||
log("\n");
|
||||
log("This command runs synthesis for Intel FPGAs.\n");
|
||||
log("\n");
|
||||
log(" -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>\n");
|
||||
log(" generate the synthesis netlist for the specified family.\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(" Cyclone V and Arria 10 GX devices are experimental, use it with a10gx argument.\n");
|
||||
log("\n");
|
||||
log(" -top <module>\n");
|
||||
log(" use the specified module as top module (default='top')\n");
|
||||
log("\n");
|
||||
log(" -vqm <file>\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("\n");
|
||||
log(" -vpr <file>\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(" output file is omitted if this parameter is not specified.\n");
|
||||
log("\n");
|
||||
log(" -run <from_label>:<to_label>\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(" synonymous to the end of the command list.\n");
|
||||
log("\n");
|
||||
log(" -noiopads\n");
|
||||
log(" do not use altsyncram cells in output netlist\n");
|
||||
log("\n");
|
||||
log(" -nobram\n");
|
||||
log(" do not use altsyncram cells in output netlist\n");
|
||||
log("\n");
|
||||
log(" -noflatten\n");
|
||||
log(" do not flatten design before synthesis\n");
|
||||
log("\n");
|
||||
log(" -retime\n");
|
||||
log(" run 'abc' with -dff option\n");
|
||||
log("\n");
|
||||
log("The following commands are executed by this synthesis command:\n");
|
||||
help_script();
|
||||
log("\n");
|
||||
}
|
||||
void help() YS_OVERRIDE
|
||||
{
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
log("\n");
|
||||
log(" synth_intel [options]\n");
|
||||
log("\n");
|
||||
log("This command runs synthesis for Intel FPGAs.\n");
|
||||
log("\n");
|
||||
log(" -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>\n");
|
||||
log(" generate the synthesis netlist for the specified family.\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(" Cyclone V and Arria 10 GX devices are experimental, use it with a10gx argument.\n");
|
||||
log("\n");
|
||||
log(" -top <module>\n");
|
||||
log(" use the specified module as top module (default='top')\n");
|
||||
log("\n");
|
||||
log(" -vqm <file>\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("\n");
|
||||
log(" -vpr <file>\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(" output file is omitted if this parameter is not specified.\n");
|
||||
log("\n");
|
||||
log(" -run <from_label>:<to_label>\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(" synonymous to the end of the command list.\n");
|
||||
log("\n");
|
||||
log(" -noiopads\n");
|
||||
log(" do not use altsyncram cells in output netlist\n");
|
||||
log("\n");
|
||||
log(" -nobram\n");
|
||||
log(" do not use altsyncram cells in output netlist\n");
|
||||
log("\n");
|
||||
log(" -noflatten\n");
|
||||
log(" do not flatten design before synthesis\n");
|
||||
log("\n");
|
||||
log(" -retime\n");
|
||||
log(" run 'abc' with -dff option\n");
|
||||
log("\n");
|
||||
log("The following commands are executed by this synthesis command:\n");
|
||||
help_script();
|
||||
log("\n");
|
||||
}
|
||||
|
||||
string top_opt, family_opt, vout_file, blif_file;
|
||||
bool retime, flatten, nobram, noiopads;
|
||||
string top_opt, family_opt, vout_file, blif_file;
|
||||
bool retime, flatten, nobram, noiopads;
|
||||
|
||||
void clear_flags() YS_OVERRIDE
|
||||
{
|
||||
top_opt = "-auto-top";
|
||||
family_opt = "max10";
|
||||
vout_file = "";
|
||||
blif_file = "";
|
||||
retime = false;
|
||||
flatten = true;
|
||||
nobram = false;
|
||||
noiopads = false;
|
||||
}
|
||||
void clear_flags() YS_OVERRIDE
|
||||
{
|
||||
top_opt = "-auto-top";
|
||||
family_opt = "max10";
|
||||
vout_file = "";
|
||||
blif_file = "";
|
||||
retime = false;
|
||||
flatten = true;
|
||||
nobram = false;
|
||||
noiopads = false;
|
||||
}
|
||||
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
string run_from, run_to;
|
||||
clear_flags();
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
|
||||
{
|
||||
string run_from, run_to;
|
||||
clear_flags();
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++)
|
||||
{
|
||||
if (args[argidx] == "-family" && argidx+1 < args.size()) {
|
||||
family_opt = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-top" && argidx+1 < args.size()) {
|
||||
top_opt = "-top " + args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-vqm" && argidx+1 < args.size()) {
|
||||
vout_file = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-vpr" && argidx+1 < args.size()) {
|
||||
blif_file = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-run" && argidx+1 < args.size()) {
|
||||
size_t pos = args[argidx+1].find(':');
|
||||
if (pos == std::string::npos)
|
||||
break;
|
||||
run_from = args[++argidx].substr(0, pos);
|
||||
run_to = args[argidx].substr(pos+1);
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-noiopads") {
|
||||
noiopads = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nobram") {
|
||||
nobram = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-noflatten") {
|
||||
flatten = false;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-retime") {
|
||||
retime = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||
if (args[argidx] == "-family" && argidx + 1 < args.size()) {
|
||||
family_opt = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-top" && argidx + 1 < args.size()) {
|
||||
top_opt = "-top " + args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-vqm" && argidx + 1 < args.size()) {
|
||||
vout_file = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-vpr" && argidx + 1 < args.size()) {
|
||||
blif_file = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-run" && argidx + 1 < args.size()) {
|
||||
size_t pos = args[argidx + 1].find(':');
|
||||
if (pos == std::string::npos)
|
||||
break;
|
||||
run_from = args[++argidx].substr(0, pos);
|
||||
run_to = args[argidx].substr(pos + 1);
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-noiopads") {
|
||||
noiopads = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-nobram") {
|
||||
nobram = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-noflatten") {
|
||||
flatten = false;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-retime") {
|
||||
retime = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
if (!design->full_selection())
|
||||
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")
|
||||
log_cmd_error("Invalid or not family specified: '%s'\n", family_opt.c_str());
|
||||
if (!design->full_selection())
|
||||
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")
|
||||
log_cmd_error("Invalid or not family specified: '%s'\n", family_opt.c_str());
|
||||
|
||||
log_header(design, "Executing SYNTH_INTEL pass.\n");
|
||||
log_push();
|
||||
log_header(design, "Executing SYNTH_INTEL pass.\n");
|
||||
log_push();
|
||||
|
||||
run_script(design, run_from, run_to);
|
||||
run_script(design, run_from, run_to);
|
||||
|
||||
log_pop();
|
||||
}
|
||||
log_pop();
|
||||
}
|
||||
|
||||
void script() YS_OVERRIDE
|
||||
{
|
||||
if (check_label("begin"))
|
||||
{
|
||||
if(check_label("family") && family_opt=="max10")
|
||||
run("read_verilog -sv -lib +/intel/max10/cells_sim.v");
|
||||
else if(check_label("family") && family_opt=="a10gx")
|
||||
run("read_verilog -sv -lib +/intel/a10gx/cells_sim.v");
|
||||
else if(check_label("family") && family_opt=="cyclonev")
|
||||
run("read_verilog -sv -lib +/intel/cyclonev/cells_sim.v");
|
||||
else if(check_label("family") && family_opt=="cyclone10")
|
||||
run("read_verilog -sv -lib +/intel/cyclone10/cells_sim.v");
|
||||
else if(check_label("family") && family_opt=="cycloneiv")
|
||||
run("read_verilog -sv -lib +/intel/cycloneiv/cells_sim.v");
|
||||
else
|
||||
run("read_verilog -sv -lib +/intel/cycloneive/cells_sim.v");
|
||||
// Misc and common cells
|
||||
run("read_verilog -sv -lib +/intel/common/m9k_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()));
|
||||
}
|
||||
void script() YS_OVERRIDE
|
||||
{
|
||||
if (check_label("begin")) {
|
||||
if (check_label("family") && family_opt == "max10")
|
||||
run("read_verilog -sv -lib +/intel/max10/cells_sim.v");
|
||||
else if (check_label("family") && family_opt == "a10gx")
|
||||
run("read_verilog -sv -lib +/intel/a10gx/cells_sim.v");
|
||||
else if (check_label("family") && family_opt == "cyclonev")
|
||||
run("read_verilog -sv -lib +/intel/cyclonev/cells_sim.v");
|
||||
else if (check_label("family") && family_opt == "cyclone10")
|
||||
run("read_verilog -sv -lib +/intel/cyclone10/cells_sim.v");
|
||||
else if (check_label("family") && family_opt == "cycloneiv")
|
||||
run("read_verilog -sv -lib +/intel/cycloneiv/cells_sim.v");
|
||||
else
|
||||
run("read_verilog -sv -lib +/intel/cycloneive/cells_sim.v");
|
||||
// Misc and common cells
|
||||
run("read_verilog -sv -lib +/intel/common/m9k_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()));
|
||||
}
|
||||
|
||||
if (flatten && check_label("flatten", "(unless -noflatten)"))
|
||||
{
|
||||
run("proc");
|
||||
run("flatten");
|
||||
run("tribuf -logic");
|
||||
run("deminout");
|
||||
}
|
||||
if (flatten && check_label("flatten", "(unless -noflatten)")) {
|
||||
run("proc");
|
||||
run("flatten");
|
||||
run("tribuf -logic");
|
||||
run("deminout");
|
||||
}
|
||||
|
||||
if (check_label("coarse"))
|
||||
{
|
||||
run("synth -run coarse");
|
||||
}
|
||||
if (check_label("coarse")) {
|
||||
run("synth -run coarse");
|
||||
}
|
||||
|
||||
if (!nobram && check_label("bram", "(skip if -nobram)"))
|
||||
{
|
||||
run("memory_bram -rules +/intel/common/brams.txt");
|
||||
run("techmap -map +/intel/common/brams_map.v");
|
||||
}
|
||||
if (!nobram && check_label("bram", "(skip if -nobram)")) {
|
||||
run("memory_bram -rules +/intel/common/brams.txt");
|
||||
run("techmap -map +/intel/common/brams_map.v");
|
||||
}
|
||||
|
||||
if (check_label("fine"))
|
||||
{
|
||||
run("opt -fast -mux_undef -undriven -fine -full");
|
||||
run("memory_map");
|
||||
run("opt -undriven -fine");
|
||||
run("dffsr2dff");
|
||||
run("dff2dffe -direct-match $_DFF_*");
|
||||
run("opt -fine");
|
||||
run("techmap -map +/techmap.v");
|
||||
run("opt -full");
|
||||
run("clean -purge");
|
||||
run("setundef -undriven -zero");
|
||||
if (retime || help_mode)
|
||||
run("abc -markgroups -dff", "(only if -retime)");
|
||||
}
|
||||
if (check_label("fine")) {
|
||||
run("opt -fast -mux_undef -undriven -fine -full");
|
||||
run("memory_map");
|
||||
run("opt -undriven -fine");
|
||||
run("dffsr2dff");
|
||||
run("dff2dffe -direct-match $_DFF_*");
|
||||
run("opt -fine");
|
||||
run("techmap -map +/techmap.v");
|
||||
run("opt -full");
|
||||
run("clean -purge");
|
||||
run("setundef -undriven -zero");
|
||||
if (retime || help_mode)
|
||||
run("abc -markgroups -dff", "(only if -retime)");
|
||||
}
|
||||
|
||||
if (check_label("map_luts"))
|
||||
{
|
||||
if(family_opt=="a10gx" || family_opt=="cyclonev")
|
||||
run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : ""));
|
||||
else
|
||||
run("abc -lut 4" + string(retime ? " -dff" : ""));
|
||||
run("clean");
|
||||
}
|
||||
if (check_label("map_luts")) {
|
||||
if (family_opt == "a10gx" || family_opt == "cyclonev")
|
||||
run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : ""));
|
||||
else
|
||||
run("abc -lut 4" + string(retime ? " -dff" : ""));
|
||||
run("clean");
|
||||
}
|
||||
|
||||
if (check_label("map_cells"))
|
||||
{
|
||||
if (!noiopads)
|
||||
run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)");
|
||||
if(family_opt=="max10")
|
||||
run("techmap -map +/intel/max10/cells_map.v");
|
||||
else if(family_opt=="a10gx")
|
||||
run("techmap -map +/intel/a10gx/cells_map.v");
|
||||
else if(family_opt=="cyclonev")
|
||||
run("techmap -map +/intel/cyclonev/cells_map.v");
|
||||
else if(family_opt=="cyclone10")
|
||||
run("techmap -map +/intel/cyclone10/cells_map.v");
|
||||
else if(family_opt=="cycloneiv")
|
||||
run("techmap -map +/intel/cycloneiv/cells_map.v");
|
||||
else
|
||||
run("techmap -map +/intel/cycloneive/cells_map.v");
|
||||
run("dffinit -highlow -ff dffeas q power_up");
|
||||
run("clean -purge");
|
||||
}
|
||||
if (check_label("map_cells")) {
|
||||
if (!noiopads)
|
||||
run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)");
|
||||
if (family_opt == "max10")
|
||||
run("techmap -map +/intel/max10/cells_map.v");
|
||||
else if (family_opt == "a10gx")
|
||||
run("techmap -map +/intel/a10gx/cells_map.v");
|
||||
else if (family_opt == "cyclonev")
|
||||
run("techmap -map +/intel/cyclonev/cells_map.v");
|
||||
else if (family_opt == "cyclone10")
|
||||
run("techmap -map +/intel/cyclone10/cells_map.v");
|
||||
else if (family_opt == "cycloneiv")
|
||||
run("techmap -map +/intel/cycloneiv/cells_map.v");
|
||||
else
|
||||
run("techmap -map +/intel/cycloneive/cells_map.v");
|
||||
run("dffinit -highlow -ff dffeas q power_up");
|
||||
run("clean -purge");
|
||||
}
|
||||
|
||||
if (check_label("check"))
|
||||
{
|
||||
run("hierarchy -check");
|
||||
run("stat");
|
||||
run("check -noinit");
|
||||
}
|
||||
if (check_label("check")) {
|
||||
run("hierarchy -check");
|
||||
run("stat");
|
||||
run("check -noinit");
|
||||
}
|
||||
|
||||
if (check_label("vqm"))
|
||||
{
|
||||
if (!vout_file.empty() || help_mode)
|
||||
run(stringf("write_verilog -attr2comment -defparam -nohex -decimal -renameprefix syn_ %s",
|
||||
help_mode ? "<file-name>" : vout_file.c_str()));
|
||||
}
|
||||
if (check_label("vqm")) {
|
||||
if (!vout_file.empty() || help_mode)
|
||||
run(stringf("write_verilog -attr2comment -defparam -nohex -decimal -renameprefix syn_ %s",
|
||||
help_mode ? "<file-name>" : vout_file.c_str()));
|
||||
}
|
||||
|
||||
if (check_label("vpr"))
|
||||
{
|
||||
if (!blif_file.empty() || help_mode)
|
||||
{
|
||||
run(stringf("opt_clean -purge"));
|
||||
run(stringf("write_blif %s", help_mode ? "<file-name>" : blif_file.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (check_label("vpr")) {
|
||||
if (!blif_file.empty() || help_mode) {
|
||||
run(stringf("opt_clean -purge"));
|
||||
run(stringf("write_blif %s", help_mode ? "<file-name>" : blif_file.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
} SynthIntelPass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
||||
|
|
|
@ -18,12 +18,14 @@
|
|||
*/
|
||||
|
||||
// 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
|
||||
module \$_DFF_PN0_ (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
|
||||
|
||||
module \$_DFF_NN1_ (input D, C, R, output Q); \$_DFF_NP1 _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_NN0_" *)
|
||||
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 _90_dff_pn0_to_pp0 (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
|
||||
(* techmap_celltype = "$_DFF_NN1_" *)
|
||||
module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
|
||||
(* 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);
|
||||
parameter DEPTH = 0;
|
||||
|
|
|
@ -42,6 +42,10 @@ struct SynthXilinxPass : public ScriptPass
|
|||
log(" -top <module>\n");
|
||||
log(" use the specified module as top module\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(" write the design to the specified edif file. writing of an output file\n");
|
||||
log(" is omitted if this parameter is not specified.\n");
|
||||
|
@ -80,7 +84,7 @@ struct SynthXilinxPass : public ScriptPass
|
|||
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;
|
||||
|
||||
void clear_flags() YS_OVERRIDE
|
||||
|
@ -94,6 +98,7 @@ struct SynthXilinxPass : public ScriptPass
|
|||
nobram = false;
|
||||
nodram = false;
|
||||
nosrl = false;
|
||||
arch = "xc7";
|
||||
}
|
||||
|
||||
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];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-arch" && argidx+1 < args.size()) {
|
||||
arch = args[++argidx];
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-edif" && argidx+1 < args.size()) {
|
||||
edif_file = args[++argidx];
|
||||
continue;
|
||||
|
@ -152,6 +161,9 @@ struct SynthXilinxPass : public ScriptPass
|
|||
}
|
||||
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())
|
||||
log_cmd_error("This command only operates on fully selected designs!\n");
|
||||
|
||||
|
@ -257,7 +269,7 @@ struct SynthXilinxPass : public ScriptPass
|
|||
|
||||
if (check_label("check")) {
|
||||
run("hierarchy -check");
|
||||
run("stat");
|
||||
run("stat -tech xilinx");
|
||||
run("check -noinit");
|
||||
}
|
||||
|
||||
|
|
|
@ -40,3 +40,15 @@ module dff1a_test(n1, n1_inv, clk);
|
|||
n1 <= n1_inv;
|
||||
assign n1_inv = ~n1;
|
||||
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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -92,3 +92,25 @@ module mem2reg_test5(input ctrl, output out);
|
|||
assign out = bar[foo[0]];
|
||||
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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -11,13 +11,13 @@ echo "" > $STDERRFILE
|
|||
|
||||
echo -n "Test: ${TESTNAME} -> "
|
||||
|
||||
$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}.sv ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_syn.v" >> $STDOUTFILE >> $STDERRFILE
|
||||
$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}_ref.v ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_ref_syn.v" >> $STDOUTFILE >> $STDERRFILE
|
||||
set -e
|
||||
|
||||
$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
|
||||
|
||||
set -e
|
||||
|
||||
iverilog -g2012 ${TESTNAME}_syn.v
|
||||
iverilog -g2012 ${TESTNAME}_ref_syn.v
|
||||
|
||||
|
|
|
@ -147,7 +147,8 @@ do
|
|||
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 \
|
||||
"$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
|
||||
|
||||
test_count=0
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue