mirror of https://github.com/YosysHQ/yosys.git
Compare commits
29 Commits
a9138f6015
...
1b30680beb
Author | SHA1 | Date |
---|---|---|
George Rennie | 1b30680beb | |
KrystalDelusion | 6f3376cbe6 | |
github-actions[bot] | 87742fa688 | |
Martin Povišer | 646c5a19a8 | |
Martin Povišer | 1717a0b9c0 | |
Martin Povišer | 956313efe8 | |
Martin Povišer | 3bab837bc9 | |
KrystalDelusion | 698c464109 | |
KrystalDelusion | f428163252 | |
KrystalDelusion | 1e0e367aed | |
KrystalDelusion | 6ff5823d6a | |
George Rennie | 8148ebd1ad | |
George Rennie | 4a057b3c44 | |
George Rennie | 33d5138673 | |
George Rennie | c6e8fb2432 | |
George Rennie | c352f71fc0 | |
George Rennie | 73ba5da10f | |
George Rennie | cbe86afd5c | |
George Rennie | ab293d667e | |
George Rennie | 6b3901e435 | |
George Rennie | 88816ccc45 | |
George Rennie | 70646da6bb | |
George Rennie | bdc978380c | |
Krystine Sherwin | e649c1a8e1 | |
Krystine Sherwin | 44b68fb498 | |
N. Engelhardt | 96c526d1ba | |
Krystine Sherwin | 1476eaba00 | |
Larry Doolittle | 3ae9ca7c2b | |
Larry Doolittle | d36a387aca |
|
@ -32,9 +32,9 @@ jobs:
|
|||
# oldest supported
|
||||
- 'clang-14'
|
||||
- 'gcc-10'
|
||||
# newest
|
||||
- 'clang'
|
||||
- 'gcc'
|
||||
# newest, make sure to update maximum standard step to match
|
||||
- 'clang-18'
|
||||
- 'gcc-13'
|
||||
include:
|
||||
# macOS
|
||||
- os: macos-13
|
||||
|
@ -72,7 +72,7 @@ jobs:
|
|||
|
||||
# maximum standard, only on newest compilers
|
||||
- name: Build C++20
|
||||
if: ${{ matrix.compiler == 'clang' || matrix.compiler == 'gcc'}}
|
||||
if: ${{ matrix.compiler == 'clang-18' || matrix.compiler == 'gcc-13' }}
|
||||
shell: bash
|
||||
run: |
|
||||
make config-$CC_SHORT
|
||||
|
|
2
Makefile
2
Makefile
|
@ -155,7 +155,7 @@ ifeq ($(OS), Haiku)
|
|||
CXXFLAGS += -D_DEFAULT_SOURCE
|
||||
endif
|
||||
|
||||
YOSYS_VER := 0.47+121
|
||||
YOSYS_VER := 0.47+135
|
||||
|
||||
# Note: We arrange for .gitcommit to contain the (short) commit hash in
|
||||
# tarballs generated with git-archive(1) using .gitattributes. The git repo
|
||||
|
|
|
@ -28,8 +28,8 @@
|
|||
USING_YOSYS_NAMESPACE
|
||||
PRIVATE_NAMESPACE_BEGIN
|
||||
|
||||
#define BITWISE_OPS ID($buf), ID($not), ID($mux), ID($and), ID($or), ID($xor), ID($xnor), ID($fa), \
|
||||
ID($bwmux)
|
||||
#define BITWISE_OPS ID($buf), ID($barrier), ID($not), ID($mux), ID($and), ID($or), ID($xor), ID($xnor), \
|
||||
ID($fa), ID($bwmux)
|
||||
|
||||
#define REDUCE_OPS ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool)
|
||||
|
||||
|
@ -331,7 +331,7 @@ struct Index {
|
|||
a = CFALSE;
|
||||
}
|
||||
|
||||
if (cell->type.in(ID($buf), ID($pos), ID($_BUF_))) {
|
||||
if (cell->type.in(ID($buf), ID($barrier), ID($pos), ID($_BUF_))) {
|
||||
return a;
|
||||
} else if (cell->type.in(ID($not), ID($_NOT_))) {
|
||||
return NOT(a);
|
||||
|
|
|
@ -508,7 +508,7 @@ struct BtorWorker
|
|||
goto okay;
|
||||
}
|
||||
|
||||
if (cell->type.in(ID($not), ID($neg), ID($_NOT_), ID($pos)))
|
||||
if (cell->type.in(ID($not), ID($neg), ID($_NOT_), ID($pos), ID($buf), ID($_BUF_), ID($barrier)))
|
||||
{
|
||||
string btor_op;
|
||||
if (cell->type.in(ID($not), ID($_NOT_))) btor_op = "not";
|
||||
|
@ -520,9 +520,9 @@ struct BtorWorker
|
|||
int nid_a = get_sig_nid(cell->getPort(ID::A), width, a_signed);
|
||||
SigSpec sig = sigmap(cell->getPort(ID::Y));
|
||||
|
||||
// the $pos cell just passes through, all other cells need an actual operation applied
|
||||
// buffer cells just pass through, all other cells need an actual operation applied
|
||||
int nid = nid_a;
|
||||
if (cell->type != ID($pos))
|
||||
if (!cell->type.in(ID($pos), ID($buf), ID($_BUF_), ID($barrier)))
|
||||
{
|
||||
log_assert(!btor_op.empty());
|
||||
int sid = get_bv_sid(width);
|
||||
|
|
|
@ -966,7 +966,7 @@ struct FirrtlWorker
|
|||
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
|
||||
continue;
|
||||
}
|
||||
if (cell->type == ID($pos)) {
|
||||
if (cell->type.in(ID($pos), ID($buf), ID($barrier))) {
|
||||
// assign y = a;
|
||||
// printCell(cell);
|
||||
string a_expr = make_expr(cell->getPort(ID::A));
|
||||
|
|
|
@ -677,7 +677,7 @@ struct Smt2Worker
|
|||
if (cell->type == ID($eqx)) return export_bvop(cell, "(= A B)", 'b');
|
||||
|
||||
if (cell->type == ID($not)) return export_bvop(cell, "(bvnot A)");
|
||||
if (cell->type == ID($pos)) return export_bvop(cell, "A");
|
||||
if (cell->type.in(ID($pos), ID($buf), ID($barrier))) return export_bvop(cell, "A");
|
||||
if (cell->type == ID($neg)) return export_bvop(cell, "(bvneg A)");
|
||||
|
||||
if (cell->type == ID($add)) return export_bvop(cell, "(bvadd A B)");
|
||||
|
|
|
@ -1071,7 +1071,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (cell->type == ID($_BUF_)) {
|
||||
if (cell->type.in(ID($buf), ID($_BUF_), ID($barrier))) {
|
||||
f << stringf("%s" "assign ", indent.c_str());
|
||||
dump_sigspec(f, cell->getPort(ID::Y));
|
||||
f << stringf(" = ");
|
||||
|
|
|
@ -242,7 +242,7 @@ Processes
|
|||
|
||||
Declares a process, with zero or more attributes, with the given identifier in
|
||||
the enclosing module. The body of a process consists of zero or more
|
||||
assignments, exactly one switch, and zero or more syncs.
|
||||
assignments followed by zero or more switches and zero or more syncs.
|
||||
|
||||
See :ref:`sec:rtlil_process` for an overview of processes.
|
||||
|
||||
|
@ -250,7 +250,7 @@ See :ref:`sec:rtlil_process` for an overview of processes.
|
|||
|
||||
<process> ::= <attr-stmt>* <proc-stmt> <process-body> <proc-end-stmt>
|
||||
<proc-stmt> ::= process <id> <eol>
|
||||
<process-body> ::= <assign-stmt>* <switch>? <assign-stmt>* <sync>*
|
||||
<process-body> ::= <assign-stmt>* <switch>* <sync>*
|
||||
<assign-stmt> ::= assign <dest-sigspec> <src-sigspec> <eol>
|
||||
<dest-sigspec> ::= <sigspec>
|
||||
<src-sigspec> ::= <sigspec>
|
||||
|
@ -262,8 +262,8 @@ Switches
|
|||
Switches test a signal for equality against a list of cases. Each case specifies
|
||||
a comma-separated list of signals to check against. If there are no signals in
|
||||
the list, then the case is the default case. The body of a case consists of zero
|
||||
or more switches and assignments. Both switches and cases may have zero or more
|
||||
attributes.
|
||||
or more assignments followed by zero or more switches. Both switches and cases
|
||||
may have zero or more attributes.
|
||||
|
||||
.. code:: BNF
|
||||
|
||||
|
@ -272,7 +272,7 @@ attributes.
|
|||
<case> ::= <attr-stmt>* <case-stmt> <case-body>
|
||||
<case-stmt> ::= case <compare>? <eol>
|
||||
<compare> ::= <sigspec> (, <sigspec>)*
|
||||
<case-body> ::= (<switch> | <assign-stmt>)*
|
||||
<case-body> ::= <assign-stmt>* <switch>*
|
||||
<switch-end-stmt> ::= end <eol>
|
||||
|
||||
Syncs
|
||||
|
|
|
@ -56,6 +56,9 @@ if os.getenv("READTHEDOCS"):
|
|||
else:
|
||||
release = yosys_ver
|
||||
todo_include_todos = False
|
||||
elif os.getenv("YOSYS_DOCS_RELEASE") is not None:
|
||||
release = yosys_ver
|
||||
todo_include_todos = False
|
||||
else:
|
||||
release = yosys_ver
|
||||
todo_include_todos = True
|
||||
|
@ -87,5 +90,9 @@ def setup(app: Sphinx) -> None:
|
|||
from util.RtlilLexer import RtlilLexer
|
||||
app.add_lexer("RTLIL", RtlilLexer)
|
||||
|
||||
from furo_ys.lexers.YoscryptLexer import YoscryptLexer
|
||||
app.add_lexer("yoscrypt", YoscryptLexer)
|
||||
try:
|
||||
from furo_ys.lexers.YoscryptLexer import YoscryptLexer
|
||||
app.add_lexer("yoscrypt", YoscryptLexer)
|
||||
except ModuleNotFoundError:
|
||||
from pygments.lexers.special import TextLexer
|
||||
app.add_lexer("yoscrypt", TextLexer)
|
||||
|
|
|
@ -31,6 +31,11 @@ void rtlil_frontend_yyerror(char const *s)
|
|||
YOSYS_NAMESPACE_PREFIX log_error("Parser error in line %d: %s\n", rtlil_frontend_yyget_lineno(), s);
|
||||
}
|
||||
|
||||
void rtlil_frontend_yywarning(char const *s)
|
||||
{
|
||||
YOSYS_NAMESPACE_PREFIX log_warning("In line %d: %s\n", rtlil_frontend_yyget_lineno(), s);
|
||||
}
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
struct RTLILFrontend : public Frontend {
|
||||
|
|
|
@ -42,6 +42,7 @@ YOSYS_NAMESPACE_END
|
|||
extern int rtlil_frontend_yydebug;
|
||||
int rtlil_frontend_yylex(void);
|
||||
void rtlil_frontend_yyerror(char const *s);
|
||||
void rtlil_frontend_yywarning(char const *s);
|
||||
void rtlil_frontend_yyrestart(FILE *f);
|
||||
int rtlil_frontend_yyparse(void);
|
||||
int rtlil_frontend_yylex_destroy(void);
|
||||
|
|
|
@ -344,6 +344,16 @@ assign_stmt:
|
|||
TOK_ASSIGN sigspec sigspec EOL {
|
||||
if (attrbuf.size() != 0)
|
||||
rtlil_frontend_yyerror("dangling attribute");
|
||||
|
||||
// See https://github.com/YosysHQ/yosys/pull/4765 for discussion on this
|
||||
// warning
|
||||
if (!switch_stack.back()->empty()) {
|
||||
rtlil_frontend_yywarning(
|
||||
"case rule assign statements after switch statements may cause unexpected behaviour. "
|
||||
"The assign statement is reordered to come before all switch statements."
|
||||
);
|
||||
}
|
||||
|
||||
case_stack.back()->actions.push_back(RTLIL::SigSig(*$2, *$3));
|
||||
delete $2;
|
||||
delete $3;
|
||||
|
|
|
@ -290,7 +290,7 @@ Aig::Aig(Cell *cell)
|
|||
}
|
||||
}
|
||||
|
||||
if (cell->type.in(ID($not), ID($_NOT_), ID($pos), ID($buf), ID($_BUF_)))
|
||||
if (cell->type.in(ID($not), ID($_NOT_), ID($pos), ID($buf), ID($barrier), ID($_BUF_)))
|
||||
{
|
||||
for (int i = 0; i < GetSize(cell->getPort(ID::Y)); i++) {
|
||||
int A = mk.inport(ID::A, i);
|
||||
|
|
|
@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN
|
|||
|
||||
void bitwise_unary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell)
|
||||
{
|
||||
bool is_signed = (cell->type != ID($buf)) && cell->getParam(ID::A_SIGNED).as_bool();
|
||||
bool is_signed = !cell->type.in(ID($buf), ID($barrier)) && cell->getParam(ID::A_SIGNED).as_bool();
|
||||
int a_width = GetSize(cell->getPort(ID::A));
|
||||
int y_width = GetSize(cell->getPort(ID::Y));
|
||||
|
||||
|
@ -392,7 +392,7 @@ PRIVATE_NAMESPACE_END
|
|||
|
||||
bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL::Cell *cell)
|
||||
{
|
||||
if (cell->type.in(ID($not), ID($pos), ID($buf))) {
|
||||
if (cell->type.in(ID($not), ID($pos), ID($buf), ID($barrier))) {
|
||||
bitwise_unary_op(this, cell);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -87,6 +87,8 @@ struct CellTypes
|
|||
{
|
||||
setup_internals_eval();
|
||||
|
||||
setup_type(ID($barrier), {ID::A}, {ID::Y});
|
||||
|
||||
setup_type(ID($tribuf), {ID::A, ID::EN}, {ID::Y}, true);
|
||||
|
||||
setup_type(ID($assert), {ID::A, ID::EN}, pool<RTLIL::IdString>(), true);
|
||||
|
|
|
@ -364,7 +364,7 @@ public:
|
|||
|
||||
unsigned int hash() const
|
||||
{
|
||||
unsigned int inner;
|
||||
unsigned int inner = 0;
|
||||
switch (type_)
|
||||
{
|
||||
case DriveType::NONE:
|
||||
|
@ -385,6 +385,9 @@ public:
|
|||
case DriveType::MULTIPLE:
|
||||
inner = multiple_.hash();
|
||||
break;
|
||||
default:
|
||||
log_abort();
|
||||
break;
|
||||
}
|
||||
return mkhash((unsigned int)type_, inner);
|
||||
}
|
||||
|
@ -912,7 +915,7 @@ public:
|
|||
|
||||
unsigned int hash() const
|
||||
{
|
||||
unsigned int inner;
|
||||
unsigned int inner = 0;
|
||||
switch (type_)
|
||||
{
|
||||
case DriveType::NONE:
|
||||
|
@ -933,6 +936,9 @@ public:
|
|||
case DriveType::MULTIPLE:
|
||||
inner = multiple_.hash();
|
||||
break;
|
||||
default:
|
||||
log_abort();
|
||||
break;
|
||||
}
|
||||
return mkhash((unsigned int)type_, inner);
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ void QuickConeSat::prepare()
|
|||
|
||||
int QuickConeSat::cell_complexity(RTLIL::Cell *cell)
|
||||
{
|
||||
if (cell->type.in(ID($concat), ID($slice), ID($pos), ID($buf), ID($_BUF_)))
|
||||
if (cell->type.in(ID($concat), ID($slice), ID($pos), ID($buf), ID($barrier), ID($_BUF_)))
|
||||
return 0;
|
||||
if (cell->type.in(ID($not), ID($and), ID($or), ID($xor), ID($xnor),
|
||||
ID($reduce_and), ID($reduce_or), ID($reduce_xor),
|
||||
|
|
|
@ -1340,7 +1340,7 @@ namespace {
|
|||
cell->type.begins_with("$verific$") || cell->type.begins_with("$array:") || cell->type.begins_with("$extern:"))
|
||||
return;
|
||||
|
||||
if (cell->type == ID($buf)) {
|
||||
if (cell->type.in(ID($buf), ID($barrier))) {
|
||||
port(ID::A, param(ID::WIDTH));
|
||||
port(ID::Y, param(ID::WIDTH));
|
||||
check_expected();
|
||||
|
@ -2746,7 +2746,8 @@ DEF_METHOD(LogicNot, 1, ID($logic_not))
|
|||
add ## _func(name, sig_a, sig_y, is_signed, src); \
|
||||
return sig_y; \
|
||||
}
|
||||
DEF_METHOD(Buf, sig_a.size(), ID($buf))
|
||||
DEF_METHOD(Buf, sig_a.size(), ID($buf))
|
||||
DEF_METHOD(Barrier, sig_a.size(), ID($barrier))
|
||||
#undef DEF_METHOD
|
||||
|
||||
#define DEF_METHOD(_func, _y_size, _type) \
|
||||
|
@ -4048,9 +4049,9 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
|
|||
type.begins_with("$verific$") || type.begins_with("$array:") || type.begins_with("$extern:"))
|
||||
return;
|
||||
|
||||
if (type == ID($buf) || type == ID($mux) || type == ID($pmux) || type == ID($bmux)) {
|
||||
if (type.in(ID($buf), ID($barrier), ID($mux), ID($pmux), ID($bmux))) {
|
||||
parameters[ID::WIDTH] = GetSize(connections_[ID::Y]);
|
||||
if (type != ID($buf) && type != ID($mux))
|
||||
if (!type.in(ID($buf), ID($barrier), ID($mux)))
|
||||
parameters[ID::S_WIDTH] = GetSize(connections_[ID::S]);
|
||||
check();
|
||||
return;
|
||||
|
|
|
@ -814,6 +814,7 @@ struct RTLIL::AttrObject
|
|||
void set_bool_attribute(const RTLIL::IdString &id, bool value=true);
|
||||
bool get_bool_attribute(const RTLIL::IdString &id) const;
|
||||
|
||||
[[deprecated("Use Module::get_blackbox_attribute() instead.")]]
|
||||
bool get_blackbox_attribute(bool ignore_wb=false) const {
|
||||
return get_bool_attribute(ID::blackbox) || (!ignore_wb && get_bool_attribute(ID::whitebox));
|
||||
}
|
||||
|
@ -1291,6 +1292,10 @@ public:
|
|||
virtual void optimize();
|
||||
virtual void makeblackbox();
|
||||
|
||||
bool get_blackbox_attribute(bool ignore_wb=false) const {
|
||||
return get_bool_attribute(ID::blackbox) || (!ignore_wb && get_bool_attribute(ID::whitebox));
|
||||
}
|
||||
|
||||
void connect(const RTLIL::SigSig &conn);
|
||||
void connect(const RTLIL::SigSpec &lhs, const RTLIL::SigSpec &rhs);
|
||||
void new_connections(const std::vector<RTLIL::SigSig> &new_conn);
|
||||
|
@ -1371,10 +1376,11 @@ public:
|
|||
|
||||
// The add* methods create a cell and return the created cell. All signals must exist in advance.
|
||||
|
||||
RTLIL::Cell* addNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
|
||||
RTLIL::Cell* addPos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
|
||||
RTLIL::Cell* addBuf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
|
||||
RTLIL::Cell* addNeg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
|
||||
RTLIL::Cell* addNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
|
||||
RTLIL::Cell* addPos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
|
||||
RTLIL::Cell* addBuf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
|
||||
RTLIL::Cell* addBarrier (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
|
||||
RTLIL::Cell* addNeg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
|
||||
|
||||
RTLIL::Cell* addAnd (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
|
||||
RTLIL::Cell* addOr (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = "");
|
||||
|
@ -1506,10 +1512,11 @@ public:
|
|||
|
||||
// The methods without the add* prefix create a cell and an output signal. They return the newly created output signal.
|
||||
|
||||
RTLIL::SigSpec Not (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
||||
RTLIL::SigSpec Pos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
||||
RTLIL::SigSpec Buf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
||||
RTLIL::SigSpec Neg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
||||
RTLIL::SigSpec Not (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
||||
RTLIL::SigSpec Pos (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
||||
RTLIL::SigSpec Buf (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
||||
RTLIL::SigSpec Barrier (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
||||
RTLIL::SigSpec Neg (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, bool is_signed = false, const std::string &src = "");
|
||||
|
||||
RTLIL::SigSpec And (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
|
||||
RTLIL::SigSpec Or (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, bool is_signed = false, const std::string &src = "");
|
||||
|
|
|
@ -430,7 +430,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (cell->type.in(ID($pos), ID($buf), ID($neg)))
|
||||
if (cell->type.in(ID($pos), ID($buf), ID($barrier), ID($neg)))
|
||||
{
|
||||
std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep);
|
||||
std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep);
|
||||
|
@ -438,7 +438,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
|
|||
|
||||
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
|
||||
|
||||
if (cell->type.in(ID($pos), ID($buf))) {
|
||||
if (cell->type.in(ID($pos), ID($buf), ID($barrier))) {
|
||||
ez->assume(ez->vec_eq(a, yy));
|
||||
} else {
|
||||
std::vector<int> zero(a.size(), ez->CONST_FALSE);
|
||||
|
@ -451,7 +451,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
|
|||
std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep);
|
||||
extendSignalWidthUnary(undef_a, undef_y, cell);
|
||||
|
||||
if (cell->type.in(ID($pos), ID($buf))) {
|
||||
if (cell->type.in(ID($pos), ID($buf), ID($barrier))) {
|
||||
ez->assume(ez->vec_eq(undef_a, undef_y));
|
||||
} else {
|
||||
int undef_any_a = ez->expression(ezSAT::OpOr, undef_a);
|
||||
|
|
|
@ -51,3 +51,4 @@ OBJS += passes/cmds/future.o
|
|||
OBJS += passes/cmds/box_derive.o
|
||||
OBJS += passes/cmds/example_dt.o
|
||||
OBJS += passes/cmds/portarcs.o
|
||||
OBJS += passes/cmds/optbarriers.o
|
||||
|
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2024 George Rennie <georgrennie@gmail.com>
|
||||
*
|
||||
* 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
|
||||
|
||||
// Standard visitor helper
|
||||
template<class... Ts>
|
||||
struct overloaded : Ts... { using Ts::operator()...; };
|
||||
template<class... Ts>
|
||||
overloaded(Ts...) -> overloaded<Ts...>;
|
||||
|
||||
struct OptBarriersPass : public Pass {
|
||||
OptBarriersPass() : Pass("optbarriers", "insert optimization barriers") {}
|
||||
|
||||
void help() override {
|
||||
log("\n");
|
||||
log(" optbarriers [options] [selection]\n");
|
||||
log("\n");
|
||||
log("Insert optimization barriers to drivers of selected public wires.\n");
|
||||
log("\n");
|
||||
log("\n");
|
||||
log(" -nocells\n");
|
||||
log(" don't add optimization barriers to the outputs of cells\n");
|
||||
log("\n");
|
||||
log(" -noprocs\n");
|
||||
log(" don't add optimization barriers to the outputs of processes\n");
|
||||
log("\n");
|
||||
log(" -private\n");
|
||||
log(" also add optimization barriers to private wires\n");
|
||||
log("\n");
|
||||
log(" -remove\n");
|
||||
log(" replace selected optimization barriers with connections\n");
|
||||
log("\n");
|
||||
}
|
||||
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override {
|
||||
log_header(design, "Executing OPTBARRIERS pass (insert optimization barriers).\n");
|
||||
|
||||
bool nocells_mode = false;
|
||||
bool noprocs_mode = false;
|
||||
bool private_mode = false;
|
||||
bool remove_mode = false;
|
||||
|
||||
size_t argidx;
|
||||
for (argidx = 1; argidx < args.size(); argidx++) {
|
||||
std::string arg = args[argidx];
|
||||
if (arg == "-nocells") {
|
||||
nocells_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-noprocs") {
|
||||
noprocs_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-private") {
|
||||
private_mode = true;
|
||||
continue;
|
||||
}
|
||||
if (arg == "-remove") {
|
||||
remove_mode = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
||||
if (remove_mode) {
|
||||
log("Replacing optimization barriers with connections.\n");
|
||||
remove_barriers(design);
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto* module : design->selected_modules()) {
|
||||
// We can't just sigmap and iterate through wires for rewriting as
|
||||
// we want to maintain the structure in connections, and sigmap
|
||||
// will just return a canonical wire which does not have to be one
|
||||
// that is directly driving the wire. Therefore for each type of
|
||||
// object that could be driving the wires (cells, processes,
|
||||
// connections) we rewrite the sigspecs.
|
||||
|
||||
// Keep track of which wires we have allocated new wires for
|
||||
dict<RTLIL::Wire*, RTLIL::Wire*> new_wires;
|
||||
// Keep track of bit pairs we need to construct barriers for from
|
||||
// Y to A
|
||||
dict<RTLIL::SigBit, RTLIL::SigBit> new_barriers;
|
||||
|
||||
// Skip constants, unselected wires and private wires when not in
|
||||
// private mode. This works for SigChunk or SigBit input.
|
||||
const auto skip = [&](const auto& chunk) {
|
||||
if (!chunk.is_wire())
|
||||
return true;
|
||||
|
||||
if (!design->selected(module, chunk.wire))
|
||||
return true;
|
||||
|
||||
if (!private_mode && !chunk.wire->name.isPublic())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
const auto rewrite_sigspec = [&](const SigSpec& sig) {
|
||||
RTLIL::SigSpec new_output;
|
||||
for (const auto& chunk : sig.chunks()) {
|
||||
if (skip(chunk)) {
|
||||
new_output.append(chunk);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add a wire to drive if one does not already exist
|
||||
auto* new_wire = new_wires.at(chunk.wire, nullptr);
|
||||
if (!new_wire) {
|
||||
new_wire = module->addWire(NEW_ID, GetSize(chunk.wire));
|
||||
new_wires.emplace(chunk.wire, new_wire);
|
||||
}
|
||||
|
||||
RTLIL::SigChunk new_chunk = chunk;
|
||||
new_chunk.wire = new_wire;
|
||||
|
||||
// Rewrite output to drive new wire, and schedule adding
|
||||
// barrier bits from new wire to original
|
||||
new_output.append(new_chunk);
|
||||
for (int i = 0; i < GetSize(chunk); i++)
|
||||
new_barriers.emplace(chunk[i], new_chunk[i]);
|
||||
}
|
||||
|
||||
return new_output;
|
||||
};
|
||||
|
||||
// Rewrite cell outputs
|
||||
if (!nocells_mode)
|
||||
for (auto* cell : module->cells())
|
||||
if (cell->type != ID($barrier))
|
||||
for (const auto& [name, sig] : cell->connections())
|
||||
if (cell->output(name))
|
||||
cell->setPort(name, rewrite_sigspec(sig));
|
||||
|
||||
// Rewrite connections in processes
|
||||
if (!noprocs_mode) {
|
||||
const auto proc_rewriter = overloaded{
|
||||
// Don't do anything for input sigspecs
|
||||
[&](const SigSpec&) {},
|
||||
// Rewrite connections to drive barrier if needed
|
||||
[&](SigSpec& lhs, const SigSpec&) {
|
||||
lhs = rewrite_sigspec(lhs);
|
||||
}
|
||||
};
|
||||
|
||||
for (auto& proc : module->processes)
|
||||
proc.second->rewrite_sigspecs2(proc_rewriter);
|
||||
}
|
||||
|
||||
// Add all the scheduled barriers. To minimize the number of cells,
|
||||
// first construct a sigspec of all bits, then sort and unify before
|
||||
// creating barriers
|
||||
SigSpec barrier_y;
|
||||
for (const auto&[y_bit, _] : new_barriers)
|
||||
barrier_y.append(y_bit);
|
||||
barrier_y.sort_and_unify();
|
||||
|
||||
for (const auto& sig_y : barrier_y.chunks()) {
|
||||
log_assert(sig_y.is_wire());
|
||||
SigSpec sig_a;
|
||||
for (int i = 0; i < GetSize(sig_y); i++)
|
||||
sig_a.append(new_barriers[sig_y[i]]);
|
||||
module->addBarrier(NEW_ID, sig_a, sig_y);
|
||||
}
|
||||
|
||||
// Rewrite connections
|
||||
std::vector<RTLIL::SigSig> new_connections;
|
||||
for (const auto& conn : module->connections()) {
|
||||
RTLIL::SigSig skip_conn, barrier_conn;
|
||||
|
||||
for (int i = 0; i < GetSize(conn.first); i++) {
|
||||
auto& sigsig = skip(conn.first[i]) ? skip_conn : barrier_conn;
|
||||
sigsig.first.append(conn.first[i]);
|
||||
sigsig.second.append(conn.second[i]);
|
||||
}
|
||||
|
||||
if (!skip_conn.first.empty())
|
||||
new_connections.emplace_back(std::move(skip_conn));
|
||||
|
||||
if (!barrier_conn.first.empty())
|
||||
module->addBarrier(NEW_ID, barrier_conn.second, barrier_conn.first);
|
||||
}
|
||||
module->new_connections(new_connections);
|
||||
}
|
||||
}
|
||||
|
||||
void remove_barriers(RTLIL::Design* design) {
|
||||
for (auto* module : design->selected_modules()) {
|
||||
std::vector<RTLIL::Cell*> barriers;
|
||||
|
||||
for (auto* cell : module->selected_cells())
|
||||
if (cell->type == ID($barrier))
|
||||
barriers.emplace_back(cell);
|
||||
|
||||
for (auto* cell : barriers) {
|
||||
const auto lhs = cell->getPort(ID::Y), rhs = cell->getPort(ID::A);
|
||||
module->connect(lhs, rhs);
|
||||
module->remove(cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} OptBarriersPass;
|
||||
|
||||
PRIVATE_NAMESPACE_END
|
|
@ -1003,8 +1003,10 @@ struct HierarchyPass : public Pass {
|
|||
|
||||
if (top_mod == nullptr)
|
||||
for (auto mod : design->modules())
|
||||
if (mod->get_bool_attribute(ID::top))
|
||||
if (mod->get_bool_attribute(ID::top)) {
|
||||
log("Attribute `top' found on module `%s'. Setting top module to %s.\n", log_id(mod), log_id(mod));
|
||||
top_mod = mod;
|
||||
}
|
||||
|
||||
if (top_mod == nullptr)
|
||||
{
|
||||
|
|
|
@ -245,6 +245,7 @@ struct OptMergeWorker
|
|||
ct.cell_types.erase(ID($anyconst));
|
||||
ct.cell_types.erase(ID($allseq));
|
||||
ct.cell_types.erase(ID($allconst));
|
||||
ct.cell_types.erase(ID($barrier));
|
||||
|
||||
log("Finding identical cells in module `%s'.\n", module->name.c_str());
|
||||
assign_map.set(module);
|
||||
|
|
|
@ -60,6 +60,7 @@ struct FlattenWorker
|
|||
bool ignore_wb = false;
|
||||
bool create_scopeinfo = true;
|
||||
bool create_scopename = false;
|
||||
bool barriers = false;
|
||||
|
||||
template<class T>
|
||||
void map_attributes(RTLIL::Cell *cell, T *object, IdString orig_object_name)
|
||||
|
@ -246,7 +247,27 @@ struct FlattenWorker
|
|||
log_error("Cell port %s.%s.%s is driving constant bits: %s <= %s\n",
|
||||
log_id(module), log_id(cell), log_id(port_it.first), log_signal(new_conn.first), log_signal(new_conn.second));
|
||||
|
||||
module->connect(new_conn);
|
||||
if (barriers) {
|
||||
// Drive public output wires with barriers and the rest with
|
||||
// connections
|
||||
RTLIL::SigSig skip_conn, barrier_conn;
|
||||
|
||||
for (int i = 0; i < GetSize(new_conn.first); i++) {
|
||||
const auto lhs = new_conn.first[i], rhs = new_conn.second[i];
|
||||
auto& sigsig = !lhs.is_wire() || !lhs.wire->name.isPublic() ? skip_conn : barrier_conn;
|
||||
sigsig.first.append(lhs);
|
||||
sigsig.second.append(rhs);
|
||||
}
|
||||
|
||||
if (!skip_conn.first.empty())
|
||||
module->connect(skip_conn);
|
||||
|
||||
if (!barrier_conn.first.empty())
|
||||
module->addBarrier(NEW_ID, barrier_conn.second, barrier_conn.first);
|
||||
} else {
|
||||
module->connect(new_conn);
|
||||
}
|
||||
|
||||
sigmap.add(new_conn.first, new_conn.second);
|
||||
}
|
||||
|
||||
|
@ -345,6 +366,10 @@ struct FlattenPass : public Pass {
|
|||
log(" with a public name the enclosing scope can be found via their\n");
|
||||
log(" 'hdlname' attribute.\n");
|
||||
log("\n");
|
||||
log(" -barriers\n");
|
||||
log(" Use $barrier cells to connect flattened modules to their surrounding\n");
|
||||
log(" scope instead of connections for public wires.\n");
|
||||
log("\n");
|
||||
}
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
{
|
||||
|
@ -367,6 +392,10 @@ struct FlattenPass : public Pass {
|
|||
worker.create_scopename = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-barriers") {
|
||||
worker.barriers = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
|
|
@ -67,6 +67,11 @@ struct PrepPass : public ScriptPass
|
|||
log(" -nokeepdc\n");
|
||||
log(" do not call opt_* with -keepdc\n");
|
||||
log("\n");
|
||||
log(" -barriers\n");
|
||||
log(" add optimization barriers to all public wires to preserve their structure.\n");
|
||||
log(" this limits the optimizations that can be applied to the design to only\n");
|
||||
log(" those involving private wires.\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");
|
||||
|
@ -79,7 +84,7 @@ struct PrepPass : public ScriptPass
|
|||
}
|
||||
|
||||
string top_module, fsm_opts;
|
||||
bool autotop, flatten, ifxmode, memxmode, nomemmode, nokeepdc, rdff;
|
||||
bool autotop, flatten, ifxmode, memxmode, nomemmode, nokeepdc, rdff, barriers;
|
||||
|
||||
void clear_flags() override
|
||||
{
|
||||
|
@ -92,6 +97,7 @@ struct PrepPass : public ScriptPass
|
|||
nomemmode = false;
|
||||
nokeepdc = false;
|
||||
rdff = false;
|
||||
barriers = false;
|
||||
}
|
||||
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override
|
||||
|
@ -148,6 +154,10 @@ struct PrepPass : public ScriptPass
|
|||
nokeepdc = true;
|
||||
continue;
|
||||
}
|
||||
if (args[argidx] == "-barriers") {
|
||||
barriers = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
extra_args(args, argidx, design);
|
||||
|
@ -183,12 +193,16 @@ struct PrepPass : public ScriptPass
|
|||
|
||||
if (check_label("coarse"))
|
||||
{
|
||||
if (help_mode || barriers)
|
||||
run("optbarriers", "(if -barriers)");
|
||||
if (help_mode)
|
||||
run("proc [-ifx]");
|
||||
else
|
||||
run(ifxmode ? "proc -ifx" : "proc");
|
||||
if (help_mode || flatten)
|
||||
run("flatten", "(if -flatten)");
|
||||
if (help_mode)
|
||||
run("flatten [-barriers]", "(if -flatten)");
|
||||
else if (flatten)
|
||||
run(barriers ? "flatten -barriers" : "flatten");
|
||||
run("future");
|
||||
run(nokeepdc ? "opt_expr" : "opt_expr -keepdc");
|
||||
run("opt_clean");
|
||||
|
|
|
@ -108,6 +108,29 @@ endmodule
|
|||
|
||||
// --------------------------------------------------------
|
||||
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
//-
|
||||
//- $barrier (A, Y)
|
||||
//* group unary
|
||||
//-
|
||||
//- A coarse-grain buffer cell type that acts as a barrier for optimizations.
|
||||
//- Optimization passes are forbidden from rewriting patterns that include
|
||||
//- this cell (by merging, constant propagation etc) with the exception of
|
||||
//- opt_clean that can remove it if the output is unused.
|
||||
//-
|
||||
module \$barrier (A, Y);
|
||||
|
||||
parameter WIDTH = 0;
|
||||
|
||||
input [WIDTH-1:0] A;
|
||||
output [WIDTH-1:0] Y;
|
||||
|
||||
assign Y = A;
|
||||
|
||||
endmodule
|
||||
|
||||
// --------------------------------------------------------
|
||||
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
//-
|
||||
//- $neg (A, Y)
|
||||
|
|
Loading…
Reference in New Issue