From 4edb1a19210b9b3118d7b0072e13a4363f81fb94 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Tue, 5 Sep 2023 22:19:28 -0400 Subject: [PATCH 01/95] sv: support assignments within expressions - Add support for assignments within expressions, e.g., `x[y++] = z;` or `x = (y *= 2) - 1;`. The logic is handled entirely within the parser by injecting statements into the current procedural block. - Add support for pre-increment/decrement statements, which are behaviorally equivalent to post-increment/decrement statements. - Fix non-standard attribute position used for post-increment/decrement statements. --- CHANGELOG | 4 + README.md | 2 + frontends/verilog/verilog_parser.y | 113 ++++++++++++++++++++------ tests/verilog/asgn_expr.sv | 60 ++++++++++++++ tests/verilog/asgn_expr.ys | 3 + tests/verilog/asgn_expr_not_proc_1.ys | 7 ++ tests/verilog/asgn_expr_not_proc_2.ys | 7 ++ tests/verilog/asgn_expr_not_proc_3.ys | 7 ++ tests/verilog/asgn_expr_not_proc_4.ys | 7 ++ tests/verilog/asgn_expr_not_proc_5.ys | 7 ++ tests/verilog/asgn_expr_not_sv_1.ys | 7 ++ tests/verilog/asgn_expr_not_sv_2.ys | 7 ++ tests/verilog/asgn_expr_not_sv_3.ys | 7 ++ tests/verilog/asgn_expr_not_sv_4.ys | 15 ++++ tests/verilog/task_attr.ys | 2 +- 15 files changed, 231 insertions(+), 24 deletions(-) create mode 100644 tests/verilog/asgn_expr.sv create mode 100644 tests/verilog/asgn_expr.ys create mode 100644 tests/verilog/asgn_expr_not_proc_1.ys create mode 100644 tests/verilog/asgn_expr_not_proc_2.ys create mode 100644 tests/verilog/asgn_expr_not_proc_3.ys create mode 100644 tests/verilog/asgn_expr_not_proc_4.ys create mode 100644 tests/verilog/asgn_expr_not_proc_5.ys create mode 100644 tests/verilog/asgn_expr_not_sv_1.ys create mode 100644 tests/verilog/asgn_expr_not_sv_2.ys create mode 100644 tests/verilog/asgn_expr_not_sv_3.ys create mode 100644 tests/verilog/asgn_expr_not_sv_4.ys diff --git a/CHANGELOG b/CHANGELOG index 465918a36..a662ba4da 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,10 @@ List of major changes and improvements between releases Yosys 0.33 .. Yosys 0.34-dev -------------------------- + * SystemVerilog + - Added support for assignments within expressions, e.g., `x[y++] = z;` or + `x = (y *= 2) - 1;`. + Yosys 0.32 .. Yosys 0.33 -------------------------- * Various diff --git a/README.md b/README.md index 5e5a8ec3e..69a227b7f 100644 --- a/README.md +++ b/README.md @@ -592,6 +592,8 @@ from SystemVerilog: - SystemVerilog interfaces (SVIs) are supported. Modports for specifying whether ports are inputs or outputs are supported. +- Assignments within expressions are supported. + Building the documentation ========================== diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 1e82940bb..d901b3b55 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -292,6 +292,61 @@ static void rewriteGenForDeclInit(AstNode *loop) substitute(incr); } +static void ensureAsgnExprAllowed() +{ + if (!sv_mode) + frontend_verilog_yyerror("Assignments within expressions are only supported in SystemVerilog mode."); + if (ast_stack.back()->type != AST_BLOCK) + frontend_verilog_yyerror("Assignments within expressions are only permitted within procedures."); +} + +// add a pre/post-increment/decrement statement +static const AstNode *addIncOrDecStmt(AstNode *lhs, dict *attr, AST::AstNodeType op, YYLTYPE begin, YYLTYPE end) +{ + AstNode *one = AstNode::mkconst_int(1, true); + AstNode *rhs = new AstNode(op, lhs->clone(), one); + AstNode *stmt = new AstNode(AST_ASSIGN_EQ, lhs, rhs); + SET_AST_NODE_LOC(stmt, begin, end); + if (attr != nullptr) + append_attr(stmt, attr); + ast_stack.back()->children.push_back(stmt); + return stmt; +} + +// create a pre/post-increment/decrement expression, and add the corresponding statement +static AstNode *addIncOrDecExpr(AstNode *lhs, dict *attr, AST::AstNodeType op, YYLTYPE begin, YYLTYPE end, bool undo) +{ + ensureAsgnExprAllowed(); + const AstNode *stmt = addIncOrDecStmt(lhs, attr, op, begin, end); + log_assert(stmt->type == AST_ASSIGN_EQ); + AstNode *expr = stmt->children[0]->clone(); + if (undo) { + AstNode *minus_one = AstNode::mkconst_int(-1, true); + expr = new AstNode(op, expr, minus_one); + } + SET_AST_NODE_LOC(expr, begin, end); + return expr; +} + +// add a binary operator assignment statement, e.g., a += b +static const AstNode *addAsgnBinopStmt(dict *attr, AstNode *lhs, AST::AstNodeType op, AstNode *rhs, YYLTYPE begin, YYLTYPE end) +{ + SET_AST_NODE_LOC(rhs, end, end); + if (op == AST_SHIFT_LEFT || op == AST_SHIFT_RIGHT || + op == AST_SHIFT_SLEFT || op == AST_SHIFT_SRIGHT) { + rhs = new AstNode(AST_TO_UNSIGNED, rhs); + SET_AST_NODE_LOC(rhs, end, end); + } + rhs = new AstNode(op, lhs->clone(), rhs); + AstNode *stmt = new AstNode(AST_ASSIGN_EQ, lhs, rhs); + SET_AST_NODE_LOC(rhs, begin, end); + SET_AST_NODE_LOC(stmt, begin, end); + ast_stack.back()->children.push_back(stmt); + if (attr != nullptr) + append_attr(stmt, attr); + return lhs; +} + %} %define api.prefix {frontend_verilog_yy} @@ -358,7 +413,7 @@ static void rewriteGenForDeclInit(AstNode *loop) %type integer_atom_type integer_vector_type %type attr case_attr %type struct_union -%type asgn_binop +%type asgn_binop inc_or_dec_op %type genvar_identifier %type specify_target @@ -2610,17 +2665,15 @@ simple_behavioral_stmt: SET_AST_NODE_LOC(node, @2, @5); append_attr(node, $1); } | - attr lvalue TOK_INCREMENT { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, new AstNode(AST_ADD, $2->clone(), AstNode::mkconst_int(1, true))); - ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @2, @3); - append_attr(node, $1); + attr lvalue attr inc_or_dec_op { + // The position 1 attr to avoid shift/reduce conflicts with the + // other productions. We reject attributes in that position. + if (!$1->empty()) + frontend_verilog_yyerror("Attributes are not allowed on this size of the lvalue in an inc_or_dec_expression!"); + addIncOrDecStmt($2, $3, $4, @1, @4); } | - attr lvalue TOK_DECREMENT { - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, new AstNode(AST_SUB, $2->clone(), AstNode::mkconst_int(1, true))); - ast_stack.back()->children.push_back(node); - SET_AST_NODE_LOC(node, @2, @3); - append_attr(node, $1); + inc_or_dec_op attr lvalue { + addIncOrDecStmt($3, $2, $1, @1, @3); } | attr lvalue OP_LE delay expr { AstNode *node = new AstNode(AST_ASSIGN_LE, $2, $5); @@ -2629,18 +2682,7 @@ simple_behavioral_stmt: append_attr(node, $1); } | attr lvalue asgn_binop delay expr { - AstNode *expr_node = $5; - if ($3 == AST_SHIFT_LEFT || $3 == AST_SHIFT_RIGHT || - $3 == AST_SHIFT_SLEFT || $3 == AST_SHIFT_SRIGHT) { - expr_node = new AstNode(AST_TO_UNSIGNED, expr_node); - SET_AST_NODE_LOC(expr_node, @5, @5); - } - AstNode *op_node = new AstNode($3, $2->clone(), expr_node); - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, op_node); - SET_AST_NODE_LOC(op_node, @2, @5); - SET_AST_NODE_LOC(node, @2, @5); - ast_stack.back()->children.push_back(node); - append_attr(node, $1); + addAsgnBinopStmt($1, $2, $3, $5, @2, @5); }; asgn_binop: @@ -2657,6 +2699,12 @@ asgn_binop: TOK_SSHL_ASSIGN { $$ = AST_SHIFT_SLEFT; } | TOK_SSHR_ASSIGN { $$ = AST_SHIFT_SRIGHT; } ; +inc_or_dec_op: + // NOTE: These should only be permitted in SV mode, but Yosys has + // allowed them in all modes since support for them was added in 2017. + TOK_INCREMENT { $$ = AST_ADD; } | + TOK_DECREMENT { $$ = AST_SUB; } ; + for_initialization: TOK_ID '=' expr { AstNode *ident = new AstNode(AST_IDENTIFIER); @@ -3149,6 +3197,14 @@ expr: $$->children.push_back($6); SET_AST_NODE_LOC($$, @1, @$); append_attr($$, $3); + } | + inc_or_dec_op attr rvalue { + $$ = addIncOrDecExpr($3, $2, $1, @1, @3, false); + } | + // TODO: Attributes are allowed in the middle here, but they create some + // non-trivial conflicts that don't seem worth solving for now. + rvalue inc_or_dec_op { + $$ = addIncOrDecExpr($1, nullptr, $2, @1, @2, true); }; basic_expr: @@ -3436,6 +3492,17 @@ basic_expr: frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode."); $$ = new AstNode(AST_CAST_SIZE, $1, $4); SET_AST_NODE_LOC($$, @1, @4); + } | + '(' expr '=' expr ')' { + ensureAsgnExprAllowed(); + AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, $4); + ast_stack.back()->children.push_back(node); + SET_AST_NODE_LOC(node, @2, @4); + $$ = $2->clone(); + } | + '(' expr asgn_binop expr ')' { + ensureAsgnExprAllowed(); + $$ = addAsgnBinopStmt(nullptr, $2, $3, $4, @2, @4)-> clone(); }; concat_list: diff --git a/tests/verilog/asgn_expr.sv b/tests/verilog/asgn_expr.sv new file mode 100644 index 000000000..567034d10 --- /dev/null +++ b/tests/verilog/asgn_expr.sv @@ -0,0 +1,60 @@ +module top; + integer x, y, z; + task check; + input integer a, b, c; + assert (x == a); + assert (y == b); + assert (z == c); + endtask + always_comb begin + x = 0; y = 0; z = 0; + check(0, 0, 0); + + // post-increment/decrement statements + x++; + check(1, 0, 0); + y (* foo *) ++; + check(1, 1, 0); + z--; + check(1, 1, -1); + z (* foo *) --; + check(1, 1, -2); + + // pre-increment/decrement statements are equivalent + ++z; + check(1, 1, -1); + ++ (* foo *) z; + check(1, 1, 0); + --x; + check(0, 1, 0); + -- (* foo *) y; + check(0, 0, 0); + + // procedural pre-increment/decrement expressions + z = ++x; + check(1, 0, 1); + z = ++ (* foo *) x; + check(2, 0, 2); + y = --x; + check(1, 1, 2); + y = -- (* foo *) x; + + // procedural post-increment/decrement expressions + // TODO: support attributes on post-increment/decrement + check(0, 0, 2); + y = x++; + check(1, 0, 2); + y = x--; + check(0, 1, 2); + + // procedural assignment expressions + x = (y = (z = 99) + 1) + 1; + check(101, 100, 99); + x = (y *= 2); + check(200, 200, 99); + x = (z >>= 2) * 4; + check(96, 200, 24); + y = (z >>= 1'sb1) * 2; // shift is implicitly cast to unsigned + check(96, 24, 12); + end +endmodule diff --git a/tests/verilog/asgn_expr.ys b/tests/verilog/asgn_expr.ys new file mode 100644 index 000000000..18180c785 --- /dev/null +++ b/tests/verilog/asgn_expr.ys @@ -0,0 +1,3 @@ +read_verilog -sv asgn_expr.sv +proc +sat -verify -prove-asserts -show-all diff --git a/tests/verilog/asgn_expr_not_proc_1.ys b/tests/verilog/asgn_expr_not_proc_1.ys new file mode 100644 index 000000000..72ba0bd89 --- /dev/null +++ b/tests/verilog/asgn_expr_not_proc_1.ys @@ -0,0 +1,7 @@ +logger -expect error "Assignments within expressions are only permitted within procedures." 1 +read_verilog -sv < Date: Wed, 13 Sep 2023 12:47:18 +0200 Subject: [PATCH 02/95] verific: Add test of accurate semantics in memory inference --- tests/verific/memory_semantics.ys | 94 +++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 tests/verific/memory_semantics.ys diff --git a/tests/verific/memory_semantics.ys b/tests/verific/memory_semantics.ys new file mode 100644 index 000000000..92f4fd2dc --- /dev/null +++ b/tests/verific/memory_semantics.ys @@ -0,0 +1,94 @@ +verific -sv < Date: Tue, 19 Sep 2023 00:23:00 +0000 Subject: [PATCH 03/95] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a93930be0..ab7ea18c0 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+34 +YOSYS_VER := 0.33+53 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 7d07615dee4d245dd97e6f4f643dde73f41a2c81 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Mon, 18 Sep 2023 23:26:35 -0400 Subject: [PATCH 04/95] allow attributes in front of ++/-- statements --- frontends/verilog/verilog_parser.y | 22 +++++++++++----------- tests/verilog/asgn_expr.sv | 8 ++++---- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index d901b3b55..04bf2c87e 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -301,14 +301,18 @@ static void ensureAsgnExprAllowed() } // add a pre/post-increment/decrement statement -static const AstNode *addIncOrDecStmt(AstNode *lhs, dict *attr, AST::AstNodeType op, YYLTYPE begin, YYLTYPE end) +static const AstNode *addIncOrDecStmt(dict *stmt_attr, AstNode *lhs, + dict *op_attr, AST::AstNodeType op, + YYLTYPE begin, YYLTYPE end) { AstNode *one = AstNode::mkconst_int(1, true); AstNode *rhs = new AstNode(op, lhs->clone(), one); + if (op_attr != nullptr) + append_attr(rhs, op_attr); AstNode *stmt = new AstNode(AST_ASSIGN_EQ, lhs, rhs); SET_AST_NODE_LOC(stmt, begin, end); - if (attr != nullptr) - append_attr(stmt, attr); + if (stmt_attr != nullptr) + append_attr(stmt, stmt_attr); ast_stack.back()->children.push_back(stmt); return stmt; } @@ -317,7 +321,7 @@ static const AstNode *addIncOrDecStmt(AstNode *lhs, dict *at static AstNode *addIncOrDecExpr(AstNode *lhs, dict *attr, AST::AstNodeType op, YYLTYPE begin, YYLTYPE end, bool undo) { ensureAsgnExprAllowed(); - const AstNode *stmt = addIncOrDecStmt(lhs, attr, op, begin, end); + const AstNode *stmt = addIncOrDecStmt(nullptr, lhs, attr, op, begin, end); log_assert(stmt->type == AST_ASSIGN_EQ); AstNode *expr = stmt->children[0]->clone(); if (undo) { @@ -2666,14 +2670,10 @@ simple_behavioral_stmt: append_attr(node, $1); } | attr lvalue attr inc_or_dec_op { - // The position 1 attr to avoid shift/reduce conflicts with the - // other productions. We reject attributes in that position. - if (!$1->empty()) - frontend_verilog_yyerror("Attributes are not allowed on this size of the lvalue in an inc_or_dec_expression!"); - addIncOrDecStmt($2, $3, $4, @1, @4); + addIncOrDecStmt($1, $2, $3, $4, @1, @4); } | - inc_or_dec_op attr lvalue { - addIncOrDecStmt($3, $2, $1, @1, @3); + attr inc_or_dec_op attr lvalue { + addIncOrDecStmt($1, $4, $3, $2, @1, @4); } | attr lvalue OP_LE delay expr { AstNode *node = new AstNode(AST_ASSIGN_LE, $2, $5); diff --git a/tests/verilog/asgn_expr.sv b/tests/verilog/asgn_expr.sv index 567034d10..9b874ede3 100644 --- a/tests/verilog/asgn_expr.sv +++ b/tests/verilog/asgn_expr.sv @@ -13,21 +13,21 @@ module top; // post-increment/decrement statements x++; check(1, 0, 0); - y (* foo *) ++; + (* bar *) y (* foo *) ++; check(1, 1, 0); z--; check(1, 1, -1); - z (* foo *) --; + (* bar *) z (* foo *) --; check(1, 1, -2); // pre-increment/decrement statements are equivalent ++z; check(1, 1, -1); - ++ (* foo *) z; + (* bar *) ++ (* foo *) z; check(1, 1, 0); --x; check(0, 1, 0); - -- (* foo *) y; + (* bar *) -- (* foo *) y; check(0, 0, 0); // procedural pre-increment/decrement expressions From 28e99f2b8c50557e0376fbded1c77236a987ecec Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Mon, 18 Sep 2023 23:35:18 -0400 Subject: [PATCH 05/95] fix width of post-increment/decrement expressions --- frontends/verilog/verilog_parser.y | 2 +- tests/verilog/asgn_expr.sv | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 04bf2c87e..cb8c453c0 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -325,7 +325,7 @@ static AstNode *addIncOrDecExpr(AstNode *lhs, dict *attr, AS log_assert(stmt->type == AST_ASSIGN_EQ); AstNode *expr = stmt->children[0]->clone(); if (undo) { - AstNode *minus_one = AstNode::mkconst_int(-1, true); + AstNode *minus_one = AstNode::mkconst_int(-1, true, 1); expr = new AstNode(op, expr, minus_one); } SET_AST_NODE_LOC(expr, begin, end); diff --git a/tests/verilog/asgn_expr.sv b/tests/verilog/asgn_expr.sv index 9b874ede3..25f9caa33 100644 --- a/tests/verilog/asgn_expr.sv +++ b/tests/verilog/asgn_expr.sv @@ -56,5 +56,18 @@ module top; check(96, 200, 24); y = (z >>= 1'sb1) * 2; // shift is implicitly cast to unsigned check(96, 24, 12); + + // check width of post-increment expressions + z = (y = 0); + begin + byte w; + w = 0; + x = {1'b1, ++w}; + check(257, 0, 0); + assert (w == 1); + x = {2'b10, w++}; + check(513, 0, 0); + assert (w == 2); + end end endmodule From 18855f23ce866c014e8be3e4dc652b80deca121f Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 19 Sep 2023 12:00:10 +0200 Subject: [PATCH 06/95] Set src attribute for verific with full info --- frontends/verific/verific.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index a67244d7a..cd844dcee 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -265,7 +265,7 @@ void VerificImporter::import_attributes(dict &att Att *attr; if (obj->Linefile()) - attributes[ID::src] = stringf("%s:%d", LineFile::GetFileName(obj->Linefile()), LineFile::GetLineNo(obj->Linefile())); + attributes[ID::src] = stringf("%s:%d.%d-%d.%d", LineFile::GetFileName(obj->Linefile()), obj->Linefile()->GetLeftLine(), obj->Linefile()->GetLeftCol(), obj->Linefile()->GetRightLine(), obj->Linefile()->GetRightCol()); FOREACH_ATTRIBUTE(obj, mi, attr) { if (attr->Key()[0] == ' ' || attr->Value() == nullptr) From 35a05686c4e9987441ac298f5d631f1785e272fd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 00:15:04 +0000 Subject: [PATCH 07/95] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ab7ea18c0..a75af96b5 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+53 +YOSYS_VER := 0.33+56 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From e0042bdff74a6895bff04d9fbd42ad4c4713369b Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Wed, 20 Sep 2023 15:49:05 -0700 Subject: [PATCH 08/95] Speed up TopoSort. The main sorting algorithm implementation in TopoSort::sort_worker is 11-12x faster. Overall, the complete sequence of building the graph and sorting is about 2.5-3x faster. The overall impact in e.g. the replace_const_cells optimization pass is a ~25% speedup. End-to-end impact on our synthesis flow is about 3%. --- kernel/utils.h | 184 +++++++++++++++++++++++--------------- passes/cmds/glift.cc | 2 +- passes/opt/opt_expr.cc | 15 ++-- passes/opt/share.cc | 2 +- passes/techmap/flatten.cc | 2 +- 5 files changed, 126 insertions(+), 79 deletions(-) diff --git a/kernel/utils.h b/kernel/utils.h index d37f045ff..e452f380e 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -31,34 +31,30 @@ YOSYS_NAMESPACE_BEGIN // A map-like container, but you can save and restore the state // ------------------------------------------------ -template> -struct stackmap -{ -private: - std::vector> backup_state; +template > struct stackmap { + private: + std::vector> backup_state; dict current_state; static T empty_tuple; -public: - stackmap() { } - stackmap(const dict &other) : current_state(other) { } + public: + stackmap() {} + stackmap(const dict &other) : current_state(other) {} - template - void operator=(const Other &other) + template stackmap &operator=(const Other &other) { - for (auto &it : current_state) + for (const auto &it : current_state) if (!backup_state.empty() && backup_state.back().count(it.first) == 0) backup_state.back()[it.first] = new T(it.second); current_state.clear(); - for (auto &it : other) + for (const auto &it : other) set(it.first, it.second); + + return *this; } - bool has(const Key &k) - { - return current_state.count(k) != 0; - } + bool has(const Key &k) { return current_state.count(k) != 0; } void set(const Key &k, const T &v) { @@ -83,7 +79,7 @@ public: void reset(const Key &k) { - for (int i = GetSize(backup_state)-1; i >= 0; i--) + for (int i = GetSize(backup_state) - 1; i >= 0; i--) if (backup_state[i].count(k) != 0) { if (backup_state[i].at(k) == nullptr) current_state.erase(k); @@ -94,20 +90,14 @@ public: current_state.erase(k); } - const dict &stdmap() - { - return current_state; - } + const dict &stdmap() { return current_state; } - void save() - { - backup_state.resize(backup_state.size()+1); - } + void save() { backup_state.resize(backup_state.size() + 1); } void restore() { log_assert(!backup_state.empty()); - for (auto &it : backup_state.back()) + for (const auto &it : backup_state.back()) if (it.second != nullptr) { current_state[it.first] = *it.second; delete it.second; @@ -123,46 +113,116 @@ public: } }; - // ------------------------------------------------ // A simple class for topological sorting // ------------------------------------------------ -template> -struct TopoSort +template , typename OPS = hash_ops> class TopoSort { - bool analyze_loops, found_loops; - std::map, C> database; - std::set> loops; - std::vector sorted; + public: + // We use this ordering of the edges in the adjacency matrix for + // exact compatibility with an older implementation. + struct IndirectCmp { + IndirectCmp(const std::vector &nodes) : nodes_(nodes) {} + bool operator()(int a, int b) const + { + log_assert(static_cast(a) < nodes_.size()); + log_assert(static_cast(b) < nodes_.size()); + return node_cmp_(nodes_[a], nodes_[b]); + } + const C node_cmp_; + const std::vector &nodes_; + }; - TopoSort() + bool analyze_loops; + std::map node_to_index; + std::vector> edges; + std::vector sorted; + std::set> loops; + + public: + TopoSort() : indirect_cmp(nodes) { analyze_loops = true; found_loops = false; } - void node(T n) + int node(T n) { - if (database.count(n) == 0) - database[n] = std::set(); + auto it = node_to_index.find(n); + if (it == node_to_index.end()) { + int index = static_cast(nodes.size()); + node_to_index[n] = index; + nodes.push_back(n); + edges.push_back(std::set(indirect_cmp)); + return index; + } + return it->second; } - void edge(T left, T right) + void edge(int l_index, int r_index) { edges[r_index].insert(l_index); } + + void edge(T left, T right) { edge(node(left), node(right)); } + + bool has_edges(const T &node) { - node(left); - database[right].insert(left); + auto it = node_to_index.find(node); + return it == node_to_index.end() || !edges[it->second].empty(); } - void sort_worker(const T &n, std::set &marked_cells, std::set &active_cells, std::vector &active_stack) + bool sort() { - if (active_cells.count(n)) { + log_assert(GetSize(node_to_index) == GetSize(edges)); + log_assert(GetSize(nodes) == GetSize(edges)); + + loops.clear(); + sorted.clear(); + found_loops = false; + + std::vector marked_cells(edges.size(), false); + std::vector active_cells(edges.size(), false); + std::vector active_stack; + + marked_cells.reserve(edges.size()); + sorted.reserve(edges.size()); + + for (const auto &it : node_to_index) + sort_worker(it.second, marked_cells, active_cells, active_stack); + + log_assert(GetSize(sorted) == GetSize(nodes)); + + return !found_loops; + } + + // Build the more expensive representation of edges for + // a few passes that use it directly. + std::map, C> get_database() + { + std::map, C> database; + for (size_t i = 0; i < nodes.size(); ++i) { + std::set converted_edge_set; + for (int other_node : edges[i]) { + converted_edge_set.insert(nodes[other_node]); + } + database.emplace(nodes[i], converted_edge_set); + } + return database; + } + + private: + bool found_loops; + std::vector nodes; + const IndirectCmp indirect_cmp; + void sort_worker(const int root_index, std::vector &marked_cells, std::vector &active_cells, std::vector &active_stack) + { + if (active_cells[root_index]) { found_loops = true; if (analyze_loops) { std::set loop; - for (int i = GetSize(active_stack)-1; i >= 0; i--) { - loop.insert(active_stack[i]); - if (active_stack[i] == n) + for (int i = GetSize(active_stack) - 1; i >= 0; i--) { + const int index = active_stack[i]; + loop.insert(nodes[index]); + if (index == root_index) break; } loops.insert(loop); @@ -170,42 +230,24 @@ struct TopoSort return; } - if (marked_cells.count(n)) + if (marked_cells[root_index]) return; - if (!database.at(n).empty()) - { + if (!edges[root_index].empty()) { if (analyze_loops) - active_stack.push_back(n); - active_cells.insert(n); + active_stack.push_back(root_index); + active_cells[root_index] = true; - for (auto &left_n : database.at(n)) + for (int left_n : edges[root_index]) sort_worker(left_n, marked_cells, active_cells, active_stack); if (analyze_loops) active_stack.pop_back(); - active_cells.erase(n); + active_cells[root_index] = false; } - marked_cells.insert(n); - sorted.push_back(n); - } - - bool sort() - { - loops.clear(); - sorted.clear(); - found_loops = false; - - std::set marked_cells; - std::set active_cells; - std::vector active_stack; - - for (auto &it : database) - sort_worker(it.first, marked_cells, active_cells, active_stack); - - log_assert(GetSize(sorted) == GetSize(database)); - return !found_loops; + marked_cells[root_index] = true; + sorted.push_back(nodes[root_index]); } }; diff --git a/passes/cmds/glift.cc b/passes/cmds/glift.cc index 439ded076..faa4289e3 100644 --- a/passes/cmds/glift.cc +++ b/passes/cmds/glift.cc @@ -582,7 +582,7 @@ struct GliftPass : public Pass { for (auto cell : module->selected_cells()) { RTLIL::Module *tpl = design->module(cell->type); if (tpl != nullptr) { - if (topo_modules.database.count(tpl) == 0) + if (!topo_modules.has_edges(tpl)) worklist.push_back(tpl); topo_modules.edge(tpl, module); non_top_modules.insert(cell->type); diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 46773a344..7331d72a6 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -424,13 +424,18 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons for (auto &bit : sig) outbit_to_cell[bit].insert(cell); } - cells.node(cell); } - for (auto &it_right : cell_to_inbit) - for (auto &it_sigbit : it_right.second) - for (auto &it_left : outbit_to_cell[it_sigbit]) - cells.edge(it_left, it_right.first); + // Build the graph for the topological sort. + for (auto &it_right : cell_to_inbit) { + const int r_index = cells.node(it_right.first); + for (auto &it_sigbit : it_right.second) { + for (auto &it_left : outbit_to_cell[it_sigbit]) { + const int l_index = cells.node(it_left); + cells.edge(l_index, r_index); + } + } + } cells.sort(); diff --git a/passes/opt/share.cc b/passes/opt/share.cc index abef71937..586bd9dfe 100644 --- a/passes/opt/share.cc +++ b/passes/opt/share.cc @@ -1032,7 +1032,7 @@ struct ShareWorker } bool found_scc = !toposort.sort(); - topo_cell_drivers = std::move(toposort.database); + topo_cell_drivers = toposort.get_database(); if (found_scc && toposort.analyze_loops) for (auto &loop : toposort.loops) { diff --git a/passes/techmap/flatten.cc b/passes/techmap/flatten.cc index 7e6df5d2c..f49589b82 100644 --- a/passes/techmap/flatten.cc +++ b/passes/techmap/flatten.cc @@ -312,7 +312,7 @@ struct FlattenPass : public Pass { for (auto cell : module->selected_cells()) { RTLIL::Module *tpl = design->module(cell->type); if (tpl != nullptr) { - if (topo_modules.database.count(tpl) == 0) + if (!topo_modules.has_edges(tpl)) worklist.insert(tpl); topo_modules.edge(tpl, module); } From b9745f638b0a2ee4fd97096af7bce0198aedd8be Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Wed, 20 Sep 2023 16:20:08 -0700 Subject: [PATCH 09/95] Remove extraneous "public:". --- kernel/utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/utils.h b/kernel/utils.h index e452f380e..4679a23f2 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -140,7 +140,6 @@ template , typename OPS = hash_ops> cla std::vector sorted; std::set> loops; - public: TopoSort() : indirect_cmp(nodes) { analyze_loops = true; @@ -213,6 +212,7 @@ template , typename OPS = hash_ops> cla bool found_loops; std::vector nodes; const IndirectCmp indirect_cmp; + void sort_worker(const int root_index, std::vector &marked_cells, std::vector &active_cells, std::vector &active_stack) { if (active_cells[root_index]) { From aa06809d6483abe98ab270f093968cab5838d51b Mon Sep 17 00:00:00 2001 From: Ethan Mahintorabi Date: Mon, 18 Sep 2023 21:38:50 +0000 Subject: [PATCH 10/95] rtlil: Speeds up Yosys by 17% This PR speeds up by roughly 17% across a wide spectrum of designs tested at Google. Particularly for the mux generation pass. Co-authored-by: Rasmus Larsen Signed-off-by: Ethan Mahintorabi --- kernel/rtlil.cc | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 51d020913..1b57af60a 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4031,16 +4031,20 @@ void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec unpack(); other->unpack(); + dict pattern_to_with; for (int i = 0; i < GetSize(pattern.bits_); i++) { if (pattern.bits_[i].wire != NULL) { - for (int j = 0; j < GetSize(bits_); j++) { - if (bits_[j] == pattern.bits_[i]) { - other->bits_[j] = with.bits_[i]; - } - } + pattern_to_with.emplace(pattern.bits_[i], i); } } + for (int j = 0; j < GetSize(bits_); j++) { + auto it = pattern_to_with.find(bits_[j]); + if (it != pattern_to_with.end()) { + other->bits_[j] = with.bits_[it->second]; + } + } + other->check(); } From 9ed38bf9b662b36852271671f2a73ed659b00331 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Thu, 21 Sep 2023 02:46:49 -0700 Subject: [PATCH 11/95] Speed up the autoname pass by 3x. (#3945) * Speed up the autoname pass by 2x. This is accomplished by only constructing IdString objects for plain strings that have a higher score. * Defer creating IdStrings even further. This increases the speedup to 3x. --- passes/cmds/autoname.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/passes/cmds/autoname.cc b/passes/cmds/autoname.cc index 6019c6153..737bd3e58 100644 --- a/passes/cmds/autoname.cc +++ b/passes/cmds/autoname.cc @@ -24,8 +24,8 @@ PRIVATE_NAMESPACE_BEGIN int autoname_worker(Module *module, const dict& wire_score) { - dict> proposed_cell_names; - dict> proposed_wire_names; + dict> proposed_cell_names; + dict> proposed_wire_names; int best_score = -1; for (auto cell : module->selected_cells()) { @@ -36,7 +36,7 @@ int autoname_worker(Module *module, const dict& wire_score) if (bit.wire != nullptr && bit.wire->name[0] != '$') { if (suffix.empty()) suffix = stringf("_%s_%s", log_id(cell->type), log_id(conn.first)); - IdString new_name(bit.wire->name.str() + suffix); + string new_name(bit.wire->name.str() + suffix); int score = wire_score.at(bit.wire); if (cell->output(conn.first)) score = 0; score = 10000*score + new_name.size(); @@ -54,7 +54,7 @@ int autoname_worker(Module *module, const dict& wire_score) if (bit.wire != nullptr && bit.wire->name[0] == '$' && !bit.wire->port_id) { if (suffix.empty()) suffix = stringf("_%s", log_id(conn.first)); - IdString new_name(cell->name.str() + suffix); + string new_name(cell->name.str() + suffix); int score = wire_score.at(bit.wire); if (cell->output(conn.first)) score = 0; score = 10000*score + new_name.size(); @@ -71,7 +71,7 @@ int autoname_worker(Module *module, const dict& wire_score) for (auto &it : proposed_cell_names) { if (best_score*2 < it.second.first) continue; - IdString n = module->uniquify(it.second.second); + IdString n = module->uniquify(IdString(it.second.second)); log_debug("Rename cell %s in %s to %s.\n", log_id(it.first), log_id(module), log_id(n)); module->rename(it.first, n); } @@ -79,7 +79,7 @@ int autoname_worker(Module *module, const dict& wire_score) for (auto &it : proposed_wire_names) { if (best_score*2 < it.second.first) continue; - IdString n = module->uniquify(it.second.second); + IdString n = module->uniquify(IdString(it.second.second)); log_debug("Rename wire %s in %s to %s.\n", log_id(it.first), log_id(module), log_id(n)); module->rename(it.first, n); } From 934c82254d8abd33ee8827b200ff005868737f74 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 22 Sep 2023 00:14:51 +0000 Subject: [PATCH 12/95] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a75af96b5..77f7b80fa 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+56 +YOSYS_VER := 0.33+65 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From fedd12261fc6e3828baf6025a0d3af1931495eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 18 Sep 2023 18:56:30 +0200 Subject: [PATCH 13/95] booth: Move away from explicit `Wire` pointers To represent intermediate signals use the `SigBit`/`SigSpec` classes as is customary in the Yosys codebase. Do not pass around `Wire` pointers unless we have special reason to. --- passes/techmap/booth.cc | 442 ++++++++++++++++++---------------------- 1 file changed, 194 insertions(+), 248 deletions(-) diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index e74916852..fe9c1cec6 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -94,7 +94,7 @@ struct BoothPassWorker { } // Unary gate - RTLIL::Wire *mk_ugate1(const RTLIL::IdString &red_typ, std::string &name, RTLIL::Wire *ip1, std::string &op_name) + RTLIL::Wire *mk_ugate1(const RTLIL::IdString &red_typ, std::string &name, SigBit ip1, std::string &op_name) { std::string op_wire_name; if (op_name.empty()) @@ -112,7 +112,7 @@ struct BoothPassWorker { } // Binary gate - RTLIL::Wire *mk_ugate2(const RTLIL::IdString &red_typ, std::string &name, RTLIL::Wire *ip1, RTLIL::Wire *ip2, std::string &op_name) + RTLIL::Wire *mk_ugate2(const RTLIL::IdString &red_typ, std::string &name, SigBit ip1, SigBit ip2, std::string &op_name) { auto g = module->addCell(new_id(name, __LINE__, ""), red_typ); std::string op_wire_name; @@ -135,7 +135,7 @@ struct BoothPassWorker { } // Booth unsigned decoder lsb - void BuildBur4d_lsb(std::string &name, RTLIL::Wire *lsb_i, RTLIL::Wire *one_i, RTLIL::Wire *s_i, RTLIL::Wire *&ppij_o, + void BuildBur4d_lsb(std::string &name, SigBit lsb_i, SigBit one_i, SigBit s_i, SigBit &ppij_o, std::string op_wire_name) { std::string empty; @@ -144,8 +144,8 @@ struct BoothPassWorker { } // Booth unsigned radix4 decoder - void BuildBur4d_n(std::string &name, RTLIL::Wire *yn_i, RTLIL::Wire *ynm1_i, RTLIL::Wire *one_i, RTLIL::Wire *two_i, RTLIL::Wire *s_i, - RTLIL::Wire *&ppij_o) + void BuildBur4d_n(std::string &name, SigBit yn_i, SigBit ynm1_i, SigBit one_i, SigBit two_i, SigBit s_i, + SigBit &ppij_o) { // ppij = ((yn & one) | (ynm1 & two)) ^ s; std::string empty; @@ -156,7 +156,7 @@ struct BoothPassWorker { } // Booth unsigned radix4 decoder - void BuildBur4d_msb(std::string &name, RTLIL::Wire *msb_i, RTLIL::Wire *two_i, RTLIL::Wire *s_i, RTLIL::Wire *&ppij_o) + void BuildBur4d_msb(std::string &name, SigBit msb_i, SigBit two_i, SigBit s_i, SigBit &ppij_o) { // ppij = (msb & two) ^ s; std::string empty; @@ -165,7 +165,7 @@ struct BoothPassWorker { } // half adder, used in CPA - void BuildHa(std::string &name, RTLIL::Wire *a_i, RTLIL::Wire *b_i, RTLIL::Wire *&s_o, RTLIL::Wire *&c_o) + void BuildHa(std::string &name, SigBit a_i, SigBit b_i, SigBit &s_o, SigBit &c_o) { std::string empty; s_o = mk_ugate2(ID($xor), name, a_i, b_i, empty); @@ -173,9 +173,8 @@ struct BoothPassWorker { } // Booth unsigned radix 4 encoder - void BuildBur4e(std::string &name, RTLIL::Wire *y0_i, RTLIL::Wire *y1_i, RTLIL::Wire *y2_i, - - RTLIL::Wire *&one_o, RTLIL::Wire *&two_o, RTLIL::Wire *&s_o, RTLIL::Wire *&sb_o) + void BuildBur4e(std::string &name, SigBit y0_i, SigBit y1_i, SigBit y2_i, + SigBit &one_o, SigBit &two_o, SigBit &s_o, SigBit &sb_o) { std::string empty; @@ -186,11 +185,10 @@ struct BoothPassWorker { two_o = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, inv_y1_xor_y2, one_o, empty), empty); } - void BuildBr4e(std::string &name, RTLIL::Wire *y2_m1_i, - RTLIL::Wire *y2_i, // y2i - RTLIL::Wire *y2_p1_i, - - RTLIL::Wire *&negi_o, RTLIL::Wire *&twoi_n_o, RTLIL::Wire *&onei_n_o, RTLIL::Wire *&cori_o) + void BuildBr4e(std::string &name, SigBit y2_m1_i, + SigBit y2_i, // y2i + SigBit y2_p1_i, + SigBit &negi_o, SigBit &twoi_n_o, SigBit &onei_n_o, SigBit &cori_o) { std::string empty; @@ -217,9 +215,8 @@ struct BoothPassWorker { // // signed booth radix 4 decoder // - void BuildBr4d(std::string &name, RTLIL::Wire *nxj_m1_i, RTLIL::Wire *twoi_n_i, RTLIL::Wire *xj_i, RTLIL::Wire *negi_i, RTLIL::Wire *onei_n_i, - - RTLIL::Wire *&ppij_o, RTLIL::Wire *&nxj_o) + void BuildBr4d(std::string &name, SigBit nxj_m1_i, SigBit twoi_n_i, SigBit xj_i, SigBit negi_i, SigBit onei_n_i, + SigBit &ppij_o, SigBit &nxj_o) { std::string empty; @@ -227,8 +224,8 @@ struct BoothPassWorker { // nxj_o = xnj_in, // ppij = ~( (nxj_m1_i | twoi_n_i) & (nxj_int | onei_n_i)); nxj_o = mk_ugate2(ID($xnor), name, xj_i, negi_i, empty); - RTLIL::Wire *or1 = mk_ugate2(ID($or), name, nxj_m1_i, twoi_n_i, empty); - RTLIL::Wire *or2 = mk_ugate2(ID($or), name, nxj_o, onei_n_i, empty); + SigBit or1 = mk_ugate2(ID($or), name, nxj_m1_i, twoi_n_i, empty); + SigBit or2 = mk_ugate2(ID($or), name, nxj_o, onei_n_i, empty); ppij_o = mk_ugate1(ID($not), name, mk_ugate2(ID($and), name, or1, or2, empty), empty); } @@ -237,12 +234,9 @@ struct BoothPassWorker { using non-booth encoded logic. We can save a booth encoder for the first couple of bits. */ - void BuildBoothQ1(std::string &name, RTLIL::Wire *negi_i, RTLIL::Wire *cori_i, RTLIL::Wire *x0_i, RTLIL::Wire *x1_i, RTLIL::Wire *y0_i, - RTLIL::Wire *y1_i, - - RTLIL::Wire *&nxj_o, RTLIL::Wire *&cor_o, RTLIL::Wire *&pp0_o, RTLIL::Wire *&pp1_o - - ) + void BuildBoothQ1(std::string &name, SigBit negi_i, SigBit cori_i, SigBit x0_i, SigBit x1_i, SigBit y0_i, + SigBit y1_i, + SigBit &nxj_o, SigBit &cor_o, SigBit &pp0_o, SigBit &pp1_o) { /* assign NXJO = ~(X1 ^ NEGI); @@ -258,11 +252,11 @@ struct BoothPassWorker { std::string empty; nxj_o = mk_ugate2(ID($xnor), name, x1_i, negi_i, empty); pp0_o = mk_ugate2(ID($and), name, x0_i, y0_i, empty); - RTLIL::Wire *pp1_1_int = mk_ugate2(ID($and), name, x1_i, y0_i, empty); - RTLIL::Wire *pp1_2_int = mk_ugate2(ID($and), name, x0_i, y1_i, empty); + SigBit pp1_1_int = mk_ugate2(ID($and), name, x1_i, y0_i, empty); + SigBit pp1_2_int = mk_ugate2(ID($and), name, x0_i, y1_i, empty); pp1_o = mk_ugate2(ID($xor), name, pp1_1_int, pp1_2_int, empty); - RTLIL::Wire *pp1_nor_pp0 = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, pp1_o, pp0_o, empty), empty); + SigBit pp1_nor_pp0 = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, pp1_o, pp0_o, empty), empty); cor_o = mk_ugate2(ID($and), name, pp1_nor_pp0, cori_i, empty); } @@ -355,13 +349,13 @@ struct BoothPassWorker { buf->setPort(ID::Y, SigSpec(Y)); if (is_signed == false) /* unsigned multiplier */ - CreateBoothUMult(module, x_sz_revised, y_sz_revised, required_op_size, + CreateBoothUMult(module, expanded_A, // multiplicand expanded_B, // multiplier(scanned) expanded_Y // result ); else /*signed multiplier */ - CreateBoothSMult(module, x_sz_revised, y_sz_revised, required_op_size, + CreateBoothSMult(module, expanded_A, // multiplicand expanded_B, // multiplier(scanned) expanded_Y // result (sized) @@ -382,19 +376,17 @@ struct BoothPassWorker { extra row of decoders and extended multiplier */ - void CreateBoothUMult(RTLIL::Module *module, int x_sz, int y_sz, int z_sz, - RTLIL::Wire *X, // multiplicand - RTLIL::Wire *Y, // multiplier - RTLIL::Wire *Z) + void CreateBoothUMult(RTLIL::Module *module, + SigSpec X, // multiplicand + SigSpec Y, // multiplier + SigSpec Z) { // result + int x_sz = X.size(), z_sz = Z.size(); - std::vector one_int; - std::vector two_int; - std::vector s_int; - std::vector sb_int; + SigSpec one_int, two_int, s_int, sb_int; int encoder_count = 0; - BuildBoothUMultEncoders(Y, y_sz, one_int, two_int, s_int, sb_int, module, encoder_count); + BuildBoothUMultEncoders(Y, one_int, two_int, s_int, sb_int, module, encoder_count); // Build the decoder rows // format of each Partial product to be passed to CSA @@ -404,31 +396,10 @@ struct BoothPassWorker { // Shift // Sign bit to be added // - std::vector, int, RTLIL::Wire *>> ppij_int; - - static int constant_ix; - constant_ix++; - std::string buf_name = "constant_buf_" + std::to_string(constant_ix); - auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - RTLIL::Wire *constant_one = module->addWire(new_id(buf_name, __LINE__, ""), 1); - buf->setPort(ID::A, State::S1); - buf->setParam(ID::A_WIDTH, 1); - buf->setParam(ID::Y_WIDTH, 1); - buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, constant_one); - - constant_ix++; - buf_name = "constant_buf_" + std::to_string(constant_ix); - buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - RTLIL::Wire *constant_zero = module->addWire(new_id(buf_name, __LINE__, ""), 1); - buf->setPort(ID::A, State::S0); - buf->setParam(ID::A_WIDTH, 1); - buf->setParam(ID::Y_WIDTH, 1); - buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, constant_zero); + std::vector> ppij_int; // Row 0: special case 1. Format S/.S.S.C.Data - std::vector ppij_row_0; + SigSpec ppij_row_0; BuildBoothUMultDecoderRow0(module, X, s_int, sb_int, one_int, two_int, ppij_row_0); // data, shift, sign @@ -436,11 +407,11 @@ struct BoothPassWorker { for (int i = 1; i < encoder_count - 2; i++) { // format 1,S.Data.shift = encoder_ix*2,sign = sb_int[i] - std::vector ppij_row_n; + SigSpec ppij_row_n; BuildBoothUMultDecoderRowN(module, X, // multiplicand - one_int[i], two_int[i], s_int[i], sb_int[i], ppij_row_n, constant_one, i, + one_int[i], two_int[i], s_int[i], sb_int[i], ppij_row_n, i, false, // include sign false // include constant ); @@ -450,18 +421,18 @@ struct BoothPassWorker { // Build second to last row // format S/,Data + sign bit - std::vector ppij_row_em1; + SigSpec ppij_row_em1; BuildBoothUMultDecoderRowN(module, X, one_int[encoder_count - 2], two_int[encoder_count - 2], s_int[encoder_count - 2], - sb_int[encoder_count - 2], ppij_row_em1, constant_one, encoder_count - 2, + sb_int[encoder_count - 2], ppij_row_em1, encoder_count - 2, false, // include sign true // no constant ); ppij_int.push_back(std::make_tuple(ppij_row_em1, (encoder_count - 2) * 2, s_int[encoder_count - 2])); // Build last row // format Data + sign bit - std::vector ppij_row_e; + SigSpec ppij_row_e; BuildBoothUMultDecoderRowN(module, X, one_int[encoder_count - 1], two_int[encoder_count - 1], s_int[encoder_count - 1], - sb_int[encoder_count - 1], ppij_row_e, constant_one, encoder_count - 1, + sb_int[encoder_count - 1], ppij_row_e, encoder_count - 1, true, // no sign true // no constant ); @@ -471,13 +442,13 @@ struct BoothPassWorker { // DebugDumpPP(ppij_int); // Summation of Partial Products (Wallace Tree) - std::vector> aligned_pp; + std::vector aligned_pp; aligned_pp.resize(encoder_count + 1); // make an entirely redundant row // just for sign bit in lsb. (We then filter this out). // resize all to be same size as z for (int i = 0; i < encoder_count + 1; i++) - aligned_pp[i].resize(z_sz); + aligned_pp[i].extend_u0(z_sz); AlignPP(x_sz, z_sz, ppij_int, aligned_pp); @@ -485,8 +456,8 @@ struct BoothPassWorker { // Later on yosys will clean up unused constants // DebugDumpAlignPP(aligned_pp); - std::vector s_vec; - std::vector c_vec; + SigSpec s_vec; + SigSpec c_vec; std::vector> debug_csa_trees; debug_csa_trees.resize(z_sz); @@ -504,9 +475,9 @@ struct BoothPassWorker { */ void BuildBoothUMultDecoderRow0(RTLIL::Module *module, - RTLIL::Wire *X, // multiplicand - std::vector &s_int, std::vector &sb_int, std::vector &one_int, - std::vector &two_int, std::vector &ppij_vec) + SigSpec X, // multiplicand + SigSpec s_int, SigSpec sb_int, SigSpec one_int, + SigSpec two_int, SigSpec &ppij_vec) { (void)module; int x_sz = GetSize(X); @@ -514,73 +485,72 @@ struct BoothPassWorker { // lsb std::string dec_name = "row0_lsb_dec"; - RTLIL::Wire *ppij; + SigBit ppij; std::string ppij_name = "ppij_0_0"; - BuildBur4d_lsb(dec_name, mk_wireFromSigSpec(SigSpec(X, 0, 1)), one_int[0], s_int[0], ppij, ppij_name); - ppij_vec.push_back(ppij); + BuildBur4d_lsb(dec_name, X[0], one_int[0], s_int[0], ppij, ppij_name); + ppij_vec.append(ppij); // 1..xsize -1 for (int i = 1; i < x_sz; i++) { dec_name = "row0_dec_" + std::to_string(i); - RTLIL::Wire *ppij; - BuildBur4d_n(dec_name, mk_wireFromSigSpec(SigSpec(X, i, 1)), mk_wireFromSigSpec(SigSpec(X, i - 1, 1)), one_int[0], two_int[0], + SigBit ppij; + BuildBur4d_n(dec_name, X[i], X[i - 1], one_int[0], two_int[0], s_int[0], ppij); - ppij_vec.push_back(ppij); + ppij_vec.append(ppij); } // The redundant bit. Duplicate decoding of last bit. dec_name = "row0_dec_msb"; - BuildBur4d_msb(dec_name, mk_wireFromSigSpec(SigSpec(X, x_sz - 1, 1)), two_int[0], s_int[0], ppij); - ppij_vec.push_back(ppij); + BuildBur4d_msb(dec_name, X[x_sz - 1], two_int[0], s_int[0], ppij); + ppij_vec.append(ppij); // append the sign bits - ppij_vec.push_back(s_int[0]); - ppij_vec.push_back(s_int[0]); - ppij_vec.push_back(sb_int[0]); + ppij_vec.append(s_int[0]); + ppij_vec.append(s_int[0]); + ppij_vec.append(sb_int[0]); } // Build a generic row of decoders. void BuildBoothUMultDecoderRowN(RTLIL::Module *module, - RTLIL::Wire *X, // multiplicand - RTLIL::Wire *one_int, RTLIL::Wire *two_int, RTLIL::Wire *s_int, RTLIL::Wire *sb_int, - std::vector &ppij_vec, RTLIL::Wire *constant_one, int row_ix, bool no_sign, bool no_constant) + SigSpec X, // multiplicand + SigSpec one_int, SigSpec two_int, SigSpec s_int, SigSpec sb_int, + SigSpec &ppij_vec, int row_ix, bool no_sign, bool no_constant) { (void)module; int x_sz = GetSize(X); // lsb std::string ppij_name = "ppij_" + std::to_string(row_ix) + "_0"; - RTLIL::Wire *ppij = nullptr; + SigBit ppij; std::string empty; std::string dec_name = "row" + std::to_string(row_ix) + "_lsb_dec"; - BuildBur4d_lsb(dec_name, mk_wireFromSigSpec(SigSpec(X, 0, 1)), one_int, s_int, ppij, empty); + BuildBur4d_lsb(dec_name, X[0], one_int, s_int, ppij, empty); - ppij_vec.push_back(ppij); + ppij_vec.append(ppij); // core bits for (int i = 1; i < x_sz; i++) { dec_name = "row_" + std::to_string(row_ix) + "_dec_" + std::to_string(i); - RTLIL::Wire *ppij = nullptr; - BuildBur4d_n(dec_name, mk_wireFromSigSpec(SigSpec(X, i, 1)), mk_wireFromSigSpec(SigSpec(X, i - 1, 1)), one_int, two_int, - s_int, ppij); - ppij_vec.push_back(ppij); + BuildBur4d_n(dec_name, X[i], X[i - 1], + one_int, two_int, s_int, ppij); + ppij_vec.append(ppij); } // redundant bit dec_name = "row_dec_red"; - BuildBur4d_msb(dec_name, mk_wireFromSigSpec(SigSpec(X, x_sz - 1, 1)), two_int, s_int, ppij); - ppij_vec.push_back(ppij); + BuildBur4d_msb(dec_name, X[x_sz - 1], two_int, s_int, ppij); + ppij_vec.append(ppij); // sign bit if (no_sign == false) // if no sign is false then make a sign bit - ppij_vec.push_back(sb_int); + ppij_vec.append(sb_int); // constant bit if (no_constant == false) { // if non constant is false make a constant bit - ppij_vec.push_back(constant_one); + ppij_vec.append(State::S1); } } @@ -663,8 +633,8 @@ struct BoothPassWorker { } } - void BuildCSATree(RTLIL::Module *module, std::vector> &bits_to_reduce, std::vector &s_vec, - std::vector &c_vec, std::vector> &debug_csa_trees) + void BuildCSATree(RTLIL::Module *module, std::vector &bits_to_reduce, SigSpec &s_vec, + SigSpec &c_vec, std::vector> &debug_csa_trees) { if (!(bits_to_reduce.size() > 0)) @@ -672,24 +642,24 @@ struct BoothPassWorker { int column_size = bits_to_reduce[0].size(); int row_size = bits_to_reduce.size(); - std::vector carry_bits_to_add_to_next_column; + SigSpec carry_bits_to_add_to_next_column; for (int column_ix = 0; column_ix < column_size; column_ix++) { // get the bits in this column. - std::vector column_bits; + SigSpec column_bits; for (int row_ix = 0; row_ix < row_size; row_ix++) { - if (bits_to_reduce[row_ix].at(column_ix)) - column_bits.push_back(bits_to_reduce[row_ix].at(column_ix)); + if (bits_to_reduce[row_ix][column_ix].wire) + column_bits.append(bits_to_reduce[row_ix][column_ix]); } for (auto c : carry_bits_to_add_to_next_column) { #ifdef DEBUG_CSA printf("\t Propagating column bit %s to column %d from column %d\n", c->name.c_str(), column_ix, column_ix - 1); #endif - column_bits.push_back(c); + column_bits.append(c); } - carry_bits_to_add_to_next_column.resize(0); + carry_bits_to_add_to_next_column = {}; #ifdef DEBUG_CSA printf("Column %d Reducing %d bits\n", column_ix, column_bits.size()); @@ -699,16 +669,15 @@ struct BoothPassWorker { printf("\n"); #endif - RTLIL::Wire *s = nullptr; - RTLIL::Wire *c = nullptr; + SigBit s, c; #ifdef DEBUG_CSA int csa_count_before = debug_csa_trees[column_ix].size(); #endif ReduceBits(module, column_ix, column_bits, s, c, carry_bits_to_add_to_next_column, debug_csa_trees); - s_vec.push_back(s); - c_vec.push_back(c); + s_vec.append(s); + c_vec.append(c); #ifdef DEBUG_CSA int csa_count_after = debug_csa_trees[column_ix].size(); @@ -738,8 +707,8 @@ struct BoothPassWorker { Pad out rows with zeros and left the opt pass clean them up. */ - void AlignPP(int x_sz, int z_sz, std::vector, int, RTLIL::Wire *>> &ppij_int, - std::vector> &aligned_pp) + void AlignPP(int x_sz, int z_sz, std::vector> &ppij_int, + std::vector &aligned_pp) { unsigned aligned_pp_ix = aligned_pp.size() - 1; @@ -748,7 +717,7 @@ struct BoothPassWorker { for (unsigned i = 0; i < aligned_pp.size(); i++) { for (int j = 0; j < z_sz; j++) { - aligned_pp[i][j] = nullptr; + aligned_pp[i][j] = State::S0; } } @@ -758,21 +727,19 @@ struct BoothPassWorker { // in first column of the last partial product // which is at index corresponding to size of multiplicand { - RTLIL::Wire *prior_row_sign = nullptr; - prior_row_sign = get<2>(ppij_int[aligned_pp_ix - 1]); - if (prior_row_sign) { + SigBit prior_row_sign = get<2>(ppij_int[aligned_pp_ix - 1]); + //if (prior_row_sign) { log_assert(aligned_pp_ix < aligned_pp.size()); log_assert(x_sz - 1 < (int)(aligned_pp[aligned_pp_ix].size())); aligned_pp[aligned_pp_ix][x_sz - 1] = prior_row_sign; - } + //} } for (int row_ix = aligned_pp_ix - 1; row_ix >= 0; row_ix--) { int shift_amount = get<1>(ppij_int[row_ix]); - RTLIL::Wire *prior_row_sign = nullptr; // copy in data - unsigned copy_ix = shift_amount; + int copy_ix = shift_amount; for (auto w : get<0>(ppij_int[row_ix])) { if (copy_ix < aligned_pp[row_ix].size()) { aligned_pp[row_ix][copy_ix] = w; @@ -786,7 +753,7 @@ struct BoothPassWorker { // the destination of the sign bit is the (row_ix -1)*2 // eg destination for sign bit for row 0 is 0. // eg destination for sign bit for row 1 is 1 - prior_row_sign = get<2>(ppij_int[row_ix - 1]); + SigBit prior_row_sign = get<2>(ppij_int[row_ix - 1]); copy_ix = (row_ix - 1) * 2; aligned_pp[row_ix][copy_ix] = prior_row_sign; } @@ -797,32 +764,23 @@ struct BoothPassWorker { Build a Carry Propagate Adder ----------------------------- First build the sum and carry vectors to be added. - Axioms: - c_vec.size() == s_vec.size() - result.size() == s_vec.size() + 2; (assume result is reserved to hold correct size) */ - void BuildCPA(RTLIL::Module *module, std::vector &s_vec, std::vector &c_vec, RTLIL::Wire *result) + void BuildCPA(RTLIL::Module *module, SigSpec s_vec, SigSpec c_vec, SigSpec result) { - static int cpa_id; cpa_id++; - RTLIL::Wire *carry = nullptr; + log_assert(c_vec.size() == s_vec.size()); + // TODO: doesn't pass + //log_assert(result.size() == s_vec.size() + 2); - log_assert(s_vec.size() == c_vec.size()); - - for (unsigned n = 0; n < s_vec.size(); n++) { + SigBit carry; + for (int n = 0; n < s_vec.size(); n++) { std::string carry_name; // Base Case: Bit 0 is sum 0 if (n == 0) { - std::string buf_name = "base_buf_" + std::to_string(cpa_id) + "_" + std::to_string(n); - auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, s_vec[0]); - buf->setParam(ID::A_WIDTH, 1); - buf->setParam(ID::Y_WIDTH, 1); - buf->setParam(ID::A_SIGNED, false); - buf->setPort(ID::Y, SigSpec(result, 0, 1)); + module->addBufGate(NEW_ID_SUFFIX(stringf("base_buf_%d_%d", cpa_id, n)), s_vec[0], result[0]); #ifdef DEBUG_CPA printf("CPA bit [%d] Cell %s IP 0 %s \n", n, buf->name.c_str(), s_vec[0]->name.c_str()); @@ -835,10 +793,9 @@ struct BoothPassWorker { // else if (n == 1) { std::string ha_name = "cpa_" + std::to_string(cpa_id) + "_ha_" + std::to_string(n); - RTLIL::Wire *ha_op; + SigBit ha_op; BuildHa(ha_name, s_vec[n], c_vec[n - 1], ha_op, carry); - - module->connect(ha_op, SigSpec(result, n, 1)); + module->connect(result[n], ha_op); #ifdef DEBUG_CPA printf("CPA bit [%d] Cell %s IPs [%s] [%s] \n", n, ha_cell->name.c_str(), s_vec[n]->name.c_str(), @@ -847,9 +804,10 @@ struct BoothPassWorker { } // End Case - else if (n == (unsigned)((s_vec.size() - 1))) { + else if (n == s_vec.size() - 1) { // Make the carry results.. Two extra bits after fa. std::string fa_name = "cpa_" + std::to_string(cpa_id) + "_fa_" + std::to_string(n); + auto fa_cell = module->addCell(new_id(fa_name, __LINE__, ""), ID($fa)); fa_cell->setParam(ID::WIDTH, 1); carry_name = "cpa_" + std::to_string(cpa_id) + "carry_" + std::to_string(n); @@ -857,7 +815,7 @@ struct BoothPassWorker { fa_cell->setPort(ID::B, c_vec[n - 1]); fa_cell->setPort(ID::C, carry); // wire in result and carry out - fa_cell->setPort(ID::Y, SigSpec(result, n, 1)); + fa_cell->setPort(ID::Y, result[n]); // make a new carry bit for carry out... carry = module->addWire(new_id(carry_name, __LINE__, ""), 1); @@ -867,16 +825,16 @@ struct BoothPassWorker { printf("CPA bit [%d] Cell %s IPs [%s] [%s] [%s]\n", n, fa_cell->name.c_str(), s_vec[n]->name.c_str(), c_vec[n - 1]->name.c_str(), carry->name.c_str()); #endif - if (n + 1 < (unsigned)(GetSize(result))) { + if (n + 1 < GetSize(result)) { // Now make a half adder: c_vec[n] = carry std::string ha_name = "cpa_" + std::to_string(cpa_id) + "_ha_" + std::to_string(n); - RTLIL::Wire *ha_sum; - RTLIL::Wire *ha_carry; + SigBit ha_sum; + SigBit ha_carry; BuildHa(ha_name, c_vec[n], carry, ha_sum, ha_carry); - if (n + 1 < (unsigned)GetSize(result)) - module->connect(ha_sum, SigSpec(result, n + 1, 1)); - if (n + 2 < (unsigned)GetSize(result)) - module->connect(ha_carry, SigSpec(result, n + 2, 1)); + if (n + 1 < GetSize(result)) + module->connect(result[n + 1], ha_sum); + if (n + 2 < GetSize(result)) + module->connect(result[n + 2], ha_carry); } } // Step case @@ -890,7 +848,7 @@ struct BoothPassWorker { fa_cell->setPort(ID::B, c_vec[n - 1]); fa_cell->setPort(ID::C, carry); // wire in result and carry out - fa_cell->setPort(ID::Y, SigSpec(result, n, 1)); + fa_cell->setPort(ID::Y, result[n]); // make a new carry bit for carry out... carry = module->addWire(new_id(carry_name, __LINE__, ""), 1); fa_cell->setPort(ID::X, carry); @@ -907,8 +865,8 @@ struct BoothPassWorker { // Pass the carry bits from each csa to the next // column for summation. - void ReduceBits(RTLIL::Module *module, int column_ix, std::vector &column_bits, RTLIL::Wire *&s_result, RTLIL::Wire *&c_result, - std::vector &carry_bits_to_sum, std::vector> &debug_csa_trees) + void ReduceBits(RTLIL::Module *module, int column_ix, SigSpec column_bits, SigBit &s_result, SigBit &c_result, + SigSpec &carry_bits_to_sum, std::vector> &debug_csa_trees) { int csa_ix = 0; @@ -918,12 +876,12 @@ struct BoothPassWorker { unique_id++; if (column_size > 0) { - unsigned var_ix = 0; - std::vector first_csa_ips; + int var_ix = 0; + SigSpec first_csa_ips; // get the first 3 inputs, if possible for (var_ix = 0; var_ix < column_bits.size() && first_csa_ips.size() != 3; var_ix++) { - if (column_bits[var_ix]) - first_csa_ips.push_back(column_bits[var_ix]); + if (column_bits[var_ix].is_wire()) + first_csa_ips.append(column_bits[var_ix]); } if (first_csa_ips.size() > 0) { @@ -961,16 +919,16 @@ struct BoothPassWorker { c_result = c_wire; if (var_ix <= column_bits.size() - 1) - carry_bits_to_sum.push_back(c_wire); + carry_bits_to_sum.append(c_wire); // Now build the rest of the tree if we can while (var_ix <= column_bits.size() - 1) { - std::vector csa_ips; + SigSpec csa_ips; // get the next two variables to sum for (; var_ix <= column_bits.size() - 1 && csa_ips.size() < 2;) { // skip any empty bits - if (column_bits[var_ix] != nullptr) - csa_ips.push_back(column_bits[var_ix]); + if (column_bits[var_ix].is_wire()) + csa_ips.append(column_bits[var_ix]); var_ix++; } @@ -993,7 +951,7 @@ struct BoothPassWorker { c_wire = module->addWire(new_id(carry_wire_name, __LINE__, ""), 1); if (var_ix <= column_bits.size() - 1) - carry_bits_to_sum.push_back(c_wire); + carry_bits_to_sum.append(c_wire); sum_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_s"; s_wire = module->addWire(new_id(sum_wire_name, __LINE__, ""), 1); @@ -1009,28 +967,30 @@ struct BoothPassWorker { } } - void BuildBoothUMultEncoders(RTLIL::Wire *Y, int y_sz, std::vector &one_int, std::vector &two_int, - std::vector &s_int, std::vector &sb_int, RTLIL::Module *module, int &encoder_ix) + void BuildBoothUMultEncoders(SigSpec Y, SigSpec &one_int, SigSpec &two_int, + SigSpec &s_int, SigSpec &sb_int, RTLIL::Module *module, int &encoder_ix) { + int y_sz = GetSize(Y); + for (int y_ix = 0; y_ix < y_sz;) { std::string enc_name = "bur_enc_" + std::to_string(encoder_ix) + "_"; std::string two_name = "two_int" + std::to_string(encoder_ix); - two_int.push_back(module->addWire(new_id(two_name, __LINE__, ""), 1)); + two_int.append(module->addWire(new_id(two_name, __LINE__, ""), 1)); std::string one_name = "one_int" + std::to_string(encoder_ix); - one_int.push_back(module->addWire(new_id(one_name, __LINE__, ""), 1)); + one_int.append(module->addWire(new_id(one_name, __LINE__, ""), 1)); std::string s_name = "s_int" + std::to_string(encoder_ix); - s_int.push_back(module->addWire(new_id(s_name, __LINE__, ""), 1)); + s_int.append(module->addWire(new_id(s_name, __LINE__, ""), 1)); std::string sb_name = "sb_int" + std::to_string(encoder_ix); - sb_int.push_back(module->addWire(new_id(sb_name, __LINE__, ""), 1)); + sb_int.append(module->addWire(new_id(sb_name, __LINE__, ""), 1)); if (y_ix == 0) { - BuildBur4e(enc_name, mk_wireFromSigSpec(State::S0), mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)), - mk_wireFromSigSpec(SigSpec(Y, y_ix + 1, 1)), one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], + BuildBur4e(enc_name, State::S0, Y[y_ix], + Y[y_ix + 1], one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], sb_int[encoder_ix]); y_ix = y_ix + 1; @@ -1041,39 +1001,37 @@ struct BoothPassWorker { // then add an extra booth encoder bounded by // zeroes to ensure unsigned works. // - RTLIL::Wire *y0_wire; - RTLIL::Wire *y1_wire; - RTLIL::Wire *y2_wire; + SigBit y0, y1, y2; bool need_padded_cell = false; if (y_ix > y_sz - 1) { - y0_wire = mk_wireFromSigSpec(SigSpec(Y, State::S0)); + y0 = State::S0; need_padded_cell = false; } else { - y0_wire = mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)); + y0 = Y[y_ix]; y_ix++; } if (y_ix > y_sz - 1) { need_padded_cell = false; - y1_wire = mk_wireFromSigSpec(SigSpec(Y, State::S0)); + y1 = State::S0; } else { - y1_wire = mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)); + y1 = Y[y_ix]; y_ix++; } if (y_ix > y_sz - 1) { need_padded_cell = false; - y2_wire = mk_wireFromSigSpec(SigSpec(Y, State::S0)); + y2 = State::S0; } else { if (y_ix == y_sz - 1) need_padded_cell = true; else need_padded_cell = false; - y2_wire = mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)); + y2 = Y[y_ix]; - BuildBur4e(enc_name, y0_wire, y1_wire, y2_wire, one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], + BuildBur4e(enc_name, y0, y1, y2, one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], sb_int[encoder_ix]); } @@ -1087,25 +1045,25 @@ struct BoothPassWorker { std::string enc_name = "br_enc_pad" + std::to_string(encoder_ix) + "_"; std::string two_name = "two_int" + std::to_string(encoder_ix); - two_int.push_back(module->addWire(new_id(two_name, __LINE__, ""), 1)); + two_int.append(module->addWire(new_id(two_name, __LINE__, ""), 1)); std::string one_name = "one_int" + std::to_string(encoder_ix); - one_int.push_back(module->addWire(new_id(two_name, __LINE__, ""), 1)); + one_int.append(module->addWire(new_id(two_name, __LINE__, ""), 1)); std::string s_name = "s_int" + std::to_string(encoder_ix); - s_int.push_back(module->addWire(new_id(s_name, __LINE__, ""), 1)); + s_int.append(module->addWire(new_id(s_name, __LINE__, ""), 1)); std::string sb_name = "sb_int" + std::to_string(encoder_ix); - sb_int.push_back(module->addWire(new_id(sb_name, __LINE__, ""), 1)); + sb_int.append(module->addWire(new_id(sb_name, __LINE__, ""), 1)); - RTLIL::Wire *one_o_int, *two_o_int, *s_o_int, *sb_o_int; - BuildBur4e(enc_name, mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)), mk_wireFromSigSpec(State::S0), - mk_wireFromSigSpec(State::S0), one_o_int, two_o_int, s_o_int, sb_o_int); + SigBit one_o_int, two_o_int, s_o_int, sb_o_int; + BuildBur4e(enc_name, Y[y_ix], State::S0, + State::S0, one_o_int, two_o_int, s_o_int, sb_o_int); - join_wires_with_buffer(one_o_int, one_int[encoder_ix]); - join_wires_with_buffer(two_o_int, two_int[encoder_ix]); - join_wires_with_buffer(s_o_int, s_int[encoder_ix]); - join_wires_with_buffer(sb_o_int, sb_int[encoder_ix]); + module->connect(one_int[encoder_ix], one_o_int); + module->connect(two_int[encoder_ix], two_o_int); + module->connect(s_int[encoder_ix], s_o_int); + module->connect(sb_int[encoder_ix], sb_o_int); y_ix++; encoder_ix++; } @@ -1116,8 +1074,10 @@ struct BoothPassWorker { /* Signed Multiplier */ - void CreateBoothSMult(RTLIL::Module *module, int x_sz, int y_sz, int z_sz, RTLIL::Wire *X, RTLIL::Wire *Y, RTLIL::Wire *Z) + void CreateBoothSMult(RTLIL::Module *module, SigSpec X, SigSpec Y, SigSpec Z) { // product + int x_sz = X.size(), y_sz = Y.size(), z_sz = Z.size(); + unsigned enc_count = (y_sz / 2) + (((y_sz % 2) != 0) ? 1 : 0); int dec_count = x_sz + 1; @@ -1128,10 +1088,12 @@ struct BoothPassWorker { "Result of size %d. %d encoders %d decoders\n", x_sz, y_sz, z_sz, enc_count, dec_count); - RTLIL::Wire **negi_n_int = new RTLIL::Wire *[enc_count]; - RTLIL::Wire **twoi_n_int = new RTLIL::Wire *[enc_count]; - RTLIL::Wire **onei_n_int = new RTLIL::Wire *[enc_count]; - RTLIL::Wire **cori_n_int = new RTLIL::Wire *[enc_count]; + SigSpec negi_n_int, twoi_n_int, onei_n_int, cori_n_int; + + negi_n_int.extend_u0(enc_count); + twoi_n_int.extend_u0(enc_count); + onei_n_int.extend_u0(enc_count); + cori_n_int.extend_u0(enc_count); for (unsigned encoder_ix = 1; encoder_ix <= enc_count; encoder_ix++) { std::string enc_name = "enc_" + std::to_string(encoder_ix) + "_"; @@ -1146,38 +1108,34 @@ struct BoothPassWorker { if (encoder_ix == 1) { - BuildBr4e(enc_name, mk_wireFromSigSpec(SigSpec(State::S0)), mk_wireFromSigSpec(SigSpec(Y, 0, 1)), - mk_wireFromSigSpec(SigSpec(Y, 1, 1)), - + BuildBr4e(enc_name, State::S0, Y[0], Y[1], negi_n_int[encoder_ix - 1], twoi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], cori_n_int[encoder_ix - 1]); } else { - RTLIL::Wire *y1_wire; - RTLIL::Wire *y2_wire; - RTLIL::Wire *y3_wire; + SigBit y1, y2, y3; + + y1 = Y[(encoder_ix - 1) * 2 - 1]; - y1_wire = mk_wireFromSigSpec(SigSpec(Y, ((encoder_ix - 1) * 2 - 1), 1)); //-1 if ((encoder_ix - 1) * 2 >= (unsigned)y_sz) - y2_wire = mk_wireFromSigSpec(SigSpec(State::S0)); // constant 0 + y2 = State::S0; // constant 0 else - y2_wire = mk_wireFromSigSpec(SigSpec(Y, ((encoder_ix - 1) * 2), 1)); // 0 + y2 = Y[(encoder_ix - 1) * 2]; // 0 if (((encoder_ix - 1) * 2 + 1) >= (unsigned)y_sz) - y3_wire = mk_wireFromSigSpec(SigSpec(State::S0)); // constant 0 + y3 = State::S0; // constant 0 else - y3_wire = mk_wireFromSigSpec(SigSpec(Y, ((encoder_ix - 1) * 2 + 1), 1)); //+1 - - BuildBr4e(enc_name, y1_wire, y2_wire, y3_wire, + y3 = Y[(encoder_ix - 1) * 2 + 1]; //+1 + BuildBr4e(enc_name, y1, y2, y3, negi_n_int[encoder_ix - 1], twoi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], cori_n_int[encoder_ix - 1]); } } // Decoders and PP generation - RTLIL::Wire **PPij = new RTLIL::Wire *[enc_count * dec_count]; - RTLIL::Wire **nxj = new RTLIL::Wire *[enc_count * dec_count]; + SigSpec PPij(State::S0, enc_count * dec_count); + SigSpec nxj(State::S0, enc_count * dec_count); for (int encoder_ix = 1; encoder_ix <= (int)enc_count; encoder_ix++) { for (int decoder_ix = 1; decoder_ix <= dec_count; decoder_ix++) { @@ -1220,16 +1178,16 @@ struct BoothPassWorker { std::string dec_name = "dec_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; BuildBr4d(dec_name, nxj[((encoder_ix - 1) * dec_count) + decoder_ix - 1], twoi_n_int[encoder_ix - 1], - mk_wireFromSigSpec(SigSpec(X, decoder_ix - 1, 1)), negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], + X[decoder_ix - 1], negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], PPij[((encoder_ix - 1) * dec_count) + decoder_ix - 1], nxj[((encoder_ix - 1) * dec_count) + decoder_ix]); } // duplicate end for sign fix // applies to 9th decoder (xsz+1 decoder). std::string dec_name = "dec_" + std::to_string(encoder_ix) + "_" + std::to_string(x_sz + 1) + "_"; - RTLIL::Wire *unused_op = nullptr; + SigBit unused_op; BuildBr4d(dec_name, nxj[((encoder_ix - 1) * dec_count) + dec_count - 1], twoi_n_int[encoder_ix - 1], - mk_wireFromSigSpec(SigSpec(X, dec_count - 2, 1)), negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], + X[dec_count - 2], negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], PPij[((encoder_ix - 1) * dec_count) + dec_count - 1], unused_op); } @@ -1239,8 +1197,8 @@ struct BoothPassWorker { int fa_el_ix = 0; int fa_row_ix = 0; // use 1 d arrays (2d cannot have variable sized indices) - RTLIL::Wire **fa_sum_n = new RTLIL::Wire *[fa_row_count * fa_count]; - RTLIL::Wire **fa_carry_n = new RTLIL::Wire *[fa_row_count * fa_count]; + SigSpec fa_sum_n(State::S0, fa_row_count * fa_count); + SigSpec fa_carry_n(State::S0, fa_row_count * fa_count); for (fa_row_ix = 0; fa_row_ix < fa_row_count; fa_row_ix++) { for (fa_el_ix = 0; fa_el_ix < fa_count; fa_el_ix++) { @@ -1416,11 +1374,11 @@ struct BoothPassWorker { } // instantiate the cpa - RTLIL::Wire **cpa_carry = new RTLIL::Wire *[z_sz]; + SigSpec cpa_carry; for (int cix = 0; cix < z_sz; cix++) { std::string cpa_cix_name = "cpa_carry_" + std::to_string(cix) + "_"; - cpa_carry[cix] = module->addWire(new_id(cpa_cix_name, __LINE__, ""), 1); + cpa_carry.append(module->addWire(new_id(cpa_cix_name, __LINE__, ""), 1)); } for (int cpa_ix = 0; cpa_ix < z_sz; cpa_ix++) { @@ -1439,7 +1397,7 @@ struct BoothPassWorker { buf->setParam(ID::A_WIDTH, 1); buf->setParam(ID::Y_WIDTH, 1); buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, SigSpec(Z, cpa_ix, 1)); + buf->setPort(ID::Y, Z[cpa_ix]); cpa_ix++; buf_name = "pp_buf_" + std::to_string(cpa_ix) + "_" + "driven_by_fa_row_" + std::to_string(fa_row_ix) + "_"; @@ -1448,22 +1406,22 @@ struct BoothPassWorker { buf->setParam(ID::A_WIDTH, 1); buf->setParam(ID::Y_WIDTH, 1); buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, SigSpec(Z, cpa_ix, 1)); + buf->setPort(ID::Y, Z[cpa_ix]); } else { int offset = fa_row_count * 2; bool base_case = cpa_ix - offset == 0 ? true : false; std::string cpa_name = "cpa_" + std::to_string(cpa_ix - offset) + "_"; - RTLIL::Wire *ci_wire; + SigBit ci; if (base_case) - ci_wire = cori_n_int[enc_count - 1]; + ci = cori_n_int[enc_count - 1]; else - ci_wire = cpa_carry[cpa_ix - offset - 1]; + ci = cpa_carry[cpa_ix - offset - 1]; - RTLIL::Wire *op_wire = module->addWire(NEW_ID, 1); - BuildHa(cpa_name, fa_sum_n[(fa_row_count - 1) * fa_count + cpa_ix - offset + 2], ci_wire, op_wire, + SigBit op; + BuildHa(cpa_name, fa_sum_n[(fa_row_count - 1) * fa_count + cpa_ix - offset + 2], ci, op, cpa_carry[cpa_ix - offset]); - module->connect(op_wire, SigSpec(Z, cpa_ix, 1)); + module->connect(Z[cpa_ix], op); } } @@ -1473,35 +1431,23 @@ struct BoothPassWorker { // std::string q1_name = "icb_booth_q1_"; - RTLIL::Wire *pp0_o_int; - RTLIL::Wire *pp1_o_int; - RTLIL::Wire *nxj_o_int; - RTLIL::Wire *cor_o_int; + SigBit pp0_o_int; + SigBit pp1_o_int; + SigBit nxj_o_int; + SigBit cor_o_int; BuildBoothQ1(q1_name, negi_n_int[0], // negi cori_n_int[0], // cori - mk_wireFromSigSpec(SigSpec(X, 0, 1)), // x0 - mk_wireFromSigSpec(SigSpec(X, 1, 1)), // x1 - mk_wireFromSigSpec(SigSpec(Y, 0, 1)), // y0 - mk_wireFromSigSpec(SigSpec(Y, 1, 1)), // y1 + X[0], X[1], Y[0], Y[1], nxj_o_int, cor_o_int, pp0_o_int, pp1_o_int); - join_wires_with_buffer(pp0_o_int, fa_sum_n[(0 * fa_count) + 0]); - join_wires_with_buffer(pp1_o_int, fa_sum_n[(0 * fa_count) + 1]); - join_wires_with_buffer(cor_o_int, fa_carry_n[(0 * fa_count) + 1]); - join_wires_with_buffer(nxj_o_int, nxj[(0 * dec_count) + 2]); - - delete[] negi_n_int; - delete[] twoi_n_int; - delete[] onei_n_int; - delete[] cori_n_int; - - delete[] fa_sum_n; - delete[] fa_carry_n; - delete[] cpa_carry; + module->connect(fa_sum_n[(0 * fa_count) + 0], pp0_o_int); + module->connect(fa_sum_n[(0 * fa_count) + 1], pp1_o_int); + module->connect(fa_carry_n[(0 * fa_count) + 1], cor_o_int); + module->connect(nxj[(0 * dec_count) + 2], nxj_o_int); } }; From cb05262fc4098507e7be1fd52fe666a606687f90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 19 Sep 2023 13:06:05 +0200 Subject: [PATCH 14/95] booth: Remove now-unused helpers --- passes/techmap/booth.cc | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index fe9c1cec6..2713d3395 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -66,33 +66,6 @@ struct BoothPassWorker { BoothPassWorker(RTLIL::Module *module) : module(module), sigmap(module) { booth_counter = 0; } - // Helper routines for building architecture subcomponents - - RTLIL::Wire *mk_wireFromSigSpec(const SigSpec &v) - { - - auto g = module->addCell(NEW_ID, ID($pos)); - Wire *ret = module->addWire(NEW_ID, 1); - g->setPort(ID::A, v); - g->setPort(ID::Y, ret); - g->setParam(ID::A_WIDTH, 1); - g->setParam(ID::Y_WIDTH, 1); - g->setParam(ID::A_SIGNED, false); - return ret; - } - - // fuse wires. - void join_wires_with_buffer(RTLIL::Wire *ip, RTLIL::Wire *op) - { - std::string wire_name = "join_"; - auto g = module->addCell(new_id(wire_name, __LINE__, ""), ID($pos)); - g->setParam(ID::A_WIDTH, 1); - g->setParam(ID::Y_WIDTH, 1); - g->setParam(ID::A_SIGNED, false); - g->setPort(ID::A, ip); - g->setPort(ID::Y, op); - } - // Unary gate RTLIL::Wire *mk_ugate1(const RTLIL::IdString &red_typ, std::string &name, SigBit ip1, std::string &op_name) { From 986507f95fa69c7b35960750f583f49e672062d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 19 Sep 2023 15:48:23 +0200 Subject: [PATCH 15/95] booth: Streamline the low-level circuit emission For the basic single-bit operations, opt for gate cells (`$_AND_` etc.) instead of the coarse cells (`$and` etc.). For the emission of cells move to the conventional module methods (`module->addAndGate`) away from the local helpers. While at it, touch on the surrounding code. --- passes/techmap/booth.cc | 149 +++++++++++++++------------------------- 1 file changed, 57 insertions(+), 92 deletions(-) diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index 2713d3395..64a924e4f 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -108,98 +108,88 @@ struct BoothPassWorker { } // Booth unsigned decoder lsb - void BuildBur4d_lsb(std::string &name, SigBit lsb_i, SigBit one_i, SigBit s_i, SigBit &ppij_o, - std::string op_wire_name) + SigBit Bur4d_lsb(std::string name, SigBit lsb_i, SigBit one_i, SigBit s_i) { - std::string empty; - auto and_op = mk_ugate2(ID($and), name, lsb_i, one_i, empty); - ppij_o = mk_ugate2(ID($xor), name, and_op, s_i, op_wire_name); + SigBit and_op = module->AndGate(NEW_ID_SUFFIX(name), lsb_i, one_i); + return module->XorGate(NEW_ID_SUFFIX(name), and_op, s_i); } // Booth unsigned radix4 decoder - void BuildBur4d_n(std::string &name, SigBit yn_i, SigBit ynm1_i, SigBit one_i, SigBit two_i, SigBit s_i, - SigBit &ppij_o) + SigBit Bur4d_n(std::string name, SigBit yn_i, SigBit ynm1_i, SigBit one_i, SigBit two_i, SigBit s_i) { // ppij = ((yn & one) | (ynm1 & two)) ^ s; - std::string empty; - auto an1 = mk_ugate2(ID($and), name, yn_i, one_i, empty); - auto an2 = mk_ugate2(ID($and), name, ynm1_i, two_i, empty); - auto or1 = mk_ugate2(ID($or), name, an1, an2, empty); - ppij_o = mk_ugate2(ID($xor), name, s_i, or1, empty); + SigBit an1 = module->AndGate(NEW_ID_SUFFIX(name), yn_i, one_i); + SigBit an2 = module->AndGate(NEW_ID_SUFFIX(name), ynm1_i, two_i); + SigBit or1 = module->OrGate(NEW_ID_SUFFIX(name), an1, an2); + return module->XorGate(NEW_ID_SUFFIX(name), s_i, or1); } // Booth unsigned radix4 decoder - void BuildBur4d_msb(std::string &name, SigBit msb_i, SigBit two_i, SigBit s_i, SigBit &ppij_o) + SigBit Bur4d_msb(std::string name, SigBit msb_i, SigBit two_i, SigBit s_i) { // ppij = (msb & two) ^ s; - std::string empty; - auto an1 = mk_ugate2(ID($and), name, msb_i, two_i, empty); - ppij_o = mk_ugate2(ID($xor), name, s_i, an1, empty); + SigBit an1 = module->AndGate(NEW_ID_SUFFIX(name), msb_i, two_i); + return module->XorGate(NEW_ID_SUFFIX(name), s_i, an1); } // half adder, used in CPA - void BuildHa(std::string &name, SigBit a_i, SigBit b_i, SigBit &s_o, SigBit &c_o) + void BuildHa(std::string name, SigBit a_i, SigBit b_i, SigBit &s_o, SigBit &c_o) { - std::string empty; - s_o = mk_ugate2(ID($xor), name, a_i, b_i, empty); - c_o = mk_ugate2(ID($and), name, a_i, b_i, empty); + s_o = module->XorGate(NEW_ID_SUFFIX(name), a_i, b_i); + c_o = module->AndGate(NEW_ID_SUFFIX(name), a_i, b_i); } // Booth unsigned radix 4 encoder - void BuildBur4e(std::string &name, SigBit y0_i, SigBit y1_i, SigBit y2_i, + void BuildBur4e(std::string name, SigBit y0_i, SigBit y1_i, SigBit y2_i, SigBit &one_o, SigBit &two_o, SigBit &s_o, SigBit &sb_o) { - - std::string empty; - one_o = mk_ugate2(ID($xor), name, y0_i, y1_i, empty); + one_o = module->XorGate(NEW_ID_SUFFIX(name), y0_i, y1_i); s_o = y2_i; - sb_o = mk_ugate1(ID($not), name, y2_i, empty); - auto inv_y1_xor_y2 = mk_ugate1(ID($not), name, mk_ugate2(ID($xor), name, y1_i, y2_i, empty), empty); - two_o = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, inv_y1_xor_y2, one_o, empty), empty); + sb_o = module->NotGate(NEW_ID_SUFFIX(name), y2_i); + SigBit y1_xnor_y2 = module->XnorGate(NEW_ID_SUFFIX(name), y1_i, y2_i); + two_o = module->NorGate(NEW_ID_SUFFIX(name), y1_xnor_y2, one_o); } - void BuildBr4e(std::string &name, SigBit y2_m1_i, + void BuildBr4e(std::string name, SigBit y2_m1_i, SigBit y2_i, // y2i SigBit y2_p1_i, SigBit &negi_o, SigBit &twoi_n_o, SigBit &onei_n_o, SigBit &cori_o) { + auto y2_p1_n = module->NotGate(NEW_ID_SUFFIX(name), y2_p1_i); + auto y2_n = module->NotGate(NEW_ID_SUFFIX(name), y2_i); + auto y2_m1_n = module->NotGate(NEW_ID_SUFFIX(name), y2_m1_i); - std::string empty; - auto y2_p1_n = mk_ugate1(ID($not), name, y2_p1_i, empty); - auto y2_n = mk_ugate1(ID($not), name, y2_i, empty); - auto y2_m1_n = mk_ugate1(ID($not), name, y2_m1_i, empty); + negi_o = y2_p1_i; - // negi_o = y2_p1_i - negi_o = mk_ugate1(ID($pos), name, y2_p1_i, empty); // twoi_n = ~( // (y2_p1_n & y2_i & y2_m1_i) | // (y2_p1 & y2_n & y2_m1_n) // ) - auto and3_1 = mk_ugate2(ID($and), name, y2_p1_n, mk_ugate2(ID($and), name, y2_i, y2_m1_i, empty), empty); - auto and3_2 = mk_ugate2(ID($and), name, y2_p1_i, mk_ugate2(ID($and), name, y2_n, y2_m1_n, empty), empty); + twoi_n_o = module->NorGate(NEW_ID_SUFFIX(name), + module->AndGate(NEW_ID_SUFFIX(name), y2_p1_n, module->AndGate(NEW_ID_SUFFIX(name), y2_i, y2_m1_i)), + module->AndGate(NEW_ID_SUFFIX(name), y2_p1_i, module->AndGate(NEW_ID_SUFFIX(name), y2_n, y2_m1_n)) + ); - twoi_n_o = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, and3_1, and3_2, empty), empty); // onei_n = ~(y2_m1_i ^ y2_i); - onei_n_o = mk_ugate1(ID($not), name, mk_ugate2(ID($xor), name, y2_m1_i, y2_i, empty), empty); + onei_n_o = module->XnorGate(NEW_ID_SUFFIX(name), y2_m1_i, y2_i); // cori = (y2_m1_n | y2_n) & y2_p1_i; - cori_o = mk_ugate2(ID($and), name, y2_p1_i, mk_ugate2(ID($or), name, y2_m1_n, y2_n, empty), empty); + cori_o = module->AndGate(NEW_ID_SUFFIX(name), module->OrGate(NEW_ID_SUFFIX(name), y2_m1_n, y2_n), y2_p1_i); } // // signed booth radix 4 decoder // - void BuildBr4d(std::string &name, SigBit nxj_m1_i, SigBit twoi_n_i, SigBit xj_i, SigBit negi_i, SigBit onei_n_i, + void BuildBr4d(std::string name, SigBit nxj_m1_i, SigBit twoi_n_i, SigBit xj_i, SigBit negi_i, SigBit onei_n_i, SigBit &ppij_o, SigBit &nxj_o) { - - std::string empty; // nxj_in = xnor(xj,negi) // nxj_o = xnj_in, // ppij = ~( (nxj_m1_i | twoi_n_i) & (nxj_int | onei_n_i)); - nxj_o = mk_ugate2(ID($xnor), name, xj_i, negi_i, empty); - SigBit or1 = mk_ugate2(ID($or), name, nxj_m1_i, twoi_n_i, empty); - SigBit or2 = mk_ugate2(ID($or), name, nxj_o, onei_n_i, empty); - ppij_o = mk_ugate1(ID($not), name, mk_ugate2(ID($and), name, or1, or2, empty), empty); + nxj_o = module->XnorGate(NEW_ID_SUFFIX(name), xj_i, negi_i); + ppij_o = module->NandGate(NEW_ID_SUFFIX(name), + module->OrGate(NEW_ID_SUFFIX(name), nxj_m1_i, twoi_n_i), + module->OrGate(NEW_ID_SUFFIX(name), nxj_o, onei_n_i) + ); } /* @@ -207,7 +197,7 @@ struct BoothPassWorker { using non-booth encoded logic. We can save a booth encoder for the first couple of bits. */ - void BuildBoothQ1(std::string &name, SigBit negi_i, SigBit cori_i, SigBit x0_i, SigBit x1_i, SigBit y0_i, + void BuildBoothQ1(std::string name, SigBit negi_i, SigBit cori_i, SigBit x0_i, SigBit x1_i, SigBit y0_i, SigBit y1_i, SigBit &nxj_o, SigBit &cor_o, SigBit &pp0_o, SigBit &pp1_o) { @@ -222,15 +212,14 @@ struct BoothPassWorker { //correction propagation assign CORO = (~PP1 & ~PP0)? CORI : 1'b0; */ - std::string empty; - nxj_o = mk_ugate2(ID($xnor), name, x1_i, negi_i, empty); - pp0_o = mk_ugate2(ID($and), name, x0_i, y0_i, empty); - SigBit pp1_1_int = mk_ugate2(ID($and), name, x1_i, y0_i, empty); - SigBit pp1_2_int = mk_ugate2(ID($and), name, x0_i, y1_i, empty); - pp1_o = mk_ugate2(ID($xor), name, pp1_1_int, pp1_2_int, empty); + nxj_o = module->XnorGate(NEW_ID_SUFFIX(name), x1_i, negi_i); + pp0_o = module->AndGate(NEW_ID_SUFFIX(name), x0_i, y0_i); + SigBit pp1_1_int = module->AndGate(NEW_ID_SUFFIX(name), x1_i, y0_i); + SigBit pp1_2_int = module->AndGate(NEW_ID_SUFFIX(name), x0_i, y1_i); + pp1_o = module->XorGate(NEW_ID_SUFFIX(name), pp1_1_int, pp1_2_int); - SigBit pp1_nor_pp0 = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, pp1_o, pp0_o, empty), empty); - cor_o = mk_ugate2(ID($and), name, pp1_nor_pp0, cori_i, empty); + SigBit pp1_nor_pp0 = module->NorGate(NEW_ID_SUFFIX(name), pp1_o, pp0_o); + cor_o = module->AndGate(NEW_ID_SUFFIX(name), pp1_nor_pp0, cori_i); } void run() @@ -454,28 +443,18 @@ struct BoothPassWorker { { (void)module; int x_sz = GetSize(X); + SigBit ppij; // lsb - std::string dec_name = "row0_lsb_dec"; - - SigBit ppij; - std::string ppij_name = "ppij_0_0"; - BuildBur4d_lsb(dec_name, X[0], one_int[0], s_int[0], ppij, ppij_name); - ppij_vec.append(ppij); + ppij_vec.append(Bur4d_lsb("row0_lsb_dec", X[0], one_int[0], s_int[0])); // 1..xsize -1 - for (int i = 1; i < x_sz; i++) { - dec_name = "row0_dec_" + std::to_string(i); - SigBit ppij; - BuildBur4d_n(dec_name, X[i], X[i - 1], one_int[0], two_int[0], - s_int[0], ppij); - ppij_vec.append(ppij); - } + for (int i = 1; i < x_sz; i++) + ppij_vec.append(Bur4d_n(stringf("row0_dec_%d", i), X[i], X[i - 1], + one_int[0], two_int[0], s_int[0])); // The redundant bit. Duplicate decoding of last bit. - dec_name = "row0_dec_msb"; - BuildBur4d_msb(dec_name, X[x_sz - 1], two_int[0], s_int[0], ppij); - ppij_vec.append(ppij); + ppij_vec.append(Bur4d_msb("row0_dec_msb", X[x_sz - 1], two_int[0], s_int[0])); // append the sign bits ppij_vec.append(s_int[0]); @@ -494,37 +473,23 @@ struct BoothPassWorker { int x_sz = GetSize(X); // lsb - std::string ppij_name = "ppij_" + std::to_string(row_ix) + "_0"; - SigBit ppij; - std::string empty; - std::string dec_name = "row" + std::to_string(row_ix) + "_lsb_dec"; - BuildBur4d_lsb(dec_name, X[0], one_int, s_int, ppij, empty); - - ppij_vec.append(ppij); + ppij_vec.append(Bur4d_lsb(stringf("row_%d_lsb_dec", row_ix), X[0], one_int, s_int)); // core bits - for (int i = 1; i < x_sz; i++) { - - dec_name = "row_" + std::to_string(row_ix) + "_dec_" + std::to_string(i); - BuildBur4d_n(dec_name, X[i], X[i - 1], - one_int, two_int, s_int, ppij); - ppij_vec.append(ppij); - } + for (int i = 1; i < x_sz; i++) + ppij_vec.append(Bur4d_n(stringf("row_%d_dec_%d", row_ix, i), X[i], X[i - 1], + one_int, two_int, s_int)); // redundant bit - - dec_name = "row_dec_red"; - BuildBur4d_msb(dec_name, X[x_sz - 1], two_int, s_int, ppij); - ppij_vec.append(ppij); + ppij_vec.append(Bur4d_msb("row_dec_red", X[x_sz - 1], two_int, s_int)); // sign bit - if (no_sign == false) // if no sign is false then make a sign bit + if (!no_sign) // if no sign is false then make a sign bit ppij_vec.append(sb_int); // constant bit - if (no_constant == false) { // if non constant is false make a constant bit + if (!no_constant) // if non constant is false make a constant bit ppij_vec.append(State::S1); - } } void DebugDumpAlignPP(std::vector> &aligned_pp) From 30f8387b75f205ff360292bcd2459191daed9a66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 19 Sep 2023 16:25:10 +0200 Subject: [PATCH 16/95] booth: Rewrite the main cell selection loop --- passes/techmap/booth.cc | 170 ++++++++++++++++++---------------------- 1 file changed, 77 insertions(+), 93 deletions(-) diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index 64a924e4f..df0f82ec2 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -225,108 +225,92 @@ struct BoothPassWorker { void run() { for (auto cell : module->selected_cells()) { - if (cell->type.in(ID($mul))) { - RTLIL::SigSpec A = sigmap(cell->getPort(ID::A)); - RTLIL::SigSpec B = sigmap(cell->getPort(ID::B)); - RTLIL::SigSpec Y = sigmap(cell->getPort(ID::Y)); - if (GetSize(A) >= 4 && GetSize(B) >= 4 && GetSize(Y) >= 8 && - ((cell->getParam(ID::A_SIGNED).as_bool() && cell->getParam(ID::B_SIGNED).as_bool()) || - (!cell->getParam(ID::A_SIGNED).as_bool() && !cell->getParam(ID::B_SIGNED).as_bool()))) { - bool is_signed = false; - if (cell->getParam(ID::A_SIGNED).as_bool()) { - log(" By passing macc inferencing for signed multiplier -- generating booth\n"); - is_signed = true; - } else - log(" By passing macc inferencing for unsigned multiplier -- generating booth\n"); + if (cell->type != ID($mul)) + continue; - int x_sz = GetSize(A); - int y_sz = GetSize(B); - int z_sz = GetSize(Y); + SigSpec A = cell->getPort(ID::A); + SigSpec B = cell->getPort(ID::B); + SigSpec Y = cell->getPort(ID::Y); + int x_sz = GetSize(A), y_sz = GetSize(B), z_sz = GetSize(Y); - // To simplify the generator size the arguments - // to be the same. Then allow logic synthesis to - // clean things up. Size to biggest + if (x_sz < 4 || y_sz < 4 || z_sz < 8) { + log_debug("Not mapping cell %s sized at %dx%x, %x: size below threshold\n", + log_id(cell), x_sz, y_sz, z_sz); + continue; + } - int x_sz_revised = x_sz; - int y_sz_revised = y_sz; + log_assert(cell->getParam(ID::A_SIGNED).as_bool() == cell->getParam(ID::B_SIGNED).as_bool()); + bool is_signed = cell->getParam(ID::A_SIGNED).as_bool(); - if (x_sz != y_sz) { - if (x_sz < y_sz) { - if (y_sz % 2 != 0) { - x_sz_revised = y_sz + 1; - y_sz_revised = y_sz + 1; - } else - x_sz_revised = y_sz; + log("Mapping cell %s to %s Booth multiplier\n", log_id(cell), is_signed ? "signed" : "unsigned"); - } else { - if (x_sz % 2 != 0) { - y_sz_revised = x_sz + 1; - x_sz_revised = x_sz + 1; - } else - y_sz_revised = x_sz; - } + // To simplify the generator size the arguments + // to be the same. Then allow logic synthesis to + // clean things up. Size to biggest + + int x_sz_revised = x_sz; + int y_sz_revised = y_sz; + + if (x_sz != y_sz) { + if (x_sz < y_sz) { + if (y_sz % 2 != 0) { + x_sz_revised = y_sz + 1; + y_sz_revised = y_sz + 1; } else { - if (x_sz % 2 != 0) { - y_sz_revised = y_sz + 1; - x_sz_revised = x_sz + 1; - } + x_sz_revised = y_sz; + } + } else { + if (x_sz % 2 != 0) { + y_sz_revised = x_sz + 1; + x_sz_revised = x_sz + 1; + } else { + y_sz_revised = x_sz; } - - log_assert((x_sz_revised == y_sz_revised) && (x_sz_revised % 2 == 0) && (y_sz_revised % 2 == 0)); - - Wire *expanded_A = module->addWire(NEW_ID, x_sz_revised); - Wire *expanded_B = module->addWire(NEW_ID, y_sz_revised); - - std::string buf_name = "expand_a_buf_"; - auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setParam(ID::A_WIDTH, x_sz); - buf->setParam(ID::Y_WIDTH, x_sz_revised); - buf->setPort(ID::A, SigSpec(A)); - buf->setParam(ID::A_SIGNED, is_signed ? true : false); - buf->setPort(ID::Y, SigSpec(expanded_A)); - - buf_name = "expand_b_buf_"; - buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, SigSpec(B)); - buf->setParam(ID::A_WIDTH, y_sz); - buf->setParam(ID::Y_WIDTH, y_sz_revised); - buf->setParam(ID::A_SIGNED, is_signed ? true : false); - buf->setPort(ID::Y, SigSpec(expanded_B)); - - // Make sure output domain is big enough to take - // all combinations. - // Later logic synthesis will kill unused - // portions of the output domain. - - unsigned required_op_size = x_sz_revised + y_sz_revised; - Wire *expanded_Y = module->addWire(NEW_ID, required_op_size); - // now connect the expanded_Y with a tap to fill out sig Spec Y - buf_name = "reducer_buf_"; - buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, expanded_Y); - buf->setParam(ID::A_WIDTH, required_op_size); - buf->setParam(ID::Y_WIDTH, z_sz); // The real user width - buf->setParam(ID::A_SIGNED, is_signed ? true : false); - // wire in output Y - buf->setPort(ID::Y, SigSpec(Y)); - - if (is_signed == false) /* unsigned multiplier */ - CreateBoothUMult(module, - expanded_A, // multiplicand - expanded_B, // multiplier(scanned) - expanded_Y // result - ); - else /*signed multiplier */ - CreateBoothSMult(module, - expanded_A, // multiplicand - expanded_B, // multiplier(scanned) - expanded_Y // result (sized) - ); - module->remove(cell); - booth_counter++; - continue; + } + } else { + if (x_sz % 2 != 0) { + y_sz_revised = y_sz + 1; + x_sz_revised = x_sz + 1; } } + + log_assert((x_sz_revised == y_sz_revised) && (x_sz_revised % 2 == 0) && (y_sz_revised % 2 == 0)); + + + A.extend_u0(x_sz_revised, is_signed); + B.extend_u0(y_sz_revised, is_signed); + + // Make sure output domain is big enough to take + // all combinations. + // Later logic synthesis will kill unused + // portions of the output domain. + + int required_op_size = x_sz_revised + y_sz_revised; + + if (required_op_size != z_sz) { + SigSpec expanded_Y = module->addWire(NEW_ID, required_op_size); + SigSpec Y_driver = expanded_Y; + Y_driver.extend_u0(Y.size(), is_signed); + module->connect(Y, Y_driver); + Y = expanded_Y; + } + log_assert(GetSize(Y) == required_op_size); + + if (!is_signed) /* unsigned multiplier */ + CreateBoothUMult(module, + A, // multiplicand + B, // multiplier(scanned) + Y // result + ); + else /* signed multiplier */ + CreateBoothSMult(module, + A, // multiplicand + B, // multiplier(scanned) + Y // result (sized) + ); + + module->remove(cell); + booth_counter++; } } From 62302f601ddc9810b5b780748b97c84d875dfa10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 19 Sep 2023 16:25:40 +0200 Subject: [PATCH 17/95] booth: Remove more of unused helpers --- passes/techmap/booth.cc | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index df0f82ec2..086b2e85b 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -66,47 +66,6 @@ struct BoothPassWorker { BoothPassWorker(RTLIL::Module *module) : module(module), sigmap(module) { booth_counter = 0; } - // Unary gate - RTLIL::Wire *mk_ugate1(const RTLIL::IdString &red_typ, std::string &name, SigBit ip1, std::string &op_name) - { - std::string op_wire_name; - if (op_name.empty()) - op_wire_name = name + "_o"; - else - op_wire_name = op_name; - RTLIL::Wire *ret = module->addWire(new_id(op_wire_name, __LINE__, ""), 1); - auto g = module->addCell(new_id(name, __LINE__, ""), red_typ); - g->setPort(ID::A, ip1); - g->setPort(ID::Y, ret); - g->setParam(ID::A_SIGNED, false); - g->setParam(ID::A_WIDTH, 1); - g->setParam(ID::Y_WIDTH, 1); - return ret; - } - - // Binary gate - RTLIL::Wire *mk_ugate2(const RTLIL::IdString &red_typ, std::string &name, SigBit ip1, SigBit ip2, std::string &op_name) - { - auto g = module->addCell(new_id(name, __LINE__, ""), red_typ); - std::string op_wire_name; - if (op_name.empty()) - op_wire_name = name + "_o"; - else - op_wire_name = op_name; - - auto ret = module->addWire(new_id(op_wire_name, __LINE__, ""), 1); - - g->setPort(ID::A, ip1); - g->setPort(ID::B, ip2); - g->setPort(ID::Y, ret); - g->setParam(ID::A_SIGNED, false); - g->setParam(ID::B_SIGNED, false); - g->setParam(ID::A_WIDTH, 1); - g->setParam(ID::B_WIDTH, 1); - g->setParam(ID::Y_WIDTH, 1); - return ret; - } - // Booth unsigned decoder lsb SigBit Bur4d_lsb(std::string name, SigBit lsb_i, SigBit one_i, SigBit s_i) { From d641dfaec2a67a25afb4a82469af3b0627e9b334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 19 Sep 2023 16:33:22 +0200 Subject: [PATCH 18/95] rtlil: Add helper to emit full-adder cells --- kernel/rtlil.cc | 13 +++++++++++++ kernel/rtlil.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 1b57af60a..efd76e9cd 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -2677,6 +2677,19 @@ RTLIL::Cell* RTLIL::Module::addPow(RTLIL::IdString name, const RTLIL::SigSpec &s return cell; } +RTLIL::Cell* RTLIL::Module::addFa(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_x, const RTLIL::SigSpec &sig_y, const std::string &src) +{ + RTLIL::Cell *cell = addCell(name, ID($fa)); + cell->parameters[ID::WIDTH] = sig_a.size(); + cell->setPort(ID::A, sig_a); + cell->setPort(ID::B, sig_b); + cell->setPort(ID::C, sig_c); + cell->setPort(ID::X, sig_x); + cell->setPort(ID::Y, sig_y); + cell->set_src_attribute(src); + return cell; +} + RTLIL::Cell* RTLIL::Module::addSlice(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, RTLIL::Const offset, const std::string &src) { RTLIL::Cell *cell = addCell(name, ID($slice)); diff --git a/kernel/rtlil.h b/kernel/rtlil.h index c50d75e90..3dff48b4f 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1298,6 +1298,8 @@ public: RTLIL::Cell* addModFloor (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* addPow (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_y, bool a_signed = false, bool b_signed = false, const std::string &src = ""); + RTLIL::Cell* addFa (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_x, const RTLIL::SigSpec &sig_y, const std::string &src = ""); + RTLIL::Cell* addLogicNot (RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_y, bool is_signed = false, const std::string &src = ""); RTLIL::Cell* addLogicAnd (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* addLogicOr (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 = ""); From cde2a0b926c1edd24936748e878eee40a3389f26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 25 Sep 2023 13:54:24 +0200 Subject: [PATCH 19/95] booth: Make more use of appropriate helpers Use the `addFa` helper, do not misuse `new_id` and make other changes to the transformation code. --- passes/techmap/booth.cc | 408 +++++++++++++++------------------------- 1 file changed, 150 insertions(+), 258 deletions(-) diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index 086b2e85b..aa5684b74 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -687,20 +687,15 @@ struct BoothPassWorker { // End Case else if (n == s_vec.size() - 1) { // Make the carry results.. Two extra bits after fa. - std::string fa_name = "cpa_" + std::to_string(cpa_id) + "_fa_" + std::to_string(n); - - auto fa_cell = module->addCell(new_id(fa_name, __LINE__, ""), ID($fa)); - fa_cell->setParam(ID::WIDTH, 1); - carry_name = "cpa_" + std::to_string(cpa_id) + "carry_" + std::to_string(n); - fa_cell->setPort(ID::A, s_vec[n]); - fa_cell->setPort(ID::B, c_vec[n - 1]); - fa_cell->setPort(ID::C, carry); - // wire in result and carry out - fa_cell->setPort(ID::Y, result[n]); - - // make a new carry bit for carry out... - carry = module->addWire(new_id(carry_name, __LINE__, ""), 1); - fa_cell->setPort(ID::X, carry); + SigBit carry_out = module->addWire(NEW_ID, 1); + module->addFa(NEW_ID_SUFFIX(stringf("cpa_%d_fa_%d", cpa_id, n)), + /* A */ s_vec[n], + /* B */ c_vec[n - 1], + /* C */ carry, + /* X */ carry_out, + /* Y */ result[n] + ); + carry = carry_out; #ifdef DEBUG_CPA printf("CPA bit [%d] Cell %s IPs [%s] [%s] [%s]\n", n, fa_cell->name.c_str(), s_vec[n]->name.c_str(), @@ -720,20 +715,15 @@ struct BoothPassWorker { } // Step case else { - std::string fa_name = "cpa_" + std::to_string(cpa_id) + "_fa_" + std::to_string(n); - auto fa_cell = module->addCell(new_id(fa_name, __LINE__, ""), ID($fa)); - fa_cell->setParam(ID::WIDTH, 1); - - carry_name = "cpa_" + std::to_string(cpa_id) + "carry_" + std::to_string(n); - fa_cell->setPort(ID::A, s_vec[n]); - fa_cell->setPort(ID::B, c_vec[n - 1]); - fa_cell->setPort(ID::C, carry); - // wire in result and carry out - fa_cell->setPort(ID::Y, result[n]); - // make a new carry bit for carry out... - carry = module->addWire(new_id(carry_name, __LINE__, ""), 1); - fa_cell->setPort(ID::X, carry); - + SigBit carry_out = module->addWire(NEW_ID_SUFFIX(stringf("cpa_%d_carry_%d", cpa_id, n)), 1); + module->addFa(NEW_ID_SUFFIX(stringf("cpa_%d_fa_%d", cpa_id, n)), + /* A */ s_vec[n], + /* B */ c_vec[n - 1], + /* C */ carry, + /* X */ carry_out, + /* Y */ result[n] + ); + carry = carry_out; #ifdef DEBUG_CPA printf("CPA bit [%d] Cell %s IPs [%s] [%s] [%s]\n", n, fa_cell->name.c_str(), s_vec[n]->name.c_str(), c_vec[n - 1]->name.c_str(), carry->name.c_str()); @@ -752,9 +742,6 @@ struct BoothPassWorker { int csa_ix = 0; int column_size = column_bits.size(); - static int unique_id = 0; - - unique_id++; if (column_size > 0) { int var_ix = 0; @@ -767,38 +754,23 @@ struct BoothPassWorker { if (first_csa_ips.size() > 0) { // build the first csa - std::string csa_name = - "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_" + std::to_string(unique_id) + "_"; - auto csa = module->addCell(NEW_ID, - // new_id(csa_name, - // __LINE__, - // ""), - ID($fa)); - csa->setParam(ID::WIDTH, 1); - debug_csa_trees[column_ix].push_back(csa); - csa_ix++; + auto s_wire = module->addWire(NEW_ID_SUFFIX(stringf("csa_%d_%d_s", column_ix, csa_ix + 1)), 1); + auto c_wire = module->addWire(NEW_ID_SUFFIX(stringf("csa_%d_%d_c", column_ix, csa_ix + 1)), 1); - csa->setPort(ID::A, first_csa_ips[0]); + auto csa = module->addFa(NEW_ID_SUFFIX(stringf("csa_%d_%d", column_ix, csa_ix)), + /* A */ first_csa_ips[0], + /* B */ first_csa_ips.size() > 1 ? first_csa_ips[1] : State::S0, + /* C */ first_csa_ips.size() > 2 ? first_csa_ips[2] : State::S0, + /* X */ c_wire, + /* Y */ s_wire + ); - if (first_csa_ips.size() > 1) - csa->setPort(ID::B, first_csa_ips[1]); - else - csa->setPort(ID::B, State::S0); - - if (first_csa_ips.size() > 2) - csa->setPort(ID::C, first_csa_ips[2]); - else - csa->setPort(ID::C, State::S0); - - std::string sum_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_s"; - auto s_wire = module->addWire(new_id(sum_wire_name, __LINE__, ""), 1); - csa->setPort(ID::Y, s_wire); s_result = s_wire; - std::string carry_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_c"; - auto c_wire = module->addWire(new_id(carry_wire_name, __LINE__, ""), 1); - csa->setPort(ID::X, c_wire); c_result = c_wire; + debug_csa_trees[column_ix].push_back(csa); + csa_ix++; + if (var_ix <= column_bits.size() - 1) carry_bits_to_sum.append(c_wire); @@ -814,32 +786,23 @@ struct BoothPassWorker { } if (csa_ips.size() > 0) { - csa_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix); - auto csa = module->addCell(new_id(csa_name, __LINE__, ""), ID($fa)); - csa->setParam(ID::WIDTH, 1); + auto c_wire = module->addWire(NEW_ID_SUFFIX(stringf("csa_%d_%d_c", column_ix, csa_ix + 1)), 1); + auto s_wire = module->addWire(NEW_ID_SUFFIX(stringf("csa_%d_%d_s", column_ix, csa_ix + 1)), 1); + + auto csa = module->addFa(NEW_ID_SUFFIX(stringf("csa_%d_%d", column_ix, csa_ix)), + /* A */ s_result, + /* B */ csa_ips[0], + /* C */ csa_ips.size() > 1 ? csa_ips[1] : State::S0, + /* X */ c_wire, + /* Y */ s_wire + ); + debug_csa_trees[column_ix].push_back(csa); - csa_ix++; - // prior level - csa->setPort(ID::A, s_wire); - csa->setPort(ID::B, csa_ips[0]); - if (csa_ips.size() > 1) - csa->setPort(ID::C, csa_ips[1]); - else - csa->setPort(ID::C, State::S0); - - carry_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_c"; - c_wire = module->addWire(new_id(carry_wire_name, __LINE__, ""), 1); if (var_ix <= column_bits.size() - 1) carry_bits_to_sum.append(c_wire); - sum_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_s"; - s_wire = module->addWire(new_id(sum_wire_name, __LINE__, ""), 1); - - csa->setPort(ID::X, c_wire); - csa->setPort(ID::Y, s_wire); - s_result = s_wire; c_result = c_wire; } @@ -854,22 +817,14 @@ struct BoothPassWorker { int y_sz = GetSize(Y); for (int y_ix = 0; y_ix < y_sz;) { - std::string enc_name = "bur_enc_" + std::to_string(encoder_ix) + "_"; + std::string enc_name = stringf("bur_enc_%d", encoder_ix); - std::string two_name = "two_int" + std::to_string(encoder_ix); - two_int.append(module->addWire(new_id(two_name, __LINE__, ""), 1)); - - std::string one_name = "one_int" + std::to_string(encoder_ix); - one_int.append(module->addWire(new_id(one_name, __LINE__, ""), 1)); - - std::string s_name = "s_int" + std::to_string(encoder_ix); - s_int.append(module->addWire(new_id(s_name, __LINE__, ""), 1)); - - std::string sb_name = "sb_int" + std::to_string(encoder_ix); - sb_int.append(module->addWire(new_id(sb_name, __LINE__, ""), 1)); + two_int.append(module->addWire(NEW_ID_SUFFIX(stringf("two_int_%d", encoder_ix)), 1)); + one_int.append(module->addWire(NEW_ID_SUFFIX(stringf("one_int_%d", encoder_ix)), 1)); + s_int.append(module->addWire(NEW_ID_SUFFIX(stringf("s_int_%d", encoder_ix)), 1)); + sb_int.append(module->addWire(NEW_ID_SUFFIX(stringf("sb_int_%d", encoder_ix)), 1)); if (y_ix == 0) { - BuildBur4e(enc_name, State::S0, Y[y_ix], Y[y_ix + 1], one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], sb_int[encoder_ix]); @@ -919,23 +874,15 @@ struct BoothPassWorker { encoder_ix++; if (need_padded_cell == true) { - // make extra encoder cell // y_ix at y0, rest 0 - std::string enc_name = "br_enc_pad" + std::to_string(encoder_ix) + "_"; + std::string enc_name = stringf("br_enc_pad_%d", encoder_ix); - std::string two_name = "two_int" + std::to_string(encoder_ix); - two_int.append(module->addWire(new_id(two_name, __LINE__, ""), 1)); - - std::string one_name = "one_int" + std::to_string(encoder_ix); - one_int.append(module->addWire(new_id(two_name, __LINE__, ""), 1)); - - std::string s_name = "s_int" + std::to_string(encoder_ix); - s_int.append(module->addWire(new_id(s_name, __LINE__, ""), 1)); - - std::string sb_name = "sb_int" + std::to_string(encoder_ix); - sb_int.append(module->addWire(new_id(sb_name, __LINE__, ""), 1)); + two_int.append(module->addWire(NEW_ID_SUFFIX(stringf("two_int_%d", encoder_ix)), 1)); + one_int.append(module->addWire(NEW_ID_SUFFIX(stringf("one_int_%d", encoder_ix)), 1)); + s_int.append(module->addWire(NEW_ID_SUFFIX(stringf("s_int_%d", encoder_ix)), 1)); + sb_int.append(module->addWire(NEW_ID_SUFFIX(stringf("sb_int_%d", encoder_ix)), 1)); SigBit one_o_int, two_o_int, s_o_int, sb_o_int; BuildBur4e(enc_name, Y[y_ix], State::S0, @@ -977,18 +924,13 @@ struct BoothPassWorker { cori_n_int.extend_u0(enc_count); for (unsigned encoder_ix = 1; encoder_ix <= enc_count; encoder_ix++) { - std::string enc_name = "enc_" + std::to_string(encoder_ix) + "_"; - std::string negi_name = "negi_n_int" + std::to_string(encoder_ix) + "_"; - negi_n_int[encoder_ix - 1] = module->addWire(new_id(negi_name, __LINE__, ""), 1); - std::string twoi_name = "twoi_n_int_" + std::to_string(encoder_ix) + "_"; - twoi_n_int[encoder_ix - 1] = module->addWire(new_id(twoi_name, __LINE__, ""), 1); - std::string onei_name = "onei_n_int_" + std::to_string(encoder_ix) + "_"; - onei_n_int[encoder_ix - 1] = module->addWire(new_id(onei_name, __LINE__, ""), 1); - std::string cori_name = "cori_n_int_" + std::to_string(encoder_ix) + "_"; - cori_n_int[encoder_ix - 1] = module->addWire(new_id(cori_name, __LINE__, ""), 1); + std::string enc_name = stringf("enc_%d", encoder_ix); + negi_n_int[encoder_ix - 1] = module->addWire(NEW_ID_SUFFIX(stringf("negi_n_int_%d", encoder_ix)), 1); + twoi_n_int[encoder_ix - 1] = module->addWire(NEW_ID_SUFFIX(stringf("twoi_n_int_%d", encoder_ix)), 1); + onei_n_int[encoder_ix - 1] = module->addWire(NEW_ID_SUFFIX(stringf("onei_n_int_%d", encoder_ix)), 1); + cori_n_int[encoder_ix - 1] = module->addWire(NEW_ID_SUFFIX(stringf("cori_n_int_%d", encoder_ix)), 1); if (encoder_ix == 1) { - BuildBr4e(enc_name, State::S0, Y[0], Y[1], negi_n_int[encoder_ix - 1], twoi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], cori_n_int[encoder_ix - 1]); @@ -1020,22 +962,18 @@ struct BoothPassWorker { for (int encoder_ix = 1; encoder_ix <= (int)enc_count; encoder_ix++) { for (int decoder_ix = 1; decoder_ix <= dec_count; decoder_ix++) { - std::string ppij_name = "ppij_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; - PPij[((encoder_ix - 1) * dec_count) + decoder_ix - 1] = module->addWire(new_id(ppij_name, __LINE__, ""), 1); - std::string nxj_name; - if (decoder_ix == 1) - nxj_name = "nxj_pre_dec" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; - else - nxj_name = "nxj_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; + PPij[((encoder_ix - 1) * dec_count) + decoder_ix - 1] = + module->addWire(NEW_ID_SUFFIX(stringf("ppij_%d_%d", encoder_ix, decoder_ix)), 1); - nxj[((encoder_ix - 1) * dec_count) + decoder_ix - 1] = module->addWire(new_id(nxj_name, __LINE__, ""), 1); + nxj[((encoder_ix - 1) * dec_count) + decoder_ix - 1] = + module->addWire(NEW_ID_SUFFIX(stringf("nxj_%s%d_%d", decoder_ix == 1 ? "pre_dec_" : "", + encoder_ix, decoder_ix)), 1); } } // // build decoder array // - for (int encoder_ix = 1; encoder_ix <= (int)enc_count; encoder_ix++) { // pre-decoder std::string pre_dec_name = "pre_dec_" + std::to_string(encoder_ix) + "_"; @@ -1043,10 +981,10 @@ struct BoothPassWorker { if (encoder_ix == 1) { // quadrant 1 optimization } else { - auto cell = module->addCell(new_id(pre_dec_name, __LINE__, ""), ID($_NOT_)); - cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); - cell->setPort(ID::A, negi_n_int[encoder_ix - 1]); - cell->setPort(ID::Y, nxj[(encoder_ix - 1) * dec_count]); + module->addNotGate(NEW_ID_SUFFIX(stringf("pre_dec_%d", encoder_ix)), + negi_n_int[encoder_ix - 1], + nxj[(encoder_ix - 1) * dec_count] + ); } for (int decoder_ix = 1; decoder_ix < dec_count; decoder_ix++) { @@ -1056,8 +994,7 @@ struct BoothPassWorker { if ((decoder_ix == 1 || decoder_ix == 2) && encoder_ix == 1) continue; - std::string dec_name = "dec_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; - + std::string dec_name = stringf("dec_%d_%d", encoder_ix, decoder_ix); BuildBr4d(dec_name, nxj[((encoder_ix - 1) * dec_count) + decoder_ix - 1], twoi_n_int[encoder_ix - 1], X[decoder_ix - 1], negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], PPij[((encoder_ix - 1) * dec_count) + decoder_ix - 1], nxj[((encoder_ix - 1) * dec_count) + decoder_ix]); @@ -1065,7 +1002,7 @@ struct BoothPassWorker { // duplicate end for sign fix // applies to 9th decoder (xsz+1 decoder). - std::string dec_name = "dec_" + std::to_string(encoder_ix) + "_" + std::to_string(x_sz + 1) + "_"; + std::string dec_name = stringf("dec_%d_%d", encoder_ix, x_sz + 1); SigBit unused_op; BuildBr4d(dec_name, nxj[((encoder_ix - 1) * dec_count) + dec_count - 1], twoi_n_int[encoder_ix - 1], X[dec_count - 2], negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], @@ -1083,11 +1020,10 @@ struct BoothPassWorker { for (fa_row_ix = 0; fa_row_ix < fa_row_count; fa_row_ix++) { for (fa_el_ix = 0; fa_el_ix < fa_count; fa_el_ix++) { - - std::string fa_sum_name = "fa_sum_n_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_"; - fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] = module->addWire(new_id(fa_sum_name, __LINE__, ""), 1); - std::string fa_carry_name = "fa_carry_n" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_"; - fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix] = module->addWire(new_id(fa_carry_name, __LINE__, ""), 1); + fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] = + module->addWire(NEW_ID_SUFFIX(stringf("fa_sum_n_%d_%d", fa_row_ix, fa_el_ix)), 1); + fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix] = + module->addWire(NEW_ID_SUFFIX(stringf("fa_carry_n_%d_%d", fa_row_ix, fa_el_ix)), 1); } } @@ -1110,67 +1046,52 @@ struct BoothPassWorker { // step case else if (fa_el_ix >= 2 && fa_el_ix <= x_sz) { // middle (2...x_sz cells) - bfa_name = "bfa_0_step_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - auto cell = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell->setParam(ID::WIDTH, 1); - cell->setPort(ID::A, PPij[(0 * dec_count) + fa_el_ix]); - cell->setPort(ID::B, PPij[(1 * dec_count) + fa_el_ix - 2]); - cell->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_0_step_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ PPij[(0 * dec_count) + fa_el_ix], + /* B */ PPij[(1 * dec_count) + fa_el_ix - 2], + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); } // end 3 cells: x_sz+1.2.3 // else { // fa_el_ix = x_sz+1 - bfa_name = "bfa_0_se_0" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - auto cell1 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell1->setParam(ID::WIDTH, 1); - cell1->setPort(ID::A, PPij[(0 * dec_count) + x_sz]); - cell1->setPort(ID::B, PPij[(1 * dec_count) + fa_el_ix - 2]); - cell1->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell1->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell1->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_0_se_0_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ PPij[(0 * dec_count) + x_sz], + /* B */ PPij[(1 * dec_count) + fa_el_ix - 2], + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); // exception:invert ppi fa_el_ix++; - exc_inv_name = "bfa_0_exc_inv1_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - auto cellinv1 = module->addCell(new_id(exc_inv_name, __LINE__, ""), ID($_NOT_)); - cellinv1->add_strpool_attribute(ID::src, cellinv1->get_strpool_attribute(ID::src)); + SigBit d08_inv = module->NotGate(NEW_ID_SUFFIX(stringf("bfa_0_exc_inv1_%d_%d_L", fa_row_ix, fa_el_ix)), + PPij[(0 * dec_count) + dec_count - 1]); - RTLIL::Wire *d08_inv = module->addWire(NEW_ID, 1); + SigBit d18_inv = module->NotGate(NEW_ID_SUFFIX(stringf("bfa_0_exc_inv2_%d_%d_L", fa_row_ix, fa_el_ix)), + PPij[(1 * dec_count) + dec_count - 1]); - cellinv1->setPort(ID::A, PPij[(0 * dec_count) + dec_count - 1]); - cellinv1->setPort(ID::Y, d08_inv); - - exc_inv_name = "bfa_0_exc_inv2_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - - auto cellinv2 = module->addCell(new_id(exc_inv_name, __LINE__, ""), ID($_NOT_)); - cellinv2->add_strpool_attribute(ID::src, cellinv2->get_strpool_attribute(ID::src)); - RTLIL::Wire *d18_inv = module->addWire(NEW_ID, 1); - cellinv2->setPort(ID::A, PPij[(1 * dec_count) + dec_count - 1]); - cellinv2->setPort(ID::Y, d18_inv); - - bfa_name = "bfa_0_se_1_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - - auto cell2 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell2->setParam(ID::WIDTH, 1); - cell2->setPort(ID::A, d08_inv); - cell2->setPort(ID::B, d18_inv); - cell2->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell2->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell2->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_0_se_1_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ d08_inv, + /* B */ d18_inv, + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); // sign extension fa_el_ix++; - bfa_name = "bfa_0_se_2_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; - auto cell3 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell3->setParam(ID::WIDTH, 1); - cell3->setPort(ID::A, State::S0); - cell3->setPort(ID::B, State::S1); - cell3->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell3->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell3->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + + module->addFa(NEW_ID_SUFFIX(stringf("bfa_0_se_2_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ State::S0, + /* B */ State::S1, + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); } } @@ -1181,74 +1102,59 @@ struct BoothPassWorker { if (fa_el_ix == 0) { // first two cells: have B input hooked to 0. // column is offset by row_ix*2 - bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_base_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cell1 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell1->setParam(ID::WIDTH, 1); - cell1->setPort(ID::A, fa_sum_n[(fa_row_ix - 1) * fa_count + 2]); // from prior full adder row - cell1->setPort(ID::B, State::S0); - cell1->setPort(ID::C, cori_n_int[fa_row_ix]); - cell1->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell1->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + + module->addFa(NEW_ID_SUFFIX(stringf("bfa_base_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ fa_sum_n[(fa_row_ix - 1) * fa_count + 2], + /* B */ State::S0, + /* C */ cori_n_int[fa_row_ix], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); fa_el_ix++; - bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_base_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cell2 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell2->setParam(ID::WIDTH, 1); - cell2->setPort(ID::A, - fa_sum_n[(fa_row_ix - 1) * fa_count + 3]); // from prior full adder row - cell2->setPort(ID::B, State::S0); - cell2->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell2->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell2->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_base_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ fa_sum_n[(fa_row_ix - 1) * fa_count + 3], // from prior full adder row + /* B */ State::S0, + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); + } else if (fa_el_ix >= 2 && fa_el_ix <= x_sz + 1) { // middle (2...x_sz+1 cells) - bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_step_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cell = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell->setParam(ID::WIDTH, 1); - cell->setPort(ID::A, fa_sum_n[(fa_row_ix - 1) * fa_count + fa_el_ix + 2]); - cell->setPort(ID::B, PPij[(fa_row_ix + 1) * dec_count + fa_el_ix - 2]); - cell->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_step_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ fa_sum_n[(fa_row_ix - 1) * fa_count + fa_el_ix + 2], + /* B */ PPij[(fa_row_ix + 1) * dec_count + fa_el_ix - 2], + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); } else if (fa_el_ix > x_sz + 1) { // end two bits: sign extension - std::string se_inv_name; - se_inv_name = "bfa_" + std::to_string(fa_row_ix) + "_se_inv_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cellinv = module->addCell(new_id(se_inv_name, __LINE__, ""), ID($_NOT_)); - cellinv->add_strpool_attribute(ID::src, cellinv->get_strpool_attribute(ID::src)); - RTLIL::Wire *d_inv = module->addWire(NEW_ID, 1); - cellinv->setPort(ID::A, PPij[((fa_row_ix + 1) * dec_count) + dec_count - 1]); - cellinv->setPort(ID::Y, d_inv); + SigBit d_inv = module->NotGate(NEW_ID_SUFFIX(stringf("bfa_se_inv_%d_%d_L", fa_row_ix, fa_el_ix)), + PPij[((fa_row_ix + 1) * dec_count) + dec_count - 1]); - bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_se_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cell1 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell1->setParam(ID::WIDTH, 1); - cell1->setPort(ID::A, fa_carry_n[((fa_row_ix - 1) * fa_count) + fa_count - 1]); - cell1->setPort(ID::B, d_inv); - cell1->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell1->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell1->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_se_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ fa_carry_n[((fa_row_ix - 1) * fa_count) + fa_count - 1], + /* B */ d_inv, + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); fa_el_ix++; // sign extension - bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_se_" + std::to_string(fa_row_ix) + "_" + - std::to_string(fa_el_ix) + "_L"; - auto cell2 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); - cell2->setParam(ID::WIDTH, 1); - cell2->setPort(ID::A, State::S0); - cell2->setPort(ID::B, State::S1); - cell2->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); - cell2->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); - cell2->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + module->addFa(NEW_ID_SUFFIX(stringf("bfa_se_%d_%d_L", fa_row_ix, fa_el_ix)), + /* A */ State::S0, + /* B */ State::S1, + /* C */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1], + /* X */ fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix], + /* Y */ fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] + ); } } } @@ -1257,13 +1163,10 @@ struct BoothPassWorker { // instantiate the cpa SigSpec cpa_carry; - for (int cix = 0; cix < z_sz; cix++) { - std::string cpa_cix_name = "cpa_carry_" + std::to_string(cix) + "_"; - cpa_carry.append(module->addWire(new_id(cpa_cix_name, __LINE__, ""), 1)); - } + for (int cix = 0; cix < z_sz; cix++) + cpa_carry.append(module->addWire(NEW_ID_SUFFIX(stringf("cpa_carry_%d", cix)), 1)); for (int cpa_ix = 0; cpa_ix < z_sz; cpa_ix++) { - // The end case where we pass the last two summands // from prior row directly to product output // without using a cpa cell. This is always @@ -1271,27 +1174,16 @@ struct BoothPassWorker { if (cpa_ix <= fa_row_count * 2 - 1) { int fa_row_ix = cpa_ix / 2; - std::string buf_name = - "pp_buf_" + std::to_string(cpa_ix) + "_" + "driven_by_fa_row_" + std::to_string(fa_row_ix) + "_"; - auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, fa_sum_n[(fa_row_ix * fa_count) + 0]); - buf->setParam(ID::A_WIDTH, 1); - buf->setParam(ID::Y_WIDTH, 1); - buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, Z[cpa_ix]); + module->addBufGate(NEW_ID_SUFFIX(stringf("pp_buf_%d_driven_by_fa_row_%d", cpa_ix, fa_row_ix)), + fa_sum_n[(fa_row_ix * fa_count) + 0], Z[cpa_ix]); cpa_ix++; - buf_name = "pp_buf_" + std::to_string(cpa_ix) + "_" + "driven_by_fa_row_" + std::to_string(fa_row_ix) + "_"; - buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); - buf->setPort(ID::A, fa_sum_n[(fa_row_ix * fa_count) + 1]); - buf->setParam(ID::A_WIDTH, 1); - buf->setParam(ID::Y_WIDTH, 1); - buf->setParam(ID::A_SIGNED, true); - buf->setPort(ID::Y, Z[cpa_ix]); + module->addBufGate(NEW_ID_SUFFIX(stringf("pp_buf_%d_driven_by_fa_row_%d", cpa_ix, fa_row_ix)), + fa_sum_n[(fa_row_ix * fa_count) + 1], Z[cpa_ix]); } else { int offset = fa_row_count * 2; bool base_case = cpa_ix - offset == 0 ? true : false; - std::string cpa_name = "cpa_" + std::to_string(cpa_ix - offset) + "_"; + std::string cpa_name = stringf("cpa_%d", cpa_ix - offset); SigBit ci; if (base_case) From 7179e4f4b89bfea706fbeeff13722a0417bed766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 25 Sep 2023 14:44:45 +0200 Subject: [PATCH 20/95] booth: Improve user interface --- passes/techmap/booth.cc | 49 +++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index aa5684b74..b81225d07 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -912,9 +912,7 @@ struct BoothPassWorker { int fa_count = x_sz + 4; int fa_row_count = enc_count - 1; - log("Signed multiplier generator using low Power Negative First Booth Algorithm. Multiplicand of size %d Multiplier of size %d. " - "Result of size %d. %d encoders %d decoders\n", - x_sz, y_sz, z_sz, enc_count, dec_count); + log_debug("Mapping %d x %d -> %d multiplier: %d encoders %d decoders\n", x_sz, y_sz, z_sz, enc_count, dec_count); SigSpec negi_n_int, twoi_n_int, onei_n_int, cori_n_int; @@ -1225,18 +1223,51 @@ struct BoothPassWorker { }; struct BoothPass : public Pass { - BoothPass() : Pass("booth", "Map $mul to booth multipliers") {} + BoothPass() : Pass("booth", "map $mul cells to Booth multipliers") {} + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" booth [selection]\n"); + log("\n"); + log("This pass replaces multiplier cells with an implementation based on the Booth\n"); + log("algorithm. It operates on $mul cells whose width of operands is at least 4x4\n"); + log("and whose width of result is at least 8. The detailed architecture is selected\n"); + log("from two options based on the signedness of the operands to the $mul cell.\n"); + log("\n"); + log("See the references below for the description of the architectures.\n"); + log("\n"); + log("Signed-multiplier architecture:\n"); + log("Y. J. Chang, Y. C. Cheng, S. C. Liao and C. H. Hsiao, \"A Low Power Radix-4 Booth\n"); + log("Multiplier With Pre-Encoded Mechanism,\" in IEEE Access, vol. 8, pp. 114842-114853,\n"); + log("2020, doi: 10.1109/ACCESS.2020.3003684\n"); + log("\n"); + log("Unsigned-multiplier architecture:\n"); + log("G. W. Bewick, \"Fast Multiplication: Algorithms and Implementations,\" PhD Thesis,\n"); + log("Department of Electrical Engineering, Stanford University, 1994\n"); + log("\n"); + } void execute(vector args, RTLIL::Design *design) override { - (void)args; - log_header(design, - "Executing booth pass. Generating Booth Multiplier structures for signed/unsigned multipliers of 4 bits or more\n"); - for (auto mod : design->selected_modules()) + log_header(design, "Executing BOOTH pass (map to Booth multipliers).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + break; + } + extra_args(args, argidx, design); + + int total = 0; + + for (auto mod : design->selected_modules()) { if (!mod->has_processes_warn()) { BoothPassWorker worker(mod); worker.run(); - log_header(design, "Created %d booth multipliers.\n", worker.booth_counter); + total += worker.booth_counter; } + } + + log("Mapped %d multipliers.\n", total); } } MultPass; From 91bcf81dbda538ddb23a992eedc6c3ec67bcec56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 25 Sep 2023 14:45:56 +0200 Subject: [PATCH 21/95] booth: Note down debug prints are broken --- passes/techmap/booth.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index b81225d07..be38c8fc3 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -52,6 +52,9 @@ or in generic synthesis call with -booth argument: synth -top my_design -booth */ +//FIXME: These debug prints are broken now, should be fixed or removed. +//#define DEBUG_CPA + #include "kernel/sigtools.h" #include "kernel/yosys.h" From 3319fdc46e3a66690b6a90ad5e47d8a665310984 Mon Sep 17 00:00:00 2001 From: "N. Engelhardt" Date: Mon, 25 Sep 2023 17:20:16 +0200 Subject: [PATCH 22/95] show: use dot for wire aliases instead of BUF --- passes/cmds/show.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc index 0dc5c452c..d57cbc6bb 100644 --- a/passes/cmds/show.cc +++ b/passes/cmds/show.cc @@ -575,7 +575,7 @@ struct ShowWorker } else { net_conn_map[right_node].in.insert({stringf("x%d", single_idx_count), GetSize(conn.first)}); net_conn_map[left_node].out.insert({stringf("x%d", single_idx_count), GetSize(conn.first)}); - fprintf(f, "x%d [shape=box, style=rounded, label=\"BUF\", %s];\n", single_idx_count++, findColor(conn).c_str()); + fprintf(f, "x%d [shape=point, %s];\n", single_idx_count++, findColor(conn).c_str()); } } } From 10d0e69588a64c0ef451b54d42e8741e4be260e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 4 Apr 2023 20:52:30 +0200 Subject: [PATCH 23/95] ast/simplify: Make tweaks in advance of big in_lvalue/in_param change The following commit will replace the way in_lvalue/in_param is being tracked in the simplify code. Make tweaks in advance so that it will be easier to make the old way and the new way agree. These changes all should be innocuous. --- frontends/ast/simplify.cc | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index ee1be3781..7f2b76af0 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -47,7 +47,7 @@ Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_ std::vector args; for (size_t index = first_arg_at; index < children.size(); index++) { AstNode *node_arg = children[index]; - while (node_arg->simplify(true, false, stage, -1, false, false)) { } + while (node_arg->simplify(true, false, stage, -1, false, in_param)) { } VerilogFmtArg arg = {}; arg.filename = filename; @@ -91,7 +91,7 @@ void AstNode::annotateTypedEnums(AstNode *template_node) log_assert(current_scope.count(enum_type) == 1); AstNode *enum_node = current_scope.at(enum_type); log_assert(enum_node->type == AST_ENUM); - while (enum_node->simplify(true, false, 1, -1, false, true)) { } + while (enum_node->simplify(true, false, 1, -1, false, false)) { } //get width from 1st enum item: log_assert(enum_node->children.size() >= 1); AstNode *enum_item0 = enum_node->children[0]; @@ -457,7 +457,8 @@ static int get_max_offset(AstNode *node) static AstNode *make_packed_struct(AstNode *template_node, std::string &name, decltype(AstNode::attributes) &attributes) { // create a wire for the packed struct - auto wnode = new AstNode(AST_WIRE); + int offset = get_max_offset(template_node); + auto wnode = new AstNode(AST_WIRE, make_range(offset, 0)); wnode->str = name; wnode->is_logic = true; wnode->range_valid = true; @@ -465,9 +466,6 @@ static AstNode *make_packed_struct(AstNode *template_node, std::string &name, de for (auto &pair : attributes) { wnode->attributes[pair.first] = pair.second->clone(); } - int offset = get_max_offset(template_node); - auto range = make_range(offset, 0); - wnode->children.push_back(range); // make sure this node is the one in scope for this name current_scope[name] = wnode; // add all the struct members to scope under the wire's name @@ -980,7 +978,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin // when $display()/$write() functions are used in an always block, simplify the expressions and // convert them to a special cell later in genrtlil for (auto node : children) - while (node->simplify(true, false, stage, -1, false, false)) {} + while (node->simplify(true, false, stage, -1, false, in_param)) {} return false; } @@ -1806,7 +1804,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *template_node = resolved_type_node->children[0]; // Ensure typedef itself is fully simplified - while (template_node->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, in_param)) {}; + while (template_node->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, false)) {}; if (!str.empty() && str[0] == '\\' && (template_node->type == AST_STRUCT || template_node->type == AST_UNION)) { // replace instance with wire representing the packed structure @@ -1871,7 +1869,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *template_node = resolved_type_node->children[0]; // Ensure typedef itself is fully simplified - while (template_node->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, in_param)) {}; + while (template_node->simplify(const_fold, false, stage, width_hint, sign_hint, false)) {}; if (template_node->type == AST_STRUCT || template_node->type == AST_UNION) { // replace with wire representing the packed structure @@ -2761,7 +2759,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin if (children[0]->id2ast->attributes.count(ID::nowrshmsk)) { AstNode *node = children[0]->id2ast->attributes.at(ID::nowrshmsk); - while (node->simplify(true, false, stage, -1, false, false)) { } + while (node->simplify(true, false, stage, -1, false, true)) { } if (node->type != AST_CONSTANT) input_error("Non-constant value for `nowrshmsk' attribute on `%s'!\n", children[0]->id2ast->str.c_str()); if (node->asAttrConst().as_bool()) @@ -3582,7 +3580,7 @@ skip_dynamic_range_lvalue_expansion:; } if (children.size() >= 1) { - while (children[0]->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (children[0]->simplify(true, false, stage, width_hint, sign_hint, in_param)) { } if (!children[0]->isConst()) input_error("Failed to evaluate system function `%s' with non-constant argument.\n", RTLIL::unescape_id(str).c_str()); @@ -3593,7 +3591,7 @@ skip_dynamic_range_lvalue_expansion:; } if (children.size() >= 2) { - while (children[1]->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (children[1]->simplify(true, false, stage, width_hint, sign_hint, in_param)) { } if (!children[1]->isConst()) input_error("Failed to evaluate system function `%s' with non-constant argument.\n", RTLIL::unescape_id(str).c_str()); @@ -3650,7 +3648,7 @@ skip_dynamic_range_lvalue_expansion:; // Determine which bits to count for (size_t i = 1; i < children.size(); i++) { AstNode *node = children[i]; - while (node->simplify(true, false, stage, -1, false, false)) { } + while (node->simplify(true, false, stage, -1, false, in_param)) { } if (node->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant control bit argument.\n", str.c_str()); if (node->bits.size() != 1) @@ -3855,7 +3853,7 @@ skip_dynamic_range_lvalue_expansion:; bool require_const_eval = decl->has_const_only_constructs(); bool all_args_const = true; for (auto child : children) { - while (child->simplify(true, false, 1, -1, false, true)) { } + while (child->simplify(true, in_lvalue, 1, -1, false, in_param)) { } if (child->type != AST_CONSTANT && child->type != AST_REALVALUE) all_args_const = false; } @@ -4048,7 +4046,7 @@ skip_dynamic_range_lvalue_expansion:; } } // updates the sizing - while (wire->simplify(true, false, 1, -1, false, false)) { } + while (wire->simplify(true, false, 1, -1, false, true)) { } delete arg; continue; } From 22b99413e8e22147aeb8a6492c21b456d56a9a90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 5 Apr 2023 11:00:07 +0200 Subject: [PATCH 24/95] ast/simplify: Make in_lvalue/in_param into props of AST nodes Instead of passing around in_lvalue/in_param flags to simplify, we make the flags into properties of the AST nodes themselves. After the tree is first parsed, we once do ast->fixup_hierarchy_flags(true) to walk the full hierarchy and set the flags to their initial correct values. Then as long as one is using ->clone(), ->cloneInto() and the AstNode constructor (with children passed to it) to modify the tree, the flags will be kept in sync automatically. On the other hand if we are modifying the children list of an existing node, we may need to call node->fixup_hierarchy_flags() to do a localized fixup. That fixup will update the flags on the node's children, and will propagate the change down the tree if necessary. clone() doesn't always retain the flags of the subtree being cloned. It will produce a tree with a consistent setting of the flags, but the root doesn't have in_param/in_lvalue set unless it's intrinsic to the type of node being cloned (e.g. AST_PARAMETER). cloneInto() will make sure the cloned subtree has the flags consistent with the new placement in a hierarchy. Add asserts to make sure the old and new way of determining the flags agree. --- frontends/ast/ast.cc | 26 ++++- frontends/ast/ast.h | 25 +++++ frontends/ast/genrtlil.cc | 11 ++- frontends/ast/simplify.cc | 202 +++++++++++++++++++++++++++++++------- 4 files changed, 222 insertions(+), 42 deletions(-) diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index a027295e9..5a5851c3e 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -229,6 +229,10 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch id2ast = NULL; basic_prep = false; lookahead = false; + in_lvalue_from_above = false; + in_param_from_above = false; + in_lvalue = false; + in_param = false; if (child1) children.push_back(child1); @@ -238,6 +242,8 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch children.push_back(child3); if (child4) children.push_back(child4); + + fixup_hierarchy_flags(); } // create a (deep recursive) copy of a node @@ -249,6 +255,10 @@ AstNode *AstNode::clone() const it = it->clone(); for (auto &it : that->attributes) it.second = it.second->clone(); + + that->set_in_lvalue_flag(false); + that->set_in_param_flag(false); + that->fixup_hierarchy_flags(); // fixup to set flags on cloned children return that; } @@ -256,10 +266,13 @@ AstNode *AstNode::clone() const void AstNode::cloneInto(AstNode *other) const { AstNode *tmp = clone(); + tmp->in_lvalue_from_above = other->in_lvalue_from_above; + tmp->in_param_from_above = other->in_param_from_above; other->delete_children(); *other = *tmp; tmp->children.clear(); tmp->attributes.clear(); + other->fixup_hierarchy_flags(); delete tmp; } @@ -351,6 +364,10 @@ void AstNode::dumpAst(FILE *f, std::string indent) const if (is_enum) { fprintf(f, " type=enum"); } + if (in_lvalue) + fprintf(f, " in_lvalue"); + if (in_param) + fprintf(f, " in_param"); fprintf(f, "\n"); for (auto &it : attributes) { @@ -1091,7 +1108,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d ast->attributes.erase(ID::whitebox); } AstNode *n = ast->attributes.at(ID::lib_whitebox); - ast->attributes[ID::whitebox] = n; + ast->set_attribute(ID::whitebox, n); ast->attributes.erase(ID::lib_whitebox); } } @@ -1150,7 +1167,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d ast->children.swap(new_children); if (ast->attributes.count(ID::blackbox) == 0) { - ast->attributes[ID::blackbox] = AstNode::mkconst_int(1, false); + ast->set_attribute(ID::blackbox, AstNode::mkconst_int(1, false)); } } @@ -1298,6 +1315,8 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump flag_pwires = pwires; flag_autowire = autowire; + ast->fixup_hierarchy_flags(true); + log_assert(current_ast->type == AST_DESIGN); for (AstNode *child : current_ast->children) { @@ -1748,7 +1767,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dictclone(); if (!new_ast->attributes.count(ID::hdlname)) - new_ast->attributes[ID::hdlname] = AstNode::mkconst_str(stripped_name); + new_ast->set_attribute(ID::hdlname, AstNode::mkconst_str(stripped_name)); para_counter = 0; for (auto child : new_ast->children) { @@ -1795,6 +1814,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dictchildren.push_back(defparam); } + new_ast->fixup_hierarchy_flags(true); (*new_ast_out) = new_ast; return modname; } diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index e357579ad..cd6e25421 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -221,6 +221,13 @@ namespace AST std::string filename; AstSrcLocType location; + // are we embedded in an lvalue, param? + // (see fixup_hierarchy_flags) + bool in_lvalue; + bool in_param; + bool in_lvalue_from_above; + bool in_param_from_above; + // creating and deleting nodes AstNode(AstNodeType type = AST_NONE, AstNode *child1 = nullptr, AstNode *child2 = nullptr, AstNode *child3 = nullptr, AstNode *child4 = nullptr); AstNode *clone() const; @@ -343,6 +350,24 @@ namespace AST // to evaluate widths of dynamic ranges) AstNode *clone_at_zero(); + void set_attribute(RTLIL::IdString key, AstNode *node) + { + attributes[key] = node; + node->set_in_param_flag(true); + } + + // helper to set in_lvalue/in_param flags from the hierarchy context (the actual flag + // can be overridden based on the intrinsic properties of this node, i.e. based on its type) + void set_in_lvalue_flag(bool flag, bool no_descend = false); + void set_in_param_flag(bool flag, bool no_descend = false); + + // fix up the hierarchy flags (in_lvalue/in_param) of this node and its children + // + // to keep the flags in sync, fixup_hierarchy_flags(true) needs to be called once after + // parsing the AST to walk the full tree, then plain fixup_hierarchy_flags() performs + // localized fixups after modifying children/attributes of a particular node + void fixup_hierarchy_flags(bool force_descend = false); + // helper to print errors from simplify/genrtlil code [[noreturn]] void input_error(const char *format, ...) const YS_ATTRIBUTE(format(printf, 2, 3)); }; diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index d62f06ae5..64626d9a9 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -176,8 +176,9 @@ struct AST_INTERNAL::LookaheadRewriter AstNode *wire = new AstNode(AST_WIRE); for (auto c : node->id2ast->children) wire->children.push_back(c->clone()); + wire->fixup_hierarchy_flags(); wire->str = stringf("$lookahead%s$%d", node->str.c_str(), autoidx++); - wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire->is_logic = true; while (wire->simplify(true, false, 1, -1, false, false)) { } current_ast_mod->children.push_back(wire); @@ -1198,8 +1199,10 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun log_assert(range->type == AST_RANGE && range->children.size() == 2); AstNode *left = range->children.at(0)->clone(); AstNode *right = range->children.at(1)->clone(); - while (left->simplify(true, false, 1, -1, false, true)) { } - while (right->simplify(true, false, 1, -1, false, true)) { } + left->set_in_param_flag(true); + right->set_in_param_flag(true); + while (left->simplify(true, in_lvalue, 1, -1, false, true)) { } + while (right->simplify(true, in_lvalue, 1, -1, false, true)) { } if (left->type != AST_CONSTANT || right->type != AST_CONSTANT) input_error("Function %s has non-constant width!", RTLIL::unescape_id(str).c_str()); @@ -1552,7 +1555,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) children[0]->children[1]->clone() : children[0]->children[0]->clone()); fake_ast->children[0]->delete_children(); if (member_node) - fake_ast->children[0]->attributes[ID::wiretype] = member_node->clone(); + fake_ast->children[0]->set_attribute(ID::wiretype, member_node->clone()); int fake_ast_width = 0; bool fake_ast_sign = true; diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 7f2b76af0..4583f770b 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -41,6 +41,95 @@ YOSYS_NAMESPACE_BEGIN using namespace AST; using namespace AST_INTERNAL; +void AstNode::set_in_lvalue_flag(bool flag, bool no_descend) +{ + if (flag != in_lvalue_from_above) { + in_lvalue_from_above = flag; + if (!no_descend) + fixup_hierarchy_flags(); + } +} + +void AstNode::set_in_param_flag(bool flag, bool no_descend) +{ + if (flag != in_param_from_above) { + in_param_from_above = flag; + if (!no_descend) + fixup_hierarchy_flags(); + } +} + +void AstNode::fixup_hierarchy_flags(bool force_descend) +{ + // With forced descend, we disable the implicit + // descend from within the set_* functions, instead + // we do an explicit descend at the end of this function + + in_param = in_param_from_above; + + switch (type) { + case AST_PARAMETER: + case AST_LOCALPARAM: + case AST_DEFPARAM: + case AST_PARASET: + case AST_PREFIX: + in_param = true; + for (auto child : children) + child->set_in_param_flag(true, force_descend); + break; + + case AST_REPLICATE: + case AST_WIRE: + case AST_GENIF: + case AST_GENCASE: + for (auto child : children) + child->set_in_param_flag(in_param, force_descend); + if (children.size() >= 1) + children[0]->set_in_param_flag(true, force_descend); + break; + + case AST_GENFOR: + case AST_FOR: + for (auto child : children) + child->set_in_param_flag(in_param, force_descend); + if (children.size() >= 2) + children[1]->set_in_param_flag(true, force_descend); + break; + + default: + in_param = in_param_from_above; + for (auto child : children) + child->set_in_param_flag(in_param, force_descend); + } + + for (auto attr : attributes) + attr.second->set_in_param_flag(true, force_descend); + + in_lvalue = in_lvalue_from_above; + + switch (type) { + case AST_ASSIGN: + case AST_ASSIGN_EQ: + case AST_ASSIGN_LE: + if (children.size() >= 1) + children[0]->set_in_lvalue_flag(true, force_descend); + if (children.size() >= 2) + children[1]->set_in_lvalue_flag(in_lvalue, force_descend); + break; + + default: + for (auto child : children) + child->set_in_lvalue_flag(in_lvalue, force_descend); + } + + if (force_descend) { + for (auto child : children) + child->fixup_hierarchy_flags(true); + for (auto attr : attributes) + attr.second->fixup_hierarchy_flags(true); + } +} + // Process a format string and arguments for $display, $write, $sprintf, etc Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_t first_arg_at) { @@ -132,7 +221,7 @@ void AstNode::annotateTypedEnums(AstNode *template_node) RTLIL::Const val = enum_item->children[0]->bitsAsConst(width, is_signed); enum_item_str.append(val.as_string()); //set attribute for available val to enum item name mappings - attributes[enum_item_str.c_str()] = mkconst_str(enum_item->str); + set_attribute(enum_item_str.c_str(), mkconst_str(enum_item->str)); } } } @@ -464,7 +553,7 @@ static AstNode *make_packed_struct(AstNode *template_node, std::string &name, de wnode->range_valid = true; wnode->is_signed = template_node->is_signed; for (auto &pair : attributes) { - wnode->attributes[pair.first] = pair.second->clone(); + wnode->set_attribute(pair.first, pair.second->clone()); } // make sure this node is the one in scope for this name current_scope[name] = wnode; @@ -525,7 +614,7 @@ const RTLIL::Module* AstNode::lookup_cell_module() auto reprocess_after = [this] (const std::string &modname) { if (!attributes.count(ID::reprocess_after)) - attributes[ID::reprocess_after] = AstNode::mkconst_str(modname); + set_attribute(ID::reprocess_after, AstNode::mkconst_str(modname)); }; const AstNode *celltype = nullptr; @@ -705,6 +794,11 @@ AstNode *AstNode::clone_at_zero() it = it->clone_at_zero(); for (auto &it : that->attributes) it.second = it.second->clone(); + + that->set_in_lvalue_flag(false); + that->set_in_param_flag(false); + that->fixup_hierarchy_flags(); + return that; } @@ -743,8 +837,7 @@ static void mark_auto_nosync(AstNode *block, const AstNode *wire) { log_assert(block->type == AST_BLOCK); log_assert(wire->type == AST_WIRE); - block->attributes[auto_nosync_prefix + wire->str] = AstNode::mkconst_int(1, - false); + block->set_attribute(auto_nosync_prefix + wire->str, AstNode::mkconst_int(1, false)); } // block names can be prefixed with an explicit scope during elaboration @@ -785,7 +878,7 @@ static void check_auto_nosync(AstNode *node) // mark the wire with `nosync` AstNode *wire = it->second; log_assert(wire->type == AST_WIRE); - wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); } // remove the attributes we've "consumed" @@ -806,7 +899,7 @@ static void check_auto_nosync(AstNode *node) // // this function also does all name resolving and sets the id2ast member of all // nodes that link to a different node using names and lexical scoping. -bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param) +bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hint, bool sign_hint, bool in_param_) { static int recursion_counter = 0; static bool deep_recursion_warning = false; @@ -913,7 +1006,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin reg->is_signed = node->is_signed; for (auto &it : node->attributes) if (it.first != ID::mem2reg) - reg->attributes.emplace(it.first, it.second->clone()); + reg->set_attribute(it.first, it.second->clone()); reg->filename = node->filename; reg->location = node->location; children.push_back(reg); @@ -994,7 +1087,9 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin // in certain cases a function must be evaluated constant. this is what in_param controls. if (type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_PREFIX) - in_param = true; + in_param_ = true; + log_assert(in_param == in_param_); + log_assert(in_lvalue == in_lvalue_); std::map backup_scope; @@ -1015,7 +1110,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin if (!c->is_simple_const_expr()) { if (attributes.count(ID::dynports)) delete attributes.at(ID::dynports); - attributes[ID::dynports] = AstNode::mkconst_int(1, true); + set_attribute(ID::dynports, AstNode::mkconst_int(1, true)); } } } @@ -1064,7 +1159,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin for (auto &it : node->attributes) { if (first_node->attributes.count(it.first) > 0) delete first_node->attributes[it.first]; - first_node->attributes[it.first] = it.second->clone(); + first_node->set_attribute(it.first, it.second->clone()); } children.erase(children.begin()+(i--)); did_something = true; @@ -1261,6 +1356,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin asgn->children.push_back(arg); asgn->children.push_back(ident); } + asgn->fixup_hierarchy_flags(); } @@ -1382,7 +1478,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin range_left = template_node->range_left; range_right = template_node->range_right; - attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); + set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); // Copy clones of children from template for (auto template_child : template_node->children) { @@ -1414,7 +1510,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin if (children[0]->type == AST_IDENTIFIER && current_scope.count(children[0]->str) > 0) { auto item_node = current_scope[children[0]->str]; if (item_node->type == AST_STRUCT || item_node->type == AST_UNION) { - attributes[ID::wiretype] = item_node->clone(); + set_attribute(ID::wiretype, item_node->clone()); size_packed_struct(attributes[ID::wiretype], 0); add_members_to_scope(attributes[ID::wiretype], str); } @@ -1809,7 +1905,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin if (!str.empty() && str[0] == '\\' && (template_node->type == AST_STRUCT || template_node->type == AST_UNION)) { // replace instance with wire representing the packed structure newNode = make_packed_struct(template_node, str, attributes); - newNode->attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); + newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); // add original input/output attribute to resolved wire newNode->is_input = this->is_input; newNode->is_output = this->is_output; @@ -1834,7 +1930,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin range_left = template_node->range_left; range_right = template_node->range_right; - attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); + set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); // if an enum then add attributes to support simulator tracing annotateTypedEnums(template_node); @@ -1848,6 +1944,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *rng = make_range(0, 0); children.insert(children.begin(), rng); } + fixup_hierarchy_flags(); did_something = true; } log_assert(!is_custom_type); @@ -1874,7 +1971,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin if (template_node->type == AST_STRUCT || template_node->type == AST_UNION) { // replace with wire representing the packed structure newNode = make_packed_struct(template_node, str, attributes); - newNode->attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); + newNode->set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); newNode->type = type; current_scope[str] = this; // copy param value, it needs to be 1st value @@ -1896,9 +1993,10 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin range_swapped = template_node->range_swapped; range_left = template_node->range_left; range_right = template_node->range_right; - attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); + set_attribute(ID::wiretype, mkconst_str(resolved_type_node->str)); for (auto template_child : template_node->children) children.push_back(template_child->clone()); + fixup_hierarchy_flags(); did_something = true; } log_assert(!is_custom_type); @@ -2018,6 +2116,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin } delete children[1]; children[1] = new AstNode(AST_RANGE, AstNode::mkconst_int(0, true), AstNode::mkconst_int(total_size-1, true)); + fixup_hierarchy_flags(); did_something = true; } @@ -2052,6 +2151,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin else children[0] = new AstNode(AST_RANGE, index_expr); + fixup_hierarchy_flags(); did_something = true; } @@ -2067,6 +2167,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin children[0]->realvalue, log_signal(constvalue)); delete children[0]; children[0] = mkconst_bits(constvalue.bits, sign_hint); + fixup_hierarchy_flags(); did_something = true; } if (children[0]->type == AST_CONSTANT) { @@ -2076,6 +2177,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *old_child_0 = children[0]; children[0] = mkconst_bits(sig.as_const().bits, is_signed); delete old_child_0; + fixup_hierarchy_flags(); } children[0]->is_signed = is_signed; } @@ -2089,6 +2191,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin delete children[0]; children[0] = new AstNode(AST_REALVALUE); children[0]->realvalue = as_realvalue; + fixup_hierarchy_flags(); did_something = true; } } @@ -2105,7 +2208,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin newNode = new AstNode(AST_IDENTIFIER, range); newNode->str = sname; // save type and original number of dimensions for $size() etc. - newNode->attributes[ID::wiretype] = item_node->clone(); + newNode->set_attribute(ID::wiretype, item_node->clone()); if (!item_node->multirange_dimensions.empty() && children.size() > 0) { if (children[0]->type == AST_RANGE) newNode->integer = 1; @@ -2199,7 +2302,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); wire->str = wire_id; if (current_block) - wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); current_ast_mod->children.push_back(wire); while (wire->simplify(true, false, 1, -1, false, false)) { } @@ -2387,6 +2490,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin // eval 3rd expression buf = next_ast->children[1]->clone(); + buf->set_in_param_flag(true); { int expr_width_hint = -1; bool expr_sign_hint = true; @@ -2548,6 +2652,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin continue; buf = child->clone(); + buf->set_in_param_flag(true); while (buf->simplify(true, false, stage, width_hint, sign_hint, true)) { } if (buf->type != AST_CONSTANT) { // for (auto f : log_files) @@ -2654,6 +2759,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin children.push_back(children_list.at(0)); children.back()->was_checked = true; children.push_back(node); + fixup_hierarchy_flags(); did_something = true; } else if (str == "buf" || str == "not") @@ -2704,6 +2810,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin children.push_back(children_list[0]); children.back()->was_checked = true; children.push_back(node); + fixup_hierarchy_flags(); did_something = true; } } @@ -2782,7 +2889,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *lvalue = children[0]->clone(); lvalue->delete_children(); if (member_node) - lvalue->attributes[ID::wiretype] = member_node->clone(); + lvalue->set_attribute(ID::wiretype, member_node->clone()); lvalue->children.push_back(new AstNode(AST_RANGE, mkconst_int(end_bit, true), mkconst_int(start_bit, true))); cond->children.push_back(new AstNode(AST_BLOCK, new AstNode(type, lvalue, children[1]->clone()))); @@ -2795,14 +2902,14 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *wire_mask = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true))); wire_mask->str = stringf("$bitselwrite$mask$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); - wire_mask->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_mask->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire_mask->is_logic = true; while (wire_mask->simplify(true, false, 1, -1, false, false)) { } current_ast_mod->children.push_back(wire_mask); AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true))); wire_data->str = stringf("$bitselwrite$data$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); - wire_data->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire_data->is_logic = true; while (wire_data->simplify(true, false, 1, -1, false, false)) { } current_ast_mod->children.push_back(wire_data); @@ -2813,7 +2920,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *wire_sel = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(shamt_width_hint-1, true), mkconst_int(0, true))); wire_sel->str = stringf("$bitselwrite$sel$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); - wire_sel->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_sel->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire_sel->is_logic = true; wire_sel->is_signed = shamt_sign_hint; while (wire_sel->simplify(true, false, 1, -1, false, false)) { } @@ -2825,7 +2932,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin AstNode *lvalue = children[0]->clone(); lvalue->delete_children(); if (member_node) - lvalue->attributes[ID::wiretype] = member_node->clone(); + lvalue->set_attribute(ID::wiretype, member_node->clone()); AstNode *ref_mask = new AstNode(AST_IDENTIFIER); ref_mask->str = wire_mask->str; @@ -2882,6 +2989,8 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin t = new AstNode(AST_BIT_OR, t, ref_data); t = new AstNode(type, lvalue, t); newNode->children.push_back(t); + + newNode->fixup_hierarchy_flags(true); } goto apply_newNode; @@ -2942,6 +3051,7 @@ skip_dynamic_range_lvalue_expansion:; assign_check->children[0]->str = id_check; assign_check->children[0]->was_checked = true; } + assign_check->fixup_hierarchy_flags(); if (current_always == nullptr || current_always->type != AST_INITIAL) { assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1)); @@ -2951,6 +3061,7 @@ skip_dynamic_range_lvalue_expansion:; } assign_en->children[0]->str = id_en; assign_en->children[0]->was_checked = true; + assign_en->fixup_hierarchy_flags(); newNode = new AstNode(AST_BLOCK); if (assign_check != nullptr) @@ -2973,6 +3084,7 @@ skip_dynamic_range_lvalue_expansion:; if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME || type == AST_LIVE || type == AST_FAIR || type == AST_COVER) && children.size() == 1) { children.push_back(mkconst_int(1, false, 1)); + fixup_hierarchy_flags(); did_something = true; } @@ -3003,7 +3115,7 @@ skip_dynamic_range_lvalue_expansion:; wire_tmp->str = stringf("$splitcmplxassign$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); current_ast_mod->children.push_back(wire_tmp); current_scope[wire_tmp->str] = wire_tmp; - wire_tmp->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_tmp->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); while (wire_tmp->simplify(true, false, 1, -1, false, false)) { } wire_tmp->is_logic = true; @@ -3743,6 +3855,7 @@ skip_dynamic_range_lvalue_expansion:; argtypes.push_back(RTLIL::unescape_id(dpi_decl->children.at(i)->str)); args.push_back(children.at(i-2)->clone()); + args.back()->set_in_param_flag(true); while (args.back()->simplify(true, false, stage, -1, false, true)) { } if (args.back()->type != AST_CONSTANT && args.back()->type != AST_REALVALUE) @@ -3860,6 +3973,7 @@ skip_dynamic_range_lvalue_expansion:; if (all_args_const) { AstNode *func_workspace = decl->clone(); + func_workspace->set_in_param_flag(true); func_workspace->str = prefix_id(prefix, "$result"); newNode = func_workspace->eval_const_function(this, in_param || require_const_eval); delete func_workspace; @@ -4004,9 +4118,9 @@ skip_dynamic_range_lvalue_expansion:; wire->is_input = false; wire->is_output = false; wire->is_reg = true; - wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); if (child->type == AST_ENUM_ITEM) - wire->attributes[ID::enum_base_type] = child->attributes[ID::enum_base_type]; + wire->set_attribute(ID::enum_base_type, child->attributes[ID::enum_base_type]); wire_cache[child->str] = wire; @@ -4045,6 +4159,7 @@ skip_dynamic_range_lvalue_expansion:; range->children.push_back(mkconst_int(0, true)); } } + wire->fixup_hierarchy_flags(); // updates the sizing while (wire->simplify(true, false, 1, -1, false, true)) { } delete arg; @@ -4364,6 +4479,7 @@ apply_newNode: newNode->filename = filename; newNode->location = location; newNode->cloneInto(this); + fixup_hierarchy_flags(); delete newNode; did_something = true; } @@ -4954,7 +5070,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, wire_addr->str = id_addr; wire_addr->is_reg = true; wire_addr->was_checked = true; - wire_addr->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); mod->children.push_back(wire_addr); while (wire_addr->simplify(true, false, 1, -1, false, false)) { } @@ -4963,7 +5079,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, wire_data->is_reg = true; wire_data->was_checked = true; wire_data->is_signed = mem_signed; - wire_data->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); mod->children.push_back(wire_data); while (wire_data->simplify(true, false, 1, -1, false, false)) { } @@ -4992,6 +5108,10 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, cond_node->children[1]->children.push_back(assign_reg); case_node->children.push_back(cond_node); } + + // fixup on the full hierarchy below case_node + case_node->fixup_hierarchy_flags(true); + block->children.insert(block->children.begin()+assign_idx+2, case_node); children[0]->delete_children(); @@ -5001,6 +5121,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, type = AST_ASSIGN_EQ; children[0]->was_checked = true; + fixup_hierarchy_flags(); did_something = true; } @@ -5071,7 +5192,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, wire_addr->is_reg = true; wire_addr->was_checked = true; if (block) - wire_addr->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); mod->children.push_back(wire_addr); while (wire_addr->simplify(true, false, 1, -1, false, false)) { } @@ -5081,7 +5202,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, wire_data->was_checked = true; wire_data->is_signed = mem_signed; if (block) - wire_data->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); mod->children.push_back(wire_data); while (wire_data->simplify(true, false, 1, -1, false, false)) { } @@ -5115,6 +5236,9 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, cond_node->children[1]->children.push_back(assign_reg); case_node->children.push_back(cond_node); + // fixup on the full hierarchy below case_node + case_node->fixup_hierarchy_flags(true); + if (block) { size_t assign_idx = 0; @@ -5126,10 +5250,10 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, } else { - AstNode *proc = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK)); - proc->children[0]->children.push_back(case_node); + AstNode *proc = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK, case_node)); mod->children.push_back(proc); mod->children.push_back(assign_addr); + mod->fixup_hierarchy_flags(); } delete_children(); @@ -5138,8 +5262,10 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, str = id_data; } - if (bit_part_sel) + if (bit_part_sel) { children.push_back(bit_part_sel); + fixup_hierarchy_flags(); + } did_something = true; } @@ -5302,6 +5428,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) { block->children.push_back(child->clone()); } + block->set_in_param_flag(true); while (!block->children.empty()) { @@ -5444,6 +5571,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) AstNode *cond = stmt->children.at(0)->clone(); if (!cond->replace_variables(variables, fcall, must_succeed)) goto finished; + cond->set_in_param_flag(true); while (cond->simplify(true, false, 1, -1, false, true)) { } if (cond->type != AST_CONSTANT) { @@ -5469,6 +5597,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) AstNode *num = stmt->children.at(0)->clone(); if (!num->replace_variables(variables, fcall, must_succeed)) goto finished; + num->set_in_param_flag(true); while (num->simplify(true, false, 1, -1, false, true)) { } if (num->type != AST_CONSTANT) { @@ -5492,6 +5621,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) AstNode *expr = stmt->children.at(0)->clone(); if (!expr->replace_variables(variables, fcall, must_succeed)) goto finished; + expr->set_in_param_flag(true); while (expr->simplify(true, false, 1, -1, false, true)) { } AstNode *sel_case = NULL; @@ -5512,6 +5642,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) goto finished; cond = new AstNode(AST_EQ, expr->clone(), cond); + cond->set_in_param_flag(true); while (cond->simplify(true, false, 1, -1, false, true)) { } if (cond->type != AST_CONSTANT) { @@ -5547,6 +5678,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) block->children.erase(block->children.begin()); block->children.insert(block->children.begin(), stmt->children.begin(), stmt->children.end()); stmt->children.clear(); + block->fixup_hierarchy_flags(); delete stmt; continue; } @@ -5581,7 +5713,7 @@ void AstNode::allocateDefaultEnumValues() int last_enum_int = -1; for (auto node : children) { log_assert(node->type==AST_ENUM_ITEM); - node->attributes[ID::enum_base_type] = mkconst_str(str); + node->set_attribute(ID::enum_base_type, mkconst_str(str)); for (size_t i = 0; i < node->children.size(); i++) { switch (node->children[i]->type) { case AST_NONE: From a511976b489ab266a511b9d8d96ee7e5001c9306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 4 Apr 2023 22:59:44 +0200 Subject: [PATCH 25/95] ast/simplify: Retire in_lvalue/in_param arguments to simplify --- frontends/ast/ast.cc | 4 +- frontends/ast/ast.h | 2 +- frontends/ast/genrtlil.cc | 26 ++--- frontends/ast/simplify.cc | 197 ++++++++++++++++++-------------------- 4 files changed, 110 insertions(+), 119 deletions(-) diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 5a5851c3e..5335a3992 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -1078,7 +1078,7 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d // simplify this module or interface using the current design as context // for lookup up ports and wires within cells set_simplify_design_context(design); - while (ast->simplify(!flag_noopt, false, 0, -1, false, false)) { } + while (ast->simplify(!flag_noopt, 0, -1, false)) { } set_simplify_design_context(nullptr); if (flag_dump_ast2) { @@ -1380,7 +1380,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump } else if (child->type == AST_PACKAGE) { // process enum/other declarations - child->simplify(true, false, 1, -1, false, false); + child->simplify(true, 1, -1, false); rename_in_package_stmts(child); design->verilog_packages.push_back(child->clone()); current_scope.clear(); diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index cd6e25421..f789e930b 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -258,7 +258,7 @@ namespace AST // simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc. // it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL() - bool simplify(bool const_fold, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param); + bool simplify(bool const_fold, int stage, int width_hint, bool sign_hint); void replace_result_wire_name_in_function(const std::string &from, const std::string &to); AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr, bool unconditional_init); void expand_genblock(const std::string &prefix); diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 64626d9a9..6e750863f 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -180,7 +180,7 @@ struct AST_INTERNAL::LookaheadRewriter wire->str = stringf("$lookahead%s$%d", node->str.c_str(), autoidx++); wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire->is_logic = true; - while (wire->simplify(true, false, 1, -1, false, false)) { } + while (wire->simplify(true, 1, -1, false)) { } current_ast_mod->children.push_back(wire); lookaheadids[node->str] = make_pair(node->id2ast, wire); wire->genRTLIL(); @@ -927,7 +927,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun this_width = id_ast->children[1]->range_left - id_ast->children[1]->range_right + 1; } else { if (id_ast->children[0]->type != AST_CONSTANT) - while (id_ast->simplify(true, false, 1, -1, false, true)) { } + while (id_ast->simplify(true, 1, -1, false)) { } if (id_ast->children[0]->type == AST_CONSTANT) this_width = id_ast->children[0]->bits.size(); else @@ -971,8 +971,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun else if (!range->range_valid) { AstNode *left_at_zero_ast = children[0]->children[0]->clone_at_zero(); AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone(); - while (left_at_zero_ast->simplify(true, false, 1, -1, false, false)) { } - while (right_at_zero_ast->simplify(true, false, 1, -1, false, false)) { } + while (left_at_zero_ast->simplify(true, 1, -1, false)) { } + while (right_at_zero_ast->simplify(true, 1, -1, false)) { } if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); this_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; @@ -988,7 +988,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun break; case AST_TO_BITS: - while (children[0]->simplify(true, false, 1, -1, false, false) == true) { } + while (children[0]->simplify(true, 1, -1, false) == true) { } if (children[0]->type != AST_CONSTANT) input_error("Left operand of tobits expression is not constant!\n"); children[1]->detectSignWidthWorker(sub_width_hint, sign_hint); @@ -1010,7 +1010,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun break; case AST_CAST_SIZE: - while (children.at(0)->simplify(true, false, 1, -1, false, false)) { } + while (children.at(0)->simplify(true, 1, -1, false)) { } if (children.at(0)->type != AST_CONSTANT) input_error("Static cast with non constant expression!\n"); children.at(1)->detectSignWidthWorker(width_hint, sign_hint); @@ -1032,7 +1032,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun break; case AST_REPLICATE: - while (children[0]->simplify(true, false, 1, -1, false, true) == true) { } + while (children[0]->simplify(true, 1, -1, false) == true) { } if (children[0]->type != AST_CONSTANT) input_error("Left operand of replicate expression is not constant!\n"); children[1]->detectSignWidthWorker(sub_width_hint, sub_sign_hint); @@ -1144,7 +1144,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_PREFIX: // Prefix nodes always resolve to identifiers in generate loops, so we // can simply perform the resolution to determine the sign and width. - simplify(true, false, 1, -1, false, false); + simplify(true, 1, -1, false); log_assert(type == AST_IDENTIFIER); detectSignWidthWorker(width_hint, sign_hint, found_real); break; @@ -1152,7 +1152,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_FCALL: if (str == "\\$anyconst" || str == "\\$anyseq" || str == "\\$allconst" || str == "\\$allseq") { if (GetSize(children) == 1) { - while (children[0]->simplify(true, false, 1, -1, false, true) == true) { } + while (children[0]->simplify(true, 1, -1, false) == true) { } if (children[0]->type != AST_CONSTANT) input_error("System function %s called with non-const argument!\n", RTLIL::unescape_id(str).c_str()); @@ -1201,8 +1201,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun AstNode *right = range->children.at(1)->clone(); left->set_in_param_flag(true); right->set_in_param_flag(true); - while (left->simplify(true, in_lvalue, 1, -1, false, true)) { } - while (right->simplify(true, in_lvalue, 1, -1, false, true)) { } + while (left->simplify(true, 1, -1, false)) { } + while (right->simplify(true, 1, -1, false)) { } if (left->type != AST_CONSTANT || right->type != AST_CONSTANT) input_error("Function %s has non-constant width!", RTLIL::unescape_id(str).c_str()); @@ -1546,8 +1546,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (!children[0]->range_valid) { AstNode *left_at_zero_ast = children[0]->children[0]->clone_at_zero(); AstNode *right_at_zero_ast = children[0]->children.size() >= 2 ? children[0]->children[1]->clone_at_zero() : left_at_zero_ast->clone(); - while (left_at_zero_ast->simplify(true, false, 1, -1, false, false)) { } - while (right_at_zero_ast->simplify(true, false, 1, -1, false, false)) { } + while (left_at_zero_ast->simplify(true, 1, -1, false)) { } + while (right_at_zero_ast->simplify(true, 1, -1, false)) { } if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) input_error("Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 4583f770b..c4a303027 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -136,7 +136,7 @@ Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_ std::vector args; for (size_t index = first_arg_at; index < children.size(); index++) { AstNode *node_arg = children[index]; - while (node_arg->simplify(true, false, stage, -1, false, in_param)) { } + while (node_arg->simplify(true, stage, -1, false)) { } VerilogFmtArg arg = {}; arg.filename = filename; @@ -180,7 +180,7 @@ void AstNode::annotateTypedEnums(AstNode *template_node) log_assert(current_scope.count(enum_type) == 1); AstNode *enum_node = current_scope.at(enum_type); log_assert(enum_node->type == AST_ENUM); - while (enum_node->simplify(true, false, 1, -1, false, false)) { } + while (enum_node->simplify(true, 1, -1, false)) { } //get width from 1st enum item: log_assert(enum_node->children.size() >= 1); AstNode *enum_item0 = enum_node->children[0]; @@ -814,8 +814,8 @@ static bool try_determine_range_width(AstNode *range, int &result_width) AstNode *left_at_zero_ast = range->children[0]->clone_at_zero(); AstNode *right_at_zero_ast = range->children[1]->clone_at_zero(); - while (left_at_zero_ast->simplify(true, false, 1, -1, false, false)) {} - while (right_at_zero_ast->simplify(true, false, 1, -1, false, false)) {} + while (left_at_zero_ast->simplify(true, 1, -1, false)) {} + while (right_at_zero_ast->simplify(true, 1, -1, false)) {} bool ok = false; if (left_at_zero_ast->type == AST_CONSTANT @@ -899,7 +899,7 @@ static void check_auto_nosync(AstNode *node) // // this function also does all name resolving and sets the id2ast member of all // nodes that link to a different node using names and lexical scoping. -bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hint, bool sign_hint, bool in_param_) +bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hint) { static int recursion_counter = 0; static bool deep_recursion_warning = false; @@ -917,8 +917,8 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi #if 0 log("-------------\n"); log("AST simplify[%d] depth %d at %s:%d on %s %p:\n", stage, recursion_counter, filename.c_str(), location.first_line, type2str(type).c_str(), this); - log("const_fold=%d, in_lvalue=%d, stage=%d, width_hint=%d, sign_hint=%d, in_param=%d\n", - int(const_fold), int(in_lvalue), int(stage), int(width_hint), int(sign_hint), int(in_param)); + log("const_fold=%d, stage=%d, width_hint=%d, sign_hint=%d\n", + int(const_fold), int(stage), int(width_hint), int(sign_hint)); // dumpAst(NULL, "> "); #endif @@ -927,7 +927,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi log_assert(type == AST_MODULE || type == AST_INTERFACE); deep_recursion_warning = true; - while (simplify(const_fold, in_lvalue, 1, width_hint, sign_hint, in_param)) { } + while (simplify(const_fold, 1, width_hint, sign_hint)) { } if (!flag_nomem2reg && !get_bool_attribute(ID::nomem2reg)) { @@ -1010,7 +1010,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi reg->filename = node->filename; reg->location = node->location; children.push_back(reg); - while (reg->simplify(true, false, 1, -1, false, false)) { } + while (reg->simplify(true, 1, -1, false)) { } } } @@ -1024,7 +1024,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi delete node; } - while (simplify(const_fold, in_lvalue, 2, width_hint, sign_hint, in_param)) { } + while (simplify(const_fold, 2, width_hint, sign_hint)) { } recursion_counter--; return false; } @@ -1071,7 +1071,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi // when $display()/$write() functions are used in an always block, simplify the expressions and // convert them to a special cell later in genrtlil for (auto node : children) - while (node->simplify(true, false, stage, -1, false, in_param)) {} + while (node->simplify(true, stage, -1, false)) {} return false; } @@ -1085,12 +1085,6 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi if (type == AST_IDENTIFIER && current_scope.count(str) > 0 && (current_scope[str]->type == AST_PARAMETER || current_scope[str]->type == AST_LOCALPARAM || current_scope[str]->type == AST_ENUM_ITEM)) const_fold = true; - // in certain cases a function must be evaluated constant. this is what in_param controls. - if (type == AST_PARAMETER || type == AST_LOCALPARAM || type == AST_DEFPARAM || type == AST_PARASET || type == AST_PREFIX) - in_param_ = true; - log_assert(in_param == in_param_); - log_assert(in_lvalue == in_lvalue_); - std::map backup_scope; // create name resolution entries for all objects with names @@ -1193,12 +1187,12 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi for (size_t i = 0; i < children.size(); i++) { AstNode *node = children[i]; if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_WIRE || node->type == AST_AUTOWIRE || node->type == AST_MEMORY || node->type == AST_TYPEDEF) - while (node->simplify(true, false, 1, -1, false, node->type == AST_PARAMETER || node->type == AST_LOCALPARAM)) + while (node->simplify(true, 1, -1, false)) did_something = true; if (node->type == AST_ENUM) { for (auto enode : node->children){ log_assert(enode->type==AST_ENUM_ITEM); - while (node->simplify(true, false, 1, -1, false, in_param)) + while (node->simplify(true, 1, -1, false)) did_something = true; } } @@ -1263,7 +1257,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi for (AstNode *child : children) { // simplify any parameters to constants if (child->type == AST_PARASET) - while (child->simplify(true, false, 1, -1, false, true)) { } + while (child->simplify(true, 1, -1, false)) { } // look for patterns which _may_ indicate ambiguity requiring // resolution of the underlying module @@ -1378,9 +1372,9 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi case AST_ASSIGN_EQ: case AST_ASSIGN_LE: case AST_ASSIGN: - while (!children[0]->basic_prep && children[0]->simplify(false, true, stage, -1, false, in_param) == true) + while (!children[0]->basic_prep && children[0]->simplify(false, stage, -1, false) == true) did_something = true; - while (!children[1]->basic_prep && children[1]->simplify(false, false, stage, -1, false, in_param) == true) + while (!children[1]->basic_prep && children[1]->simplify(false, stage, -1, false) == true) did_something = true; children[0]->detectSignWidth(backup_width_hint, backup_sign_hint); children[1]->detectSignWidth(width_hint, sign_hint); @@ -1416,7 +1410,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi if (!basic_prep) { for (auto *node : children) { // resolve any ranges - while (!node->basic_prep && node->simplify(true, false, stage, -1, false, false)) { + while (!node->basic_prep && node->simplify(true, stage, -1, false)) { did_something = true; } } @@ -1449,7 +1443,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi AstNode *template_node = resolved_type_node->children[0]; // Ensure typedef itself is fully simplified - while (template_node->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, in_param)) {}; + while (template_node->simplify(const_fold, stage, width_hint, sign_hint)) {}; // Remove type reference delete children[0]; @@ -1495,7 +1489,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi //log("\nENUM %s: %d child %d\n", str.c_str(), basic_prep, children[0]->basic_prep); if (!basic_prep) { for (auto item_node : children) { - while (!item_node->basic_prep && item_node->simplify(false, false, stage, -1, false, in_param)) + while (!item_node->basic_prep && item_node->simplify(false, stage, -1, false)) did_something = true; } // allocate values (called more than once) @@ -1515,11 +1509,11 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi add_members_to_scope(attributes[ID::wiretype], str); } } - while (!children[0]->basic_prep && children[0]->simplify(false, false, stage, -1, false, true) == true) + while (!children[0]->basic_prep && children[0]->simplify(false, stage, -1, false) == true) did_something = true; children[0]->detectSignWidth(width_hint, sign_hint); if (children.size() > 1 && children[1]->type == AST_RANGE) { - while (!children[1]->basic_prep && children[1]->simplify(false, false, stage, -1, false, true) == true) + while (!children[1]->basic_prep && children[1]->simplify(false, stage, -1, false) == true) did_something = true; if (!children[1]->range_valid) input_error("Non-constant width range on parameter decl.\n"); @@ -1527,11 +1521,11 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi } break; case AST_ENUM_ITEM: - while (!children[0]->basic_prep && children[0]->simplify(false, false, stage, -1, false, in_param)) + while (!children[0]->basic_prep && children[0]->simplify(false, stage, -1, false)) did_something = true; children[0]->detectSignWidth(width_hint, sign_hint); if (children.size() > 1 && children[1]->type == AST_RANGE) { - while (!children[1]->basic_prep && children[1]->simplify(false, false, stage, -1, false, in_param)) + while (!children[1]->basic_prep && children[1]->simplify(false, stage, -1, false)) did_something = true; if (!children[1]->range_valid) input_error("Non-constant width range on enum item decl.\n"); @@ -1590,7 +1584,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi width_hint = -1; sign_hint = true; for (auto child : children) { - while (!child->basic_prep && child->simplify(false, in_lvalue, stage, -1, false, in_param) == true) + while (!child->basic_prep && child->simplify(false, stage, -1, false) == true) did_something = true; child->detectSignWidthWorker(width_hint, sign_hint); } @@ -1625,10 +1619,10 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi if (detect_width_simple && width_hint < 0) { if (type == AST_REPLICATE) - while (children[0]->simplify(true, in_lvalue, stage, -1, false, true) == true) + while (children[0]->simplify(true, stage, -1, false) == true) did_something = true; for (auto child : children) - while (!child->basic_prep && child->simplify(false, in_lvalue, stage, -1, false, in_param) == true) + while (!child->basic_prep && child->simplify(false, stage, -1, false) == true) did_something = true; detectSignWidth(width_hint, sign_hint); } @@ -1638,18 +1632,18 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi if (type == AST_TERNARY) { if (width_hint < 0) { - while (!children[0]->basic_prep && children[0]->simplify(true, in_lvalue, stage, -1, false, in_param)) + while (!children[0]->basic_prep && children[0]->simplify(true, stage, -1, false)) did_something = true; bool backup_unevaluated_tern_branch = unevaluated_tern_branch; AstNode *chosen = get_tern_choice().first; unevaluated_tern_branch = backup_unevaluated_tern_branch || chosen == children[2]; - while (!children[1]->basic_prep && children[1]->simplify(false, in_lvalue, stage, -1, false, in_param)) + while (!children[1]->basic_prep && children[1]->simplify(false, stage, -1, false)) did_something = true; unevaluated_tern_branch = backup_unevaluated_tern_branch || chosen == children[1]; - while (!children[2]->basic_prep && children[2]->simplify(false, in_lvalue, stage, -1, false, in_param)) + while (!children[2]->basic_prep && children[2]->simplify(false, stage, -1, false)) did_something = true; unevaluated_tern_branch = backup_unevaluated_tern_branch; @@ -1681,7 +1675,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi if (const_fold && type == AST_CASE) { detectSignWidth(width_hint, sign_hint); - while (children[0]->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, in_param)) { } + while (children[0]->simplify(const_fold, stage, width_hint, sign_hint)) { } if (children[0]->type == AST_CONSTANT && children[0]->bits_only_01()) { children[0]->is_signed = sign_hint; RTLIL::Const case_expr = children[0]->bitsAsConst(width_hint, sign_hint); @@ -1695,7 +1689,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi goto keep_const_cond; if (v->type == AST_BLOCK) continue; - while (v->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, in_param)) { } + while (v->simplify(const_fold, stage, width_hint, sign_hint)) { } if (v->type == AST_CONSTANT && v->bits_only_01()) { RTLIL::Const case_item_expr = v->bitsAsConst(width_hint, sign_hint); RTLIL::Const match = const_eq(case_expr, case_item_expr, sign_hint, sign_hint, 1); @@ -1752,20 +1746,18 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi unevaluated_tern_branch = chosen && chosen != children[i]; } while (did_something_here && i < children.size()) { - bool const_fold_here = const_fold, in_lvalue_here = in_lvalue; + bool const_fold_here = const_fold; int width_hint_here = width_hint; bool sign_hint_here = sign_hint; bool in_param_here = in_param; if (i == 0 && (type == AST_REPLICATE || type == AST_WIRE)) - const_fold_here = true, in_param_here = true; + const_fold_here = true; if (i == 0 && (type == AST_GENIF || type == AST_GENCASE)) in_param_here = true; if (i == 1 && (type == AST_FOR || type == AST_GENFOR)) in_param_here = true; if (type == AST_PARAMETER || type == AST_LOCALPARAM) const_fold_here = true; - if (i == 0 && (type == AST_ASSIGN || type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE)) - in_lvalue_here = true; if (type == AST_BLOCK) { current_block = this; current_block_child = children[i]; @@ -1780,7 +1772,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi width_hint_here = -1, sign_hint_here = false; if (children_are_self_determined) width_hint_here = -1, sign_hint_here = false; - did_something_here = children[i]->simplify(const_fold_here, in_lvalue_here, stage, width_hint_here, sign_hint_here, in_param_here); + did_something_here = children[i]->simplify(const_fold_here, stage, width_hint_here, sign_hint_here); if (did_something_here) did_something = true; } @@ -1800,7 +1792,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi } } for (auto &attr : attributes) { - while (attr.second->simplify(true, false, stage, -1, false, true)) + while (attr.second->simplify(true, stage, -1, false)) did_something = true; } if (type == AST_CASE && stage == 2) { @@ -1878,7 +1870,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi log_assert(children.size() == 1); auto type_node = children[0]; log_assert(type_node->type == AST_WIRE || type_node->type == AST_MEMORY || type_node->type == AST_STRUCT || type_node->type == AST_UNION); - while (type_node->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, in_param)) { + while (type_node->simplify(const_fold, stage, width_hint, sign_hint)) { did_something = true; } log_assert(!type_node->is_custom_type); @@ -1900,7 +1892,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi AstNode *template_node = resolved_type_node->children[0]; // Ensure typedef itself is fully simplified - while (template_node->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, false)) {}; + while (template_node->simplify(const_fold, stage, width_hint, sign_hint)) {}; if (!str.empty() && str[0] == '\\' && (template_node->type == AST_STRUCT || template_node->type == AST_UNION)) { // replace instance with wire representing the packed structure @@ -1966,7 +1958,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi AstNode *template_node = resolved_type_node->children[0]; // Ensure typedef itself is fully simplified - while (template_node->simplify(const_fold, false, stage, width_hint, sign_hint, false)) {}; + while (template_node->simplify(const_fold, stage, width_hint, sign_hint)) {}; if (template_node->type == AST_STRUCT || template_node->type == AST_UNION) { // replace with wire representing the packed structure @@ -2009,7 +2001,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi input_error("Index in generate block prefix syntax is not constant!\n"); } if (children[1]->type == AST_PREFIX) - children[1]->simplify(const_fold, in_lvalue, stage, width_hint, sign_hint, in_param); + children[1]->simplify(const_fold, stage, width_hint, sign_hint); log_assert(children[1]->type == AST_IDENTIFIER); newNode = children[1]->clone(); const char *second_part = children[1]->str.c_str(); @@ -2304,7 +2296,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi if (current_block) wire->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); current_ast_mod->children.push_back(wire); - while (wire->simplify(true, false, 1, -1, false, false)) { } + while (wire->simplify(true, 1, -1, false)) { } AstNode *data = clone(); delete data->children[1]; @@ -2346,7 +2338,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi AstNode *body = children[1]; // eval count expression - while (count->simplify(true, false, stage, 32, true, false)) { } + while (count->simplify(true, stage, 32, true)) { } if (count->type != AST_CONSTANT) input_error("Repeat loops outside must have constant repeat counts!\n"); @@ -2402,7 +2394,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi int expr_width_hint = -1; bool expr_sign_hint = true; varbuf->detectSignWidth(expr_width_hint, expr_sign_hint); - while (varbuf->simplify(true, false, stage, 32, true, false)) { } + while (varbuf->simplify(true, stage, 32, true)) { } } if (varbuf->type != AST_CONSTANT) @@ -2443,7 +2435,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi int expr_width_hint = -1; bool expr_sign_hint = true; buf->detectSignWidth(expr_width_hint, expr_sign_hint); - while (buf->simplify(true, false, stage, expr_width_hint, expr_sign_hint, false)) { } + while (buf->simplify(true, stage, expr_width_hint, expr_sign_hint)) { } } if (buf->type != AST_CONSTANT) @@ -2478,7 +2470,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi if (type == AST_GENFOR) { for (size_t i = 0; i < buf->children.size(); i++) { - buf->children[i]->simplify(const_fold, false, stage, -1, false, false); + buf->children[i]->simplify(const_fold, stage, -1, false); current_ast_mod->children.push_back(buf->children[i]); } } else { @@ -2495,7 +2487,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi int expr_width_hint = -1; bool expr_sign_hint = true; buf->detectSignWidth(expr_width_hint, expr_sign_hint); - while (buf->simplify(true, false, stage, expr_width_hint, expr_sign_hint, true)) { } + while (buf->simplify(true, stage, expr_width_hint, expr_sign_hint)) { } } if (buf->type != AST_CONSTANT) @@ -2547,7 +2539,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi std::vector new_children; for (size_t i = 0; i < children.size(); i++) if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM || children[i]->type == AST_TYPEDEF) { - children[i]->simplify(false, false, stage, -1, false, false); + children[i]->simplify(false, stage, -1, false); current_ast_mod->children.push_back(children[i]); current_scope[children[i]->str] = children[i]; } else @@ -2566,7 +2558,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi } for (size_t i = 0; i < children.size(); i++) { - children[i]->simplify(const_fold, false, stage, -1, false, false); + children[i]->simplify(const_fold, stage, -1, false); current_ast_mod->children.push_back(children[i]); } @@ -2578,7 +2570,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi if (type == AST_GENIF && children.size() != 0) { AstNode *buf = children[0]->clone(); - while (buf->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (buf->simplify(true, stage, width_hint, sign_hint)) { } if (buf->type != AST_CONSTANT) { // for (auto f : log_files) // dumpAst(f, "verilog-ast> "); @@ -2602,7 +2594,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi } for (size_t i = 0; i < buf->children.size(); i++) { - buf->children[i]->simplify(const_fold, false, stage, -1, false, false); + buf->children[i]->simplify(const_fold, stage, -1, false); current_ast_mod->children.push_back(buf->children[i]); } @@ -2618,7 +2610,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi if (type == AST_GENCASE && children.size() != 0) { AstNode *buf = children[0]->clone(); - while (buf->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (buf->simplify(true, stage, width_hint, sign_hint)) { } if (buf->type != AST_CONSTANT) { // for (auto f : log_files) // dumpAst(f, "verilog-ast> "); @@ -2653,7 +2645,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi buf = child->clone(); buf->set_in_param_flag(true); - while (buf->simplify(true, false, stage, width_hint, sign_hint, true)) { } + while (buf->simplify(true, stage, width_hint, sign_hint)) { } if (buf->type != AST_CONSTANT) { // for (auto f : log_files) // dumpAst(f, "verilog-ast> "); @@ -2681,7 +2673,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi } for (size_t i = 0; i < buf->children.size(); i++) { - buf->children[i]->simplify(const_fold, false, stage, -1, false, false); + buf->children[i]->simplify(const_fold, stage, -1, false); current_ast_mod->children.push_back(buf->children[i]); } @@ -2866,7 +2858,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi if (children[0]->id2ast->attributes.count(ID::nowrshmsk)) { AstNode *node = children[0]->id2ast->attributes.at(ID::nowrshmsk); - while (node->simplify(true, false, stage, -1, false, true)) { } + while (node->simplify(true, stage, -1, false)) { } if (node->type != AST_CONSTANT) input_error("Non-constant value for `nowrshmsk' attribute on `%s'!\n", children[0]->id2ast->str.c_str()); if (node->asAttrConst().as_bool()) @@ -2904,14 +2896,14 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi wire_mask->str = stringf("$bitselwrite$mask$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); wire_mask->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire_mask->is_logic = true; - while (wire_mask->simplify(true, false, 1, -1, false, false)) { } + while (wire_mask->simplify(true, 1, -1, false)) { } current_ast_mod->children.push_back(wire_mask); AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true))); wire_data->str = stringf("$bitselwrite$data$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++); wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire_data->is_logic = true; - while (wire_data->simplify(true, false, 1, -1, false, false)) { } + while (wire_data->simplify(true, 1, -1, false)) { } current_ast_mod->children.push_back(wire_data); int shamt_width_hint = -1; @@ -2923,7 +2915,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue_, int stage, int width_hi wire_sel->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); wire_sel->is_logic = true; wire_sel->is_signed = shamt_sign_hint; - while (wire_sel->simplify(true, false, 1, -1, false, false)) { } + while (wire_sel->simplify(true, 1, -1, false)) { } current_ast_mod->children.push_back(wire_sel); did_something = true; @@ -3008,7 +3000,7 @@ skip_dynamic_range_lvalue_expansion:; wire_check->was_checked = true; current_ast_mod->children.push_back(wire_check); current_scope[wire_check->str] = wire_check; - while (wire_check->simplify(true, false, 1, -1, false, false)) { } + while (wire_check->simplify(true, 1, -1, false)) { } AstNode *wire_en = new AstNode(AST_WIRE); wire_en->str = id_en; @@ -3020,7 +3012,7 @@ skip_dynamic_range_lvalue_expansion:; current_ast_mod->children.back()->children[0]->children[0]->children[0]->was_checked = true; } current_scope[wire_en->str] = wire_en; - while (wire_en->simplify(true, false, 1, -1, false, false)) { } + while (wire_en->simplify(true, 1, -1, false)) { } AstNode *check_defval; if (type == AST_LIVE || type == AST_FAIR) { @@ -3116,7 +3108,7 @@ skip_dynamic_range_lvalue_expansion:; current_ast_mod->children.push_back(wire_tmp); current_scope[wire_tmp->str] = wire_tmp; wire_tmp->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); - while (wire_tmp->simplify(true, false, 1, -1, false, false)) { } + while (wire_tmp->simplify(true, 1, -1, false)) { } wire_tmp->is_logic = true; AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER); @@ -3186,7 +3178,7 @@ skip_dynamic_range_lvalue_expansion:; wire_addr->was_checked = true; current_ast_mod->children.push_back(wire_addr); current_scope[wire_addr->str] = wire_addr; - while (wire_addr->simplify(true, false, 1, -1, false, false)) { } + while (wire_addr->simplify(true, 1, -1, false)) { } AstNode *assign_addr = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false)); assign_addr->children[0]->str = id_addr; @@ -3212,7 +3204,7 @@ skip_dynamic_range_lvalue_expansion:; wire_data->is_signed = mem_signed; current_ast_mod->children.push_back(wire_data); current_scope[wire_data->str] = wire_data; - while (wire_data->simplify(true, false, 1, -1, false, false)) { } + while (wire_data->simplify(true, 1, -1, false)) { } AstNode *assign_data = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false)); assign_data->children[0]->str = id_data; @@ -3228,7 +3220,7 @@ skip_dynamic_range_lvalue_expansion:; wire_en->was_checked = true; current_ast_mod->children.push_back(wire_en); current_scope[wire_en->str] = wire_en; - while (wire_en->simplify(true, false, 1, -1, false, false)) { } + while (wire_en->simplify(true, 1, -1, false)) { } AstNode *assign_en_first = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); assign_en_first->children[0]->str = id_en; @@ -3356,7 +3348,7 @@ skip_dynamic_range_lvalue_expansion:; AstNode *wire = new AstNode(AST_WIRE); wire->str = stringf("$initstate$%d_wire", myidx); current_ast_mod->children.push_back(wire); - while (wire->simplify(true, false, 1, -1, false, false)) { } + while (wire->simplify(true, 1, -1, false)) { } AstNode *cell = new AstNode(AST_CELL, new AstNode(AST_CELLTYPE), new AstNode(AST_ARGUMENT, new AstNode(AST_IDENTIFIER))); cell->str = stringf("$initstate$%d", myidx); @@ -3365,7 +3357,7 @@ skip_dynamic_range_lvalue_expansion:; cell->children[1]->children[0]->str = wire->str; cell->children[1]->children[0]->id2ast = wire; current_ast_mod->children.push_back(cell); - while (cell->simplify(true, false, 1, -1, false, false)) { } + while (cell->simplify(true, 1, -1, false)) { } newNode = new AstNode(AST_IDENTIFIER); newNode->str = wire->str; @@ -3391,7 +3383,7 @@ skip_dynamic_range_lvalue_expansion:; if (GetSize(children) == 2) { AstNode *buf = children[1]->clone(); - while (buf->simplify(true, false, stage, -1, false, false)) { } + while (buf->simplify(true, stage, -1, false)) { } if (buf->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant value.\n", str.c_str()); @@ -3426,7 +3418,7 @@ skip_dynamic_range_lvalue_expansion:; current_ast_mod->children.push_back(reg); - while (reg->simplify(true, false, 1, -1, false, false)) { } + while (reg->simplify(true, 1, -1, false)) { } AstNode *regid = new AstNode(AST_IDENTIFIER); regid->str = reg->str; @@ -3502,7 +3494,7 @@ skip_dynamic_range_lvalue_expansion:; RTLIL::unescape_id(str).c_str(), int(children.size())); AstNode *buf = children[0]->clone(); - while (buf->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (buf->simplify(true, stage, width_hint, sign_hint)) { } if (buf->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant value.\n", str.c_str()); @@ -3534,7 +3526,7 @@ skip_dynamic_range_lvalue_expansion:; if (children.size() == 2) { AstNode *buf = children[1]->clone(); // Evaluate constant expression - while (buf->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (buf->simplify(true, stage, width_hint, sign_hint)) { } dim = buf->asInt(false); delete buf; } @@ -3692,7 +3684,7 @@ skip_dynamic_range_lvalue_expansion:; } if (children.size() >= 1) { - while (children[0]->simplify(true, false, stage, width_hint, sign_hint, in_param)) { } + while (children[0]->simplify(true, stage, width_hint, sign_hint)) { } if (!children[0]->isConst()) input_error("Failed to evaluate system function `%s' with non-constant argument.\n", RTLIL::unescape_id(str).c_str()); @@ -3703,7 +3695,7 @@ skip_dynamic_range_lvalue_expansion:; } if (children.size() >= 2) { - while (children[1]->simplify(true, false, stage, width_hint, sign_hint, in_param)) { } + while (children[1]->simplify(true, stage, width_hint, sign_hint)) { } if (!children[1]->isConst()) input_error("Failed to evaluate system function `%s' with non-constant argument.\n", RTLIL::unescape_id(str).c_str()); @@ -3760,7 +3752,7 @@ skip_dynamic_range_lvalue_expansion:; // Determine which bits to count for (size_t i = 1; i < children.size(); i++) { AstNode *node = children[i]; - while (node->simplify(true, false, stage, -1, false, in_param)) { } + while (node->simplify(true, stage, -1, false)) { } if (node->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant control bit argument.\n", str.c_str()); if (node->bits.size() != 1) @@ -3855,8 +3847,7 @@ skip_dynamic_range_lvalue_expansion:; argtypes.push_back(RTLIL::unescape_id(dpi_decl->children.at(i)->str)); args.push_back(children.at(i-2)->clone()); - args.back()->set_in_param_flag(true); - while (args.back()->simplify(true, false, stage, -1, false, true)) { } + while (args.back()->simplify(true, stage, -1, false)) { } if (args.back()->type != AST_CONSTANT && args.back()->type != AST_REALVALUE) input_error("Failed to evaluate DPI function with non-constant argument.\n"); @@ -3893,12 +3884,12 @@ skip_dynamic_range_lvalue_expansion:; RTLIL::unescape_id(str).c_str(), int(children.size())); AstNode *node_filename = children[0]->clone(); - while (node_filename->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (node_filename->simplify(true, stage, width_hint, sign_hint)) { } if (node_filename->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant 1st argument.\n", str.c_str()); AstNode *node_memory = children[1]->clone(); - while (node_memory->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (node_memory->simplify(true, stage, width_hint, sign_hint)) { } if (node_memory->type != AST_IDENTIFIER || node_memory->id2ast == nullptr || node_memory->id2ast->type != AST_MEMORY) input_error("Failed to evaluate system function `%s' with non-memory 2nd argument.\n", str.c_str()); @@ -3906,7 +3897,7 @@ skip_dynamic_range_lvalue_expansion:; if (GetSize(children) > 2) { AstNode *node_addr = children[2]->clone(); - while (node_addr->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (node_addr->simplify(true, stage, width_hint, sign_hint)) { } if (node_addr->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant 3rd argument.\n", str.c_str()); start_addr = int(node_addr->asInt(false)); @@ -3914,7 +3905,7 @@ skip_dynamic_range_lvalue_expansion:; if (GetSize(children) > 3) { AstNode *node_addr = children[3]->clone(); - while (node_addr->simplify(true, false, stage, width_hint, sign_hint, false)) { } + while (node_addr->simplify(true, stage, width_hint, sign_hint)) { } if (node_addr->type != AST_CONSTANT) input_error("Failed to evaluate system function `%s' with non-constant 4th argument.\n", str.c_str()); finish_addr = int(node_addr->asInt(false)); @@ -3966,7 +3957,7 @@ skip_dynamic_range_lvalue_expansion:; bool require_const_eval = decl->has_const_only_constructs(); bool all_args_const = true; for (auto child : children) { - while (child->simplify(true, in_lvalue, 1, -1, false, in_param)) { } + while (child->simplify(true, 1, -1, false)) { } if (child->type != AST_CONSTANT && child->type != AST_REALVALUE) all_args_const = false; } @@ -4011,7 +4002,7 @@ skip_dynamic_range_lvalue_expansion:; current_scope[wire->str] = wire; current_ast_mod->children.push_back(wire); - while (wire->simplify(true, false, 1, -1, false, false)) { } + while (wire->simplify(true, 1, -1, false)) { } AstNode *lvalue = new AstNode(AST_IDENTIFIER); lvalue->str = wire->str; @@ -4057,7 +4048,7 @@ skip_dynamic_range_lvalue_expansion:; wire->is_input = false; wire->is_output = false; current_ast_mod->children.push_back(wire); - while (wire->simplify(true, false, 1, -1, false, false)) { } + while (wire->simplify(true, 1, -1, false)) { } AstNode *wire_id = new AstNode(AST_IDENTIFIER); wire_id->str = wire->str; @@ -4100,7 +4091,7 @@ skip_dynamic_range_lvalue_expansion:; for (auto c : child->children) wire->children.push_back(c->clone()); } else if (!child->children.empty()) { - while (child->simplify(true, false, stage, -1, false, false)) { } + while (child->simplify(true, stage, -1, false)) { } if (GetSize(child->children) == GetSize(wire->children) - contains_value) { for (int i = 0; i < GetSize(child->children); i++) if (*child->children.at(i) != *wire->children.at(i + contains_value)) @@ -4128,7 +4119,7 @@ skip_dynamic_range_lvalue_expansion:; current_ast_mod->children.push_back(wire); } - while (wire->simplify(true, false, 1, -1, false, false)) { } + while (wire->simplify(true, 1, -1, false)) { } if ((child->is_input || child->is_output) && arg_count < children.size()) { @@ -4161,7 +4152,7 @@ skip_dynamic_range_lvalue_expansion:; } wire->fixup_hierarchy_flags(); // updates the sizing - while (wire->simplify(true, false, 1, -1, false, true)) { } + while (wire->simplify(true, 1, -1, false)) { } delete arg; continue; } @@ -5072,7 +5063,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, wire_addr->was_checked = true; wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); mod->children.push_back(wire_addr); - while (wire_addr->simplify(true, false, 1, -1, false, false)) { } + while (wire_addr->simplify(true, 1, -1, false)) { } AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); wire_data->str = id_data; @@ -5081,7 +5072,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, wire_data->is_signed = mem_signed; wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); mod->children.push_back(wire_data); - while (wire_data->simplify(true, false, 1, -1, false, false)) { } + while (wire_data->simplify(true, 1, -1, false)) { } log_assert(block != NULL); size_t assign_idx = 0; @@ -5194,7 +5185,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, if (block) wire_addr->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); mod->children.push_back(wire_addr); - while (wire_addr->simplify(true, false, 1, -1, false, false)) { } + while (wire_addr->simplify(true, 1, -1, false)) { } AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); wire_data->str = id_data; @@ -5204,7 +5195,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, if (block) wire_data->set_attribute(ID::nosync, AstNode::mkconst_int(1, false)); mod->children.push_back(wire_data); - while (wire_data->simplify(true, false, 1, -1, false, false)) { } + while (wire_data->simplify(true, 1, -1, false)) { } AstNode *assign_addr = new AstNode(block ? AST_ASSIGN_EQ : AST_ASSIGN, new AstNode(AST_IDENTIFIER), children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; @@ -5387,7 +5378,7 @@ bool AstNode::replace_variables(std::map &varia } if (!children.at(0)->replace_variables(variables, fcall, must_succeed)) return false; - while (simplify(true, false, 1, -1, false, true)) { } + while (simplify(true, 1, -1, false)) { } if (!children.at(0)->range_valid) { if (!must_succeed) return false; @@ -5443,7 +5434,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) if (stmt->type == AST_WIRE) { - while (stmt->simplify(true, false, 1, -1, false, true)) { } + while (stmt->simplify(true, 1, -1, false)) { } if (!stmt->range_valid) { if (!must_succeed) goto finished; @@ -5487,7 +5478,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) if (stmt->type == AST_LOCALPARAM) { - while (stmt->simplify(true, false, 1, -1, false, true)) { } + while (stmt->simplify(true, 1, -1, false)) { } current_scope[stmt->str] = stmt; @@ -5504,7 +5495,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) goto finished; if (!stmt->children.at(1)->replace_variables(variables, fcall, must_succeed)) goto finished; - while (stmt->simplify(true, false, 1, -1, false, true)) { } + while (stmt->simplify(true, 1, -1, false)) { } if (stmt->type != AST_ASSIGN_EQ) continue; @@ -5572,7 +5563,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) if (!cond->replace_variables(variables, fcall, must_succeed)) goto finished; cond->set_in_param_flag(true); - while (cond->simplify(true, false, 1, -1, false, true)) { } + while (cond->simplify(true, 1, -1, false)) { } if (cond->type != AST_CONSTANT) { if (!must_succeed) @@ -5598,7 +5589,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) if (!num->replace_variables(variables, fcall, must_succeed)) goto finished; num->set_in_param_flag(true); - while (num->simplify(true, false, 1, -1, false, true)) { } + while (num->simplify(true, 1, -1, false)) { } if (num->type != AST_CONSTANT) { if (!must_succeed) @@ -5622,7 +5613,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) if (!expr->replace_variables(variables, fcall, must_succeed)) goto finished; expr->set_in_param_flag(true); - while (expr->simplify(true, false, 1, -1, false, true)) { } + while (expr->simplify(true, 1, -1, false)) { } AstNode *sel_case = NULL; for (size_t i = 1; i < stmt->children.size(); i++) @@ -5643,7 +5634,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) cond = new AstNode(AST_EQ, expr->clone(), cond); cond->set_in_param_flag(true); - while (cond->simplify(true, false, 1, -1, false, true)) { } + while (cond->simplify(true, 1, -1, false)) { } if (cond->type != AST_CONSTANT) { if (!must_succeed) From c172fef01a23deee96a3b1bf45bdfd7b993376bf Mon Sep 17 00:00:00 2001 From: Wanda Date: Tue, 26 Sep 2023 18:56:54 +0200 Subject: [PATCH 26/95] hashlib: Use a better hash for pool. --- kernel/hashlib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index b3f99bf73..be759fdf0 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -988,7 +988,7 @@ public: return !operator==(other); } - bool hash() const { + unsigned int hash() const { unsigned int hashval = mkhash_init; for (auto &it : entries) hashval ^= ops.hash(it.udata); From 076c5ceb714bc8f20136a83cc9818b96e6a542b4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 27 Sep 2023 00:15:07 +0000 Subject: [PATCH 27/95] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 77f7b80fa..1fb47fa07 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+65 +YOSYS_VER := 0.33+67 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From f193ebdded593c837e9f3447fddf803723f8e5f9 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 27 Sep 2023 16:57:18 +0200 Subject: [PATCH 28/95] Verific: add default parameters to modules --- frontends/verific/verific.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index cd844dcee..310e39180 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1275,9 +1275,16 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma log("Importing module %s.\n", RTLIL::id2cstr(module->name)); } import_attributes(module->attributes, nl, nl); + const char *param_name ; + const char *param_value ; + MapIter mi; + FOREACH_PARAMETER_OF_NETLIST(nl, mi, param_name, param_value) { + module->avail_parameters(RTLIL::escape_id(param_name)); + module->parameter_default_values[RTLIL::escape_id(param_name)] = verific_const(param_value); + } SetIter si; - MapIter mi, mi2; + MapIter mi2; Port *port; PortBus *portbus; Net *net; From ac8b31e000cdcc68c2017070679821d4333f801e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 28 Sep 2023 00:15:01 +0000 Subject: [PATCH 29/95] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1fb47fa07..24184e829 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+67 +YOSYS_VER := 0.33+72 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 01a015747e274480fc5ae8d0fab18d89d04ea8b0 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Wed, 27 Sep 2023 17:16:13 -0700 Subject: [PATCH 30/95] Speed up RTLIL::Const::decode_string by 1.7x. --- kernel/rtlil.cc | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 1b57af60a..3663ca864 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -313,18 +313,33 @@ RTLIL::Const RTLIL::Const::from_string(const std::string &str) std::string RTLIL::Const::decode_string() const { - std::string string; - string.reserve(GetSize(bits)/8); - for (int i = 0; i < GetSize(bits); i += 8) { + const int n = GetSize(bits); + const int n_over_8 = n / 8; + std::string s; + s.reserve(n_over_8); + int i = n_over_8 * 8; + if (i < n) { char ch = 0; - for (int j = 0; j < 8 && i + j < int (bits.size()); j++) - if (bits[i + j] == RTLIL::State::S1) + for (int j = 0; j < (n - i); j++) { + if (bits[j + i] == RTLIL::State::S1) { ch |= 1 << j; + } + } if (ch != 0) - string.append({ch}); + s.append({ch}); } - std::reverse(string.begin(), string.end()); - return string; + i -= 8; + for (; i >= 0; i -= 8) { + char ch = 0; + for (int j = 0; j < 8; j++) { + if (bits[j + i] == RTLIL::State::S1) { + ch |= 1 << j; + } + } + if (ch != 0) + s.append({ch}); + } + return s; } bool RTLIL::Const::is_fully_zero() const @@ -4044,7 +4059,7 @@ void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec other->bits_[j] = with.bits_[it->second]; } } - + other->check(); } From 6b70b3dbefea7972c44e312c356bf7377a7d5f7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 28 Sep 2023 11:50:57 +0200 Subject: [PATCH 31/95] booth: Fix assertion Fix assertion to what it should be per Andy's comments. --- passes/techmap/booth.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index be38c8fc3..000dcff14 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -655,8 +655,7 @@ struct BoothPassWorker { cpa_id++; log_assert(c_vec.size() == s_vec.size()); - // TODO: doesn't pass - //log_assert(result.size() == s_vec.size() + 2); + log_assert(result.size() == s_vec.size()); SigBit carry; for (int n = 0; n < s_vec.size(); n++) { From b0045300fd7ee6a123d3a3a373448e4780c3bcfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 28 Sep 2023 11:55:51 +0200 Subject: [PATCH 32/95] booth: Cut down the test Cut the test down from taking ~25 s to ~3 s. --- tests/techmap/booth.ys | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/techmap/booth.ys b/tests/techmap/booth.ys index f1dce1f3b..ab7efc7b7 100644 --- a/tests/techmap/booth.ys +++ b/tests/techmap/booth.ys @@ -1 +1 @@ -test_cell -s 1694091355 -n 1000 -script booth_map_script.ys_ $mul +test_cell -s 1694091355 -n 100 -script booth_map_script.ys_ $mul From 7eaa4bcb4605d6c1d30d4daf96a94cea3b423df3 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Thu, 28 Sep 2023 17:29:24 +0200 Subject: [PATCH 33/95] sim: Add -noinitstate option and handle non-cosim initstate This adds the -noinitstate option which is required to simulate counterexamples to induction with yw-cosim. Also add handling for $initstate cells for non-co-simulation. --- passes/sat/sim.cc | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 1e6645303..963c6481b 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -111,6 +111,7 @@ struct SimShared int step = 0; std::vector triggered_assertions; bool serious_asserts = false; + bool initstate = true; }; void zinit(State &v) @@ -1356,6 +1357,8 @@ struct SimWorker : SimShared set_inports(clock, State::Sx); set_inports(clockn, State::Sx); + top->set_initstate_outputs(initstate ? State::S1 : State::S0); + update(false); register_output_step(0); @@ -1372,6 +1375,9 @@ struct SimWorker : SimShared update(true); register_output_step(10*cycle + 5); + if (cycle == 0) + top->set_initstate_outputs(State::S0); + if (debug) log("\n===== %d =====\n", 10*cycle + 10); else if (verbose) @@ -1953,7 +1959,7 @@ struct SimWorker : SimShared if (yw.steps.empty()) { log_warning("Yosys witness file `%s` contains no time steps\n", yw.filename.c_str()); } else { - top->set_initstate_outputs(State::S1); + top->set_initstate_outputs(initstate ? State::S1 : State::S0); set_yw_state(yw, hierarchy, 0); set_yw_clocks(yw, hierarchy, true); initialize_stable_past(); @@ -2546,6 +2552,9 @@ struct SimPass : public Pass { log(" -n \n"); log(" number of clock cycles to simulate (default: 20)\n"); log("\n"); + log(" -noinitstate\n"); + log(" do not activate $initstate cells during the first cycle\n"); + log("\n"); log(" -a\n"); log(" use all nets in VCD/FST operations, not just those with public names\n"); log("\n"); @@ -2646,6 +2655,10 @@ struct SimPass : public Pass { worker.cycles_set = true; continue; } + if (args[argidx] == "-noinitstate") { + worker.initstate = false; + continue; + } if (args[argidx] == "-rstlen" && argidx+1 < args.size()) { worker.rstlen = atoi(args[++argidx].c_str()); continue; From 5daa49bafbcb40816e9a56f249568127d275c59d Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Thu, 28 Sep 2023 17:32:19 +0200 Subject: [PATCH 34/95] dft_tag: Fix size extending $x[n]or and $reduce_{or,bool}/$logic_not --- passes/cmds/dft_tag.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/passes/cmds/dft_tag.cc b/passes/cmds/dft_tag.cc index 9fd356ef6..2b2340dab 100644 --- a/passes/cmds/dft_tag.cc +++ b/passes/cmds/dft_tag.cc @@ -405,7 +405,7 @@ struct DftTagWorker { auto &sig_y = cell->getPort(ID::Y); auto sig_a = cell->getPort(ID::A); auto sig_b = cell->getPort(ID::B); - if (cell->type.in(ID($and), ID($or))) { + if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor))) { sig_a.extend_u0(GetSize(sig_y), cell->getParam(ID::A_SIGNED).as_bool()); sig_b.extend_u0(GetSize(sig_y), cell->getParam(ID::B_SIGNED).as_bool()); } @@ -669,12 +669,12 @@ struct DftTagWorker { auto &sig_y = cell->getPort(ID::Y); auto sig_a = cell->getPort(ID::A); - if (cell->type.in(ID($reduce_or), ID($reduce_bool), ID($logic_not))) - sig_a = autoNot(NEW_ID, sig_a); - auto group_sig_a = tag_group_signal(tag, sig_a); auto tag_sig_a = tag_signal(tag, sig_a); + if (cell->type.in(ID($reduce_or), ID($reduce_bool), ID($logic_not))) + sig_a = autoNot(NEW_ID, sig_a); + auto filled = autoOr(NEW_ID, sig_a, group_sig_a); auto prop = autoReduceAnd(NEW_ID, filled); From 12218a4c744cb3877e5d9e78d15b7c2d90667907 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Thu, 28 Sep 2023 19:39:09 -0700 Subject: [PATCH 35/95] Unflip i and j. --- kernel/rtlil.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 3663ca864..9834a0d37 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -321,7 +321,7 @@ std::string RTLIL::Const::decode_string() const if (i < n) { char ch = 0; for (int j = 0; j < (n - i); j++) { - if (bits[j + i] == RTLIL::State::S1) { + if (bits[i + j] == RTLIL::State::S1) { ch |= 1 << j; } } @@ -332,7 +332,7 @@ std::string RTLIL::Const::decode_string() const for (; i >= 0; i -= 8) { char ch = 0; for (int j = 0; j < 8; j++) { - if (bits[j + i] == RTLIL::State::S1) { + if (bits[i + j] == RTLIL::State::S1) { ch |= 1 << j; } } From cc843d414f7a68c0140c0bc038b937210650ba78 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Fri, 29 Sep 2023 12:28:50 +0200 Subject: [PATCH 36/95] simplify: Avoid calling fixup_hierarchy_flags on nullptr Compiling on GCC hid this bug as it optimized the nullptr call away as undefined behavior, but running the SBY tests with a clang build hits this error. --- frontends/ast/simplify.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index c4a303027..c5f046704 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -3042,8 +3042,8 @@ skip_dynamic_range_lvalue_expansion:; assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_REDUCE_BOOL, children[0]->clone())); assign_check->children[0]->str = id_check; assign_check->children[0]->was_checked = true; + assign_check->fixup_hierarchy_flags(); } - assign_check->fixup_hierarchy_flags(); if (current_always == nullptr || current_always->type != AST_INITIAL) { assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1)); From b52f6cb1991b7117d23fa119bf808f9fc1849789 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 30 Sep 2023 00:14:39 +0000 Subject: [PATCH 37/95] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 24184e829..a96f3f549 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+72 +YOSYS_VER := 0.33+79 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 98d2c9088acfc1da368e36f15bc5d40a61718079 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Fri, 29 Sep 2023 13:26:22 -0700 Subject: [PATCH 38/95] Ignore emacs auto-save files. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 49b886e7e..9b799c1f3 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.gch *.gcda *.gcno +*~ __pycache__ /.cproject /.project From abd9c519634f5279cb7f85a6884d47d23a8583e4 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Fri, 29 Sep 2023 10:53:37 -0700 Subject: [PATCH 39/95] Speed up simplemap_map by 11.6x by directly inserting the cell source attribute in the new object's 'attributes' map instead of calling set_attr_pool to create a new pool and then copying that. Based on a suggestion by Martin Poviser in a comment on https://github.com/YosysHQ/yosys/pull/3959 --- passes/techmap/simplemap.cc | 228 ++++++++++++++++-------------- passes/techmap/techmap.cc | 274 +++++++++++++++++------------------- 2 files changed, 252 insertions(+), 250 deletions(-) diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc index 11692b715..14c07922b 100644 --- a/passes/techmap/simplemap.cc +++ b/passes/techmap/simplemap.cc @@ -18,10 +18,10 @@ */ #include "simplemap.h" -#include "kernel/sigtools.h" #include "kernel/ff.h" -#include +#include "kernel/sigtools.h" #include +#include #include USING_YOSYS_NAMESPACE @@ -36,7 +36,7 @@ void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell) for (int i = 0; i < GetSize(sig_y); i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a[i]); gate->setPort(ID::Y, sig_y[i]); } @@ -64,16 +64,21 @@ void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell) } IdString gate_type; - if (cell->type == ID($and)) gate_type = ID($_AND_); - if (cell->type == ID($or)) gate_type = ID($_OR_); - if (cell->type == ID($xor)) gate_type = ID($_XOR_); - if (cell->type == ID($xnor)) gate_type = ID($_XNOR_); - if (cell->type == ID($bweqx)) gate_type = ID($_XNOR_); + if (cell->type == ID($and)) + gate_type = ID($_AND_); + if (cell->type == ID($or)) + gate_type = ID($_OR_); + if (cell->type == ID($xor)) + gate_type = ID($_XOR_); + if (cell->type == ID($xnor)) + gate_type = ID($_XNOR_); + if (cell->type == ID($bweqx)) + gate_type = ID($_XNOR_); log_assert(!gate_type.empty()); for (int i = 0; i < GetSize(sig_y); i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a[i]); gate->setPort(ID::B, sig_b[i]); gate->setPort(ID::Y, sig_y[i]); @@ -89,45 +94,53 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) return; if (sig_a.size() == 0) { - if (cell->type == ID($reduce_and)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); - if (cell->type == ID($reduce_or)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); - if (cell->type == ID($reduce_xor)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); - if (cell->type == ID($reduce_xnor)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); - if (cell->type == ID($reduce_bool)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); + if (cell->type == ID($reduce_and)) + module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); + if (cell->type == ID($reduce_or)) + module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); + if (cell->type == ID($reduce_xor)) + module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); + if (cell->type == ID($reduce_xnor)) + module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); + if (cell->type == ID($reduce_bool)) + module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); return; } if (sig_y.size() > 1) { - module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1))); + module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size() - 1), RTLIL::SigSpec(0, sig_y.size() - 1))); sig_y = sig_y.extract(0, 1); } IdString gate_type; - if (cell->type == ID($reduce_and)) gate_type = ID($_AND_); - if (cell->type == ID($reduce_or)) gate_type = ID($_OR_); - if (cell->type == ID($reduce_xor)) gate_type = ID($_XOR_); - if (cell->type == ID($reduce_xnor)) gate_type = ID($_XOR_); - if (cell->type == ID($reduce_bool)) gate_type = ID($_OR_); + if (cell->type == ID($reduce_and)) + gate_type = ID($_AND_); + if (cell->type == ID($reduce_or)) + gate_type = ID($_OR_); + if (cell->type == ID($reduce_xor)) + gate_type = ID($_XOR_); + if (cell->type == ID($reduce_xnor)) + gate_type = ID($_XOR_); + if (cell->type == ID($reduce_bool)) + gate_type = ID($_OR_); log_assert(!gate_type.empty()); RTLIL::Cell *last_output_cell = NULL; - while (sig_a.size() > 1) - { + while (sig_a.size() > 1) { RTLIL::SigSpec sig_t = module->addWire(NEW_ID, sig_a.size() / 2); - for (int i = 0; i < sig_a.size(); i += 2) - { - if (i+1 == sig_a.size()) { + for (int i = 0; i < sig_a.size(); i += 2) { + if (i + 1 == sig_a.size()) { sig_t.append(sig_a[i]); continue; } RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a[i]); - gate->setPort(ID::B, sig_a[i+1]); - gate->setPort(ID::Y, sig_t[i/2]); + gate->setPort(ID::B, sig_a[i + 1]); + gate->setPort(ID::Y, sig_t[i / 2]); last_output_cell = gate; } @@ -137,7 +150,7 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) if (cell->type == ID($reduce_xnor)) { RTLIL::SigSpec sig_t = module->addWire(NEW_ID); RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a); gate->setPort(ID::Y, sig_t); last_output_cell = gate; @@ -153,22 +166,20 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig, RTLIL::Cell *cell) { - while (sig.size() > 1) - { + while (sig.size() > 1) { RTLIL::SigSpec sig_t = module->addWire(NEW_ID, sig.size() / 2); - for (int i = 0; i < sig.size(); i += 2) - { - if (i+1 == sig.size()) { + for (int i = 0; i < sig.size(); i += 2) { + if (i + 1 == sig.size()) { sig_t.append(sig[i]); continue; } RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_OR_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig[i]); - gate->setPort(ID::B, sig[i+1]); - gate->setPort(ID::Y, sig_t[i/2]); + gate->setPort(ID::B, sig[i + 1]); + gate->setPort(ID::Y, sig_t[i / 2]); } sig = sig_t; @@ -189,12 +200,12 @@ void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell) return; if (sig_y.size() > 1) { - module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1))); + module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size() - 1), RTLIL::SigSpec(0, sig_y.size() - 1))); sig_y = sig_y.extract(0, 1); } RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a); gate->setPort(ID::Y, sig_y); } @@ -213,17 +224,19 @@ void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell) return; if (sig_y.size() > 1) { - module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1))); + module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size() - 1), RTLIL::SigSpec(0, sig_y.size() - 1))); sig_y = sig_y.extract(0, 1); } IdString gate_type; - if (cell->type == ID($logic_and)) gate_type = ID($_AND_); - if (cell->type == ID($logic_or)) gate_type = ID($_OR_); + if (cell->type == ID($logic_and)) + gate_type = ID($_AND_); + if (cell->type == ID($logic_or)) + gate_type = ID($_OR_); log_assert(!gate_type.empty()); RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a); gate->setPort(ID::B, sig_b); gate->setPort(ID::Y, sig_y); @@ -239,19 +252,22 @@ void simplemap_eqne(RTLIL::Module *module, RTLIL::Cell *cell) RTLIL::SigSpec xor_out = module->addWire(NEW_ID, max(GetSize(sig_a), GetSize(sig_b))); RTLIL::Cell *xor_cell = module->addXor(NEW_ID, sig_a, sig_b, xor_out, is_signed); - xor_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + xor_cell->attributes[ID::src] = cell->attributes[ID::src]; + // xor_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); simplemap_bitop(module, xor_cell); module->remove(xor_cell); RTLIL::SigSpec reduce_out = is_ne ? sig_y : module->addWire(NEW_ID); RTLIL::Cell *reduce_cell = module->addReduceOr(NEW_ID, xor_out, reduce_out); - reduce_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + reduce_cell->attributes[ID::src] = cell->attributes[ID::src]; + // reduce_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); simplemap_reduce(module, reduce_cell); module->remove(reduce_cell); if (!is_ne) { RTLIL::Cell *not_cell = module->addLogicNot(NEW_ID, reduce_out, sig_y); - not_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + not_cell->attributes[ID::src] = cell->attributes[ID::src]; + // not_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); simplemap_lognot(module, not_cell); module->remove(not_cell); } @@ -265,7 +281,7 @@ void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell) for (int i = 0; i < GetSize(sig_y); i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a[i]); gate->setPort(ID::B, sig_b[i]); gate->setPort(ID::S, cell->getPort(ID::S)); @@ -282,7 +298,7 @@ void simplemap_bwmux(RTLIL::Module *module, RTLIL::Cell *cell) for (int i = 0; i < GetSize(sig_y); i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a[i]); gate->setPort(ID::B, sig_b[i]); gate->setPort(ID::S, sig_s[i]); @@ -298,7 +314,7 @@ void simplemap_tribuf(RTLIL::Module *module, RTLIL::Cell *cell) for (int i = 0; i < GetSize(sig_y); i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_TBUF_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a[i]); gate->setPort(ID::E, sig_e); gate->setPort(ID::Y, sig_y[i]); @@ -312,15 +328,15 @@ void simplemap_bmux(RTLIL::Module *module, RTLIL::Cell *cell) int width = GetSize(cell->getPort(ID::Y)); for (int idx = 0; idx < GetSize(sel); idx++) { - SigSpec new_data = module->addWire(NEW_ID, GetSize(data)/2); + SigSpec new_data = module->addWire(NEW_ID, GetSize(data) / 2); for (int i = 0; i < GetSize(new_data); i += width) { for (int k = 0; k < width; k++) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); - gate->setPort(ID::A, data[i*2+k]); - gate->setPort(ID::B, data[i*2+width+k]); + gate->attributes[ID::src] = cell->attributes[ID::src]; + gate->setPort(ID::A, data[i * 2 + k]); + gate->setPort(ID::B, data[i * 2 + width + k]); gate->setPort(ID::S, sel[idx]); - gate->setPort(ID::Y, new_data[i+k]); + gate->setPort(ID::Y, new_data[i + k]); } } data = new_data; @@ -336,14 +352,14 @@ void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell) lut_data.extend_u0(1 << cell->getParam(ID::WIDTH).as_int()); for (int idx = 0; GetSize(lut_data) > 1; idx++) { - SigSpec new_lut_data = module->addWire(NEW_ID, GetSize(lut_data)/2); + SigSpec new_lut_data = module->addWire(NEW_ID, GetSize(lut_data) / 2); for (int i = 0; i < GetSize(lut_data); i += 2) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_)); - gate->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, lut_data[i]); - gate->setPort(ID::B, lut_data[i+1]); + gate->setPort(ID::B, lut_data[i + 1]); gate->setPort(ID::S, lut_ctrl[idx]); - gate->setPort(ID::Y, new_lut_data[i/2]); + gate->setPort(ID::Y, new_lut_data[i / 2]); } lut_data = new_lut_data; } @@ -365,11 +381,11 @@ void simplemap_sop(RTLIL::Module *module, RTLIL::Cell *cell) for (int i = 0; i < depth; i++) { SigSpec in, pat; for (int j = 0; j < width; j++) { - if (table[2*i*width + 2*j + 0] == State::S1) { + if (table[2 * i * width + 2 * j + 0] == State::S1) { in.append(ctrl[j]); pat.append(State::S0); } - if (table[2*i*width + 2*j + 1] == State::S1) { + if (table[2 * i * width + 2 * j + 1] == State::S1) { in.append(ctrl[j]); pat.append(State::S1); } @@ -407,56 +423,56 @@ void simplemap_ff(RTLIL::Module *, RTLIL::Cell *cell) } } -void simplemap_get_mappers(dict &mappers) +void simplemap_get_mappers(dict &mappers) { - mappers[ID($not)] = simplemap_not; - mappers[ID($pos)] = simplemap_pos; - mappers[ID($and)] = simplemap_bitop; - mappers[ID($or)] = simplemap_bitop; - mappers[ID($xor)] = simplemap_bitop; - mappers[ID($xnor)] = simplemap_bitop; - mappers[ID($bweqx)] = simplemap_bitop; - mappers[ID($reduce_and)] = simplemap_reduce; - mappers[ID($reduce_or)] = simplemap_reduce; - mappers[ID($reduce_xor)] = simplemap_reduce; + mappers[ID($not)] = simplemap_not; + mappers[ID($pos)] = simplemap_pos; + mappers[ID($and)] = simplemap_bitop; + mappers[ID($or)] = simplemap_bitop; + mappers[ID($xor)] = simplemap_bitop; + mappers[ID($xnor)] = simplemap_bitop; + mappers[ID($bweqx)] = simplemap_bitop; + mappers[ID($reduce_and)] = simplemap_reduce; + mappers[ID($reduce_or)] = simplemap_reduce; + mappers[ID($reduce_xor)] = simplemap_reduce; mappers[ID($reduce_xnor)] = simplemap_reduce; mappers[ID($reduce_bool)] = simplemap_reduce; - mappers[ID($logic_not)] = simplemap_lognot; - mappers[ID($logic_and)] = simplemap_logbin; - mappers[ID($logic_or)] = simplemap_logbin; - mappers[ID($eq)] = simplemap_eqne; - mappers[ID($eqx)] = simplemap_eqne; - mappers[ID($ne)] = simplemap_eqne; - mappers[ID($nex)] = simplemap_eqne; - mappers[ID($mux)] = simplemap_mux; - mappers[ID($bwmux)] = simplemap_bwmux; - mappers[ID($tribuf)] = simplemap_tribuf; - mappers[ID($bmux)] = simplemap_bmux; - mappers[ID($lut)] = simplemap_lut; - mappers[ID($sop)] = simplemap_sop; - mappers[ID($slice)] = simplemap_slice; - mappers[ID($concat)] = simplemap_concat; - mappers[ID($sr)] = simplemap_ff; - mappers[ID($ff)] = simplemap_ff; - mappers[ID($dff)] = simplemap_ff; - mappers[ID($dffe)] = simplemap_ff; - mappers[ID($dffsr)] = simplemap_ff; - mappers[ID($dffsre)] = simplemap_ff; - mappers[ID($adff)] = simplemap_ff; - mappers[ID($sdff)] = simplemap_ff; - mappers[ID($adffe)] = simplemap_ff; - mappers[ID($sdffe)] = simplemap_ff; - mappers[ID($sdffce)] = simplemap_ff; - mappers[ID($aldff)] = simplemap_ff; - mappers[ID($aldffe)] = simplemap_ff; - mappers[ID($dlatch)] = simplemap_ff; - mappers[ID($adlatch)] = simplemap_ff; - mappers[ID($dlatchsr)] = simplemap_ff; + mappers[ID($logic_not)] = simplemap_lognot; + mappers[ID($logic_and)] = simplemap_logbin; + mappers[ID($logic_or)] = simplemap_logbin; + mappers[ID($eq)] = simplemap_eqne; + mappers[ID($eqx)] = simplemap_eqne; + mappers[ID($ne)] = simplemap_eqne; + mappers[ID($nex)] = simplemap_eqne; + mappers[ID($mux)] = simplemap_mux; + mappers[ID($bwmux)] = simplemap_bwmux; + mappers[ID($tribuf)] = simplemap_tribuf; + mappers[ID($bmux)] = simplemap_bmux; + mappers[ID($lut)] = simplemap_lut; + mappers[ID($sop)] = simplemap_sop; + mappers[ID($slice)] = simplemap_slice; + mappers[ID($concat)] = simplemap_concat; + mappers[ID($sr)] = simplemap_ff; + mappers[ID($ff)] = simplemap_ff; + mappers[ID($dff)] = simplemap_ff; + mappers[ID($dffe)] = simplemap_ff; + mappers[ID($dffsr)] = simplemap_ff; + mappers[ID($dffsre)] = simplemap_ff; + mappers[ID($adff)] = simplemap_ff; + mappers[ID($sdff)] = simplemap_ff; + mappers[ID($adffe)] = simplemap_ff; + mappers[ID($sdffe)] = simplemap_ff; + mappers[ID($sdffce)] = simplemap_ff; + mappers[ID($aldff)] = simplemap_ff; + mappers[ID($aldffe)] = simplemap_ff; + mappers[ID($dlatch)] = simplemap_ff; + mappers[ID($adlatch)] = simplemap_ff; + mappers[ID($dlatchsr)] = simplemap_ff; } void simplemap(RTLIL::Module *module, RTLIL::Cell *cell) { - static dict mappers; + static dict mappers; static bool initialized_mappers = false; if (!initialized_mappers) { @@ -471,7 +487,7 @@ YOSYS_NAMESPACE_END PRIVATE_NAMESPACE_BEGIN struct SimplemapPass : public Pass { - SimplemapPass() : Pass("simplemap", "mapping simple coarse-grain cells") { } + SimplemapPass() : Pass("simplemap", "mapping simple coarse-grain cells") {} void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -493,13 +509,13 @@ struct SimplemapPass : public Pass { log_header(design, "Executing SIMPLEMAP pass (map simple cells to gate primitives).\n"); extra_args(args, 1, design); - dict mappers; + dict mappers; simplemap_get_mappers(mappers); for (auto mod : design->modules()) { if (!design->selected(mod) || mod->get_blackbox_attribute()) continue; - std::vector cells = mod->cells(); + std::vector cells = mod->cells(); for (auto cell : cells) { if (mappers.count(cell->type) == 0) continue; diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 144f596c8..52a24dcf3 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -17,14 +17,14 @@ * */ -#include "kernel/yosys.h" -#include "kernel/utils.h" -#include "kernel/sigtools.h" #include "kernel/ffinit.h" +#include "kernel/sigtools.h" +#include "kernel/utils.h" +#include "kernel/yosys.h" #include "libs/sha1/sha1.h" -#include #include +#include #include #include "simplemap.h" @@ -42,7 +42,7 @@ PRIVATE_NAMESPACE_BEGIN void apply_prefix(IdString prefix, IdString &id) { if (id[0] == '\\') - id = stringf("%s.%s", prefix.c_str(), id.c_str()+1); + id = stringf("%s.%s", prefix.c_str(), id.c_str() + 1); else id = stringf("$techmap%s.%s", prefix.c_str(), id.c_str()); } @@ -60,13 +60,12 @@ void apply_prefix(IdString prefix, RTLIL::SigSpec &sig, RTLIL::Module *module) sig = chunks; } -struct TechmapWorker -{ - dict simplemap_mappers; - dict>, RTLIL::Module*> techmap_cache; - dict techmap_do_cache; - pool module_queue; - dict sigmaps; +struct TechmapWorker { + dict simplemap_mappers; + dict>, RTLIL::Module *> techmap_cache; + dict techmap_do_cache; + pool module_queue; + dict sigmaps; pool log_msg_cache; @@ -98,9 +97,9 @@ struct TechmapWorker } else if (connbits_map.count(bit)) { if (verbose) log(" Bit %d of port %s and bit %d of port %s are connected.\n", i, log_id(conn.first), - connbits_map.at(bit).second, log_id(connbits_map.at(bit).first)); - constmap_info += stringf("|%s %d %s %d", log_id(conn.first), i, - log_id(connbits_map.at(bit).first), connbits_map.at(bit).second); + connbits_map.at(bit).second, log_id(connbits_map.at(bit).first)); + constmap_info += stringf("|%s %d %s %d", log_id(conn.first), i, log_id(connbits_map.at(bit).first), + connbits_map.at(bit).second); } else { connbits_map.emplace(bit, std::make_pair(conn.first, i)); constmap_info += stringf("|%s %d", log_id(conn.first), i); @@ -134,8 +133,8 @@ struct TechmapWorker if (!result.empty()) { SigMap sigmap(module); for (auto &it1 : result) - for (auto &it2 : it1.second) - sigmap.apply(it2.value); + for (auto &it2 : it1.second) + sigmap.apply(it2.value); } return result; @@ -146,7 +145,7 @@ struct TechmapWorker if (tpl->processes.size() != 0) { log("Technology map yielded processes:"); for (auto &it : tpl->processes) - log(" %s",log_id(it.first)); + log(" %s", log_id(it.first)); log("\n"); if (autoproc_mode) { Pass::call_on_module(tpl->design, tpl, "proc"); @@ -156,7 +155,6 @@ struct TechmapWorker } std::string orig_cell_name; - pool extra_src_attrs = cell->get_strpool_attribute(ID::src); orig_cell_name = cell->name.str(); for (auto tpl_cell : tpl->cells()) @@ -166,32 +164,28 @@ struct TechmapWorker } dict memory_renames; - for (auto &it : tpl->memories) { IdString m_name = it.first; apply_prefix(cell->name, m_name); RTLIL::Memory *m = module->addMemory(m_name, it.second); if (m->attributes.count(ID::src)) - m->add_strpool_attribute(ID::src, extra_src_attrs); + m->attributes[ID::src] = cell->attributes[ID::src]; memory_renames[it.first] = m->name; design->select(module, m); } dict positional_ports; - dict temp_renamed_wires; + dict temp_renamed_wires; pool autopurge_tpl_bits; - for (auto tpl_w : tpl->wires()) - { - if (tpl_w->port_id > 0) - { + for (auto tpl_w : tpl->wires()) { + if (tpl_w->port_id > 0) { IdString posportname = stringf("$%d", tpl_w->port_id); positional_ports.emplace(posportname, tpl_w->name); if (tpl_w->get_bool_attribute(ID::techmap_autopurge) && - (!cell->hasPort(tpl_w->name) || !GetSize(cell->getPort(tpl_w->name))) && - (!cell->hasPort(posportname) || !GetSize(cell->getPort(posportname)))) - { + (!cell->hasPort(tpl_w->name) || !GetSize(cell->getPort(tpl_w->name))) && + (!cell->hasPort(posportname) || !GetSize(cell->getPort(posportname)))) { if (sigmaps.count(tpl) == 0) sigmaps[tpl].set(tpl); @@ -217,7 +211,7 @@ struct TechmapWorker if (tpl_w->get_bool_attribute(ID::_techmap_special_)) w->attributes.clear(); if (w->attributes.count(ID::src)) - w->add_strpool_attribute(ID::src, extra_src_attrs); + w->attributes[ID::src] = cell->attributes[ID::src]; } design->select(module, w); @@ -230,24 +224,24 @@ struct TechmapWorker pool tpl_written_bits; for (auto tpl_cell : tpl->cells()) - for (auto &conn : tpl_cell->connections()) - if (tpl_cell->output(conn.first)) - for (auto bit : conn.second) - tpl_written_bits.insert(bit); + for (auto &conn : tpl_cell->connections()) + if (tpl_cell->output(conn.first)) + for (auto bit : conn.second) + tpl_written_bits.insert(bit); for (auto &conn : tpl->connections()) for (auto bit : conn.first) tpl_written_bits.insert(bit); SigMap port_signal_map; - for (auto &it : cell->connections()) - { + for (auto &it : cell->connections()) { IdString portname = it.first; if (positional_ports.count(portname) > 0) portname = positional_ports.at(portname); if (tpl->wire(portname) == nullptr || tpl->wire(portname)->port_id == 0) { if (portname.begins_with("$")) - log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str()); + log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), + tpl->name.c_str()); continue; } @@ -297,8 +291,7 @@ struct TechmapWorker if (w->port_output && !w->port_input) { port_signal_map.add(c.second, c.first); - } else - if (!w->port_output && w->port_input) { + } else if (!w->port_output && w->port_input) { port_signal_map.add(c.first, c.second); } else { module->connect(c); @@ -311,16 +304,15 @@ struct TechmapWorker auto lhs = GetSize(extra_connect.first); auto rhs = GetSize(extra_connect.second); if (lhs > rhs) - extra_connect.first.remove(rhs, lhs-rhs); + extra_connect.first.remove(rhs, lhs - rhs); else if (rhs > lhs) - extra_connect.second.remove(lhs, rhs-lhs); + extra_connect.second.remove(lhs, rhs - lhs); module->connect(extra_connect); break; } } - for (auto tpl_cell : tpl->cells()) - { + for (auto tpl_cell : tpl->cells()) { IdString c_name = tpl_cell->name; bool techmap_replace_cell = c_name.ends_with("_TECHMAP_REPLACE_"); @@ -339,8 +331,7 @@ struct TechmapWorker vector autopurge_ports; - for (auto &conn : c->connections()) - { + for (auto &conn : c->connections()) { bool autopurge = false; if (!autopurge_tpl_bits.empty()) { autopurge = GetSize(conn.second) != 0; @@ -375,7 +366,7 @@ struct TechmapWorker } if (c->attributes.count(ID::src)) - c->add_strpool_attribute(ID::src, extra_src_attrs); + c->attributes[ID::src] = cell->attributes[ID::src]; if (techmap_replace_cell) { for (auto attr : cell->attributes) @@ -396,8 +387,7 @@ struct TechmapWorker module->remove(cell); - for (auto &it : temp_renamed_wires) - { + for (auto &it : temp_renamed_wires) { Wire *w = it.first; IdString name = it.second; IdString altname = module->uniquify(name); @@ -407,8 +397,8 @@ struct TechmapWorker } } - bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, pool &handled_cells, - const dict> &celltypeMap, bool in_recursion) + bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, pool &handled_cells, + const dict> &celltypeMap, bool in_recursion) { std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping"; @@ -422,12 +412,11 @@ struct TechmapWorker SigMap sigmap(module); FfInitVals initvals(&sigmap, module); - TopoSort> cells; - dict> cell_to_inbit; - dict> outbit_to_cell; + TopoSort> cells; + dict> cell_to_inbit; + dict> outbit_to_cell; - for (auto cell : module->selected_cells()) - { + for (auto cell : module->selected_cells()) { if (handled_cells.count(cell) > 0) continue; @@ -441,8 +430,7 @@ struct TechmapWorker continue; } - for (auto &conn : cell->connections()) - { + for (auto &conn : cell->connections()) { RTLIL::SigSpec sig = sigmap(conn.second); sig.remove_const(); @@ -464,14 +452,13 @@ struct TechmapWorker } for (auto &it_right : cell_to_inbit) - for (auto &it_sigbit : it_right.second) - for (auto &it_left : outbit_to_cell[it_sigbit]) - cells.edge(it_left, it_right.first); + for (auto &it_sigbit : it_right.second) + for (auto &it_left : outbit_to_cell[it_sigbit]) + cells.edge(it_left, it_right.first); cells.sort(); - for (auto cell : cells.sorted) - { + for (auto cell : cells.sorted) { log_assert(handled_cells.count(cell) == 0); log_assert(cell == module->cell(cell->name)); bool mapped_cell = false; @@ -481,8 +468,7 @@ struct TechmapWorker if (in_recursion && cell->type.begins_with("\\$")) cell_type = cell_type.substr(1); - for (auto &tpl_name : celltypeMap.at(cell_type)) - { + for (auto &tpl_name : celltypeMap.at(cell_type)) { IdString derived_name = tpl_name; RTLIL::Module *tpl = map->module(tpl_name); dict parameters(cell->parameters); @@ -501,12 +487,10 @@ struct TechmapWorker if (tpl->attributes.count(ID::techmap_wrap)) extmapper_name = "wrap"; - if (!extmapper_name.empty()) - { + if (!extmapper_name.empty()) { cell->type = cell_type; - if ((extern_mode && !in_recursion) || extmapper_name == "wrap") - { + if ((extern_mode && !in_recursion) || extmapper_name == "wrap") { std::string m_name = stringf("$extern:%s:%s", extmapper_name.c_str(), log_id(cell->type)); for (auto &c : cell->parameters) @@ -518,8 +502,7 @@ struct TechmapWorker RTLIL::Design *extmapper_design = extern_mode && !in_recursion ? design : tpl->design; RTLIL::Module *extmapper_module = extmapper_design->module(m_name); - if (extmapper_module == nullptr) - { + if (extmapper_module == nullptr) { extmapper_module = extmapper_design->addModule(m_name); RTLIL::Cell *extmapper_cell = extmapper_module->addCell(cell->type, cell); @@ -542,7 +525,8 @@ struct TechmapWorker if (extmapper_name == "simplemap") { log("Creating %s with simplemap.\n", log_id(extmapper_module)); if (simplemap_mappers.count(extmapper_cell->type) == 0) - log_error("No simplemap mapper for cell type %s found!\n", log_id(extmapper_cell->type)); + log_error("No simplemap mapper for cell type %s found!\n", + log_id(extmapper_cell->type)); simplemap_mappers.at(extmapper_cell->type)(extmapper_module, extmapper_cell); extmapper_module->remove(extmapper_cell); } @@ -550,7 +534,8 @@ struct TechmapWorker if (extmapper_name == "maccmap") { log("Creating %s with maccmap.\n", log_id(extmapper_module)); if (extmapper_cell->type != ID($macc)) - log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(extmapper_cell->type)); + log_error("The maccmap mapper can only map $macc (not %s) cells!\n", + log_id(extmapper_cell->type)); maccmap(extmapper_module, extmapper_cell); extmapper_module->remove(extmapper_cell); } @@ -572,21 +557,23 @@ struct TechmapWorker goto use_wrapper_tpl; } - auto msg = stringf("Using extmapper %s for cells of type %s.", log_id(extmapper_module), log_id(cell->type)); + auto msg = + stringf("Using extmapper %s for cells of type %s.", log_id(extmapper_module), log_id(cell->type)); if (!log_msg_cache.count(msg)) { log_msg_cache.insert(msg); log("%s\n", msg.c_str()); } - log_debug("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(extmapper_module)); - } - else - { - auto msg = stringf("Using extmapper %s for cells of type %s.", extmapper_name.c_str(), log_id(cell->type)); + log_debug("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), + log_id(cell->type), log_id(extmapper_module)); + } else { + auto msg = + stringf("Using extmapper %s for cells of type %s.", extmapper_name.c_str(), log_id(cell->type)); if (!log_msg_cache.count(msg)) { log_msg_cache.insert(msg); log("%s\n", msg.c_str()); } - log_debug("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), extmapper_name.c_str()); + log_debug("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), + log_id(cell->type), extmapper_name.c_str()); if (extmapper_name == "simplemap") { if (simplemap_mappers.count(cell->type) == 0) @@ -596,7 +583,8 @@ struct TechmapWorker if (extmapper_name == "maccmap") { if (cell->type != ID($macc)) - log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(cell->type)); + log_error("The maccmap mapper can only map $macc (not %s) cells!\n", + log_id(cell->type)); maccmap(module, cell); } @@ -614,13 +602,14 @@ struct TechmapWorker continue; if (tpl->wire(conn.first) != nullptr && tpl->wire(conn.first)->port_id > 0) continue; - if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || tpl->avail_parameters.count(conn.first) == 0) + if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || + tpl->avail_parameters.count(conn.first) == 0) goto next_tpl; parameters[conn.first] = conn.second.as_const(); } if (0) { - next_tpl: + next_tpl: continue; } @@ -634,14 +623,16 @@ struct TechmapWorker std::vector v = sigmap(conn.second).to_sigbit_vector(); for (auto &bit : v) bit = RTLIL::SigBit(bit.wire == nullptr ? RTLIL::State::S1 : RTLIL::State::S0); - parameters.emplace(stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first)), RTLIL::SigSpec(v).as_const()); + parameters.emplace(stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first)), + RTLIL::SigSpec(v).as_const()); } if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first))) != 0) { std::vector v = sigmap(conn.second).to_sigbit_vector(); for (auto &bit : v) if (bit.wire != nullptr) bit = RTLIL::SigBit(RTLIL::State::Sx); - parameters.emplace(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first)), RTLIL::SigSpec(v).as_const()); + parameters.emplace(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first)), + RTLIL::SigSpec(v).as_const()); } if (tpl->avail_parameters.count(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first))) != 0) { parameters.emplace(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first)), initvals(conn.second)); @@ -666,7 +657,7 @@ struct TechmapWorker // Find highest bit set int bits = 0; for (int i = 0; i < 32; i++) - if (((unique_bit_id_counter-1) & (1 << i)) != 0) + if (((unique_bit_id_counter - 1) & (1 << i)) != 0) bits = i; // Increment index by one to get number of bits bits++; @@ -688,7 +679,7 @@ struct TechmapWorker } if (0) { - use_wrapper_tpl:; + use_wrapper_tpl:; // do not register techmap_wrap modules with techmap_cache } else { std::pair> key(tpl_name, parameters); @@ -710,15 +701,13 @@ struct TechmapWorker if (constmapped_tpl != nullptr) tpl = constmapped_tpl; - if (techmap_do_cache.count(tpl) == 0) - { + if (techmap_do_cache.count(tpl) == 0) { bool keep_running = true; techmap_do_cache[tpl] = true; pool techmap_wire_names; - while (keep_running) - { + while (keep_running) { TechmapWires twd = techmap_find_special_wires(tpl); keep_running = false; @@ -731,8 +720,9 @@ struct TechmapWorker for (const TechmapWireData &elem : it.second) { RTLIL::SigSpec value = elem.value; if (value.is_fully_const() && value.as_bool()) { - log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n", - derived_name.c_str(), log_id(elem.wire->name), log_signal(value)); + log("Not using module `%s' from techmap as it contains a %s marker wire with " + "non-zero value %s.\n", + derived_name.c_str(), log_id(elem.wire->name), log_signal(value)); techmap_do_cache[tpl] = false; } } @@ -741,27 +731,26 @@ struct TechmapWorker if (!techmap_do_cache[tpl]) break; - for (auto &it : twd) - { + for (auto &it : twd) { if (!it.first.contains("_TECHMAP_DO_") || it.second.empty()) continue; auto &data = it.second.front(); if (!data.value.is_fully_const()) - log_error("Techmap yielded config wire %s with non-const value %s.\n", log_id(data.wire->name), log_signal(data.value)); + log_error("Techmap yielded config wire %s with non-const value %s.\n", + log_id(data.wire->name), log_signal(data.value)); techmap_wire_names.erase(it.first); const char *p = data.wire->name.c_str(); - const char *q = strrchr(p+1, '.'); - q = q ? q+1 : p+1; + const char *q = strrchr(p + 1, '.'); + q = q ? q + 1 : p + 1; std::string cmd_string = data.value.as_const().decode_string(); restart_eval_cmd_string: - if (cmd_string.rfind("CONSTMAP; ", 0) == 0) - { + if (cmd_string.rfind("CONSTMAP; ", 0) == 0) { cmd_string = cmd_string.substr(strlen("CONSTMAP; ")); log("Analyzing pattern of constant bits for this cell:\n"); @@ -780,8 +769,7 @@ struct TechmapWorker dict port_connmap; dict cellbits_to_tplbits; - for (auto wire : tpl->wires().to_vector()) - { + for (auto wire : tpl->wires().to_vector()) { if (!wire->port_input || wire->port_output) continue; @@ -793,14 +781,15 @@ struct TechmapWorker wire->port_id = 0; for (int i = 0; i < wire->width; i++) { - port_new2old_map.emplace(RTLIL::SigBit(new_wire, i), RTLIL::SigBit(wire, i)); - port_connmap.emplace(RTLIL::SigBit(wire, i), RTLIL::SigBit(new_wire, i)); + port_new2old_map.emplace(RTLIL::SigBit(new_wire, i), + RTLIL::SigBit(wire, i)); + port_connmap.emplace(RTLIL::SigBit(wire, i), + RTLIL::SigBit(new_wire, i)); } } // Handle outputs first, as these cannot be remapped. - for (auto &conn : cell->connections()) - { + for (auto &conn : cell->connections()) { Wire *twire = tpl->wire(conn.first); if (!twire->port_output) continue; @@ -813,28 +802,22 @@ struct TechmapWorker } // Now handle inputs, remapping as necessary. - for (auto &conn : cell->connections()) - { + for (auto &conn : cell->connections()) { Wire *twire = tpl->wire(conn.first); if (twire->port_output) continue; - for (int i = 0; i < GetSize(conn.second); i++) - { + for (int i = 0; i < GetSize(conn.second); i++) { RTLIL::SigBit bit = sigmap(conn.second[i]); RTLIL::SigBit tplbit(twire, i); - if (bit.wire == nullptr) - { + if (bit.wire == nullptr) { RTLIL::SigBit oldbit = port_new2old_map.at(tplbit); port_connmap.at(oldbit) = bit; - } - else if (cellbits_to_tplbits.count(bit)) - { + } else if (cellbits_to_tplbits.count(bit)) { RTLIL::SigBit oldbit = port_new2old_map.at(tplbit); port_connmap.at(oldbit) = cellbits_to_tplbits[bit]; - } - else + } else cellbits_to_tplbits[bit] = tplbit; } } @@ -850,17 +833,18 @@ struct TechmapWorker goto restart_eval_cmd_string; } - if (cmd_string.rfind("RECURSION; ", 0) == 0) - { + if (cmd_string.rfind("RECURSION; ", 0) == 0) { cmd_string = cmd_string.substr(strlen("RECURSION; ")); - while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { } + while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { + } goto restart_eval_cmd_string; } Pass::call_on_module(map, tpl, cmd_string); log_assert(!strncmp(q, "_TECHMAP_DO_", 12)); - std::string new_name = data.wire->name.substr(0, q-p) + "_TECHMAP_DONE_" + data.wire->name.substr(q-p+12); + std::string new_name = + data.wire->name.substr(0, q - p) + "_TECHMAP_DONE_" + data.wire->name.substr(q - p + 12); while (tpl->wire(new_name) != nullptr) new_name += "_"; tpl->rename(data.wire->name, new_name); @@ -872,12 +856,15 @@ struct TechmapWorker TechmapWires twd = techmap_find_special_wires(tpl); for (auto &it : twd) { - if (!it.first.ends_with("_TECHMAP_FAIL_") && (!it.first.begins_with("\\_TECHMAP_REMOVEINIT_") || !it.first.ends_with("_")) && !it.first.contains("_TECHMAP_DO_") && !it.first.contains("_TECHMAP_DONE_")) + if (!it.first.ends_with("_TECHMAP_FAIL_") && + (!it.first.begins_with("\\_TECHMAP_REMOVEINIT_") || !it.first.ends_with("_")) && + !it.first.contains("_TECHMAP_DO_") && !it.first.contains("_TECHMAP_DONE_")) log_error("Techmap yielded unknown config wire %s.\n", log_id(it.first)); if (techmap_do_cache[tpl]) for (auto &it2 : it.second) if (!it2.value.is_fully_const()) - log_error("Techmap yielded config wire %s with non-const value %s.\n", log_id(it2.wire->name), log_signal(it2.value)); + log_error("Techmap yielded config wire %s with non-const value %s.\n", + log_id(it2.wire->name), log_signal(it2.value)); techmap_wire_names.erase(it.first); } @@ -890,7 +877,8 @@ struct TechmapWorker log_continue = false; mkdebug.off(); } - while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { } + while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { + } } } @@ -920,12 +908,10 @@ struct TechmapWorker } } - if (extern_mode && !in_recursion) - { + if (extern_mode && !in_recursion) { std::string m_name = stringf("$extern:%s", log_id(tpl)); - if (!design->module(m_name)) - { + if (!design->module(m_name)) { RTLIL::Module *m = design->addModule(m_name); tpl->cloneInto(m); @@ -940,15 +926,14 @@ struct TechmapWorker log_debug("%s %s.%s to imported %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(m_name)); cell->type = m_name; cell->parameters.clear(); - } - else - { + } else { auto msg = stringf("Using template %s for cells of type %s.", log_id(tpl), log_id(cell->type)); if (!log_msg_cache.count(msg)) { log_msg_cache.insert(msg); log("%s\n", msg.c_str()); } - log_debug("%s %s.%s (%s) using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(tpl)); + log_debug("%s %s.%s (%s) using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), + log_id(cell->type), log_id(tpl)); techmap_module_worker(design, module, cell, tpl); cell = nullptr; } @@ -974,7 +959,7 @@ struct TechmapWorker }; struct TechmapPass : public Pass { - TechmapPass() : Pass("techmap", "generic technology mapper") { } + TechmapPass() : Pass("techmap", "generic technology mapper") {} void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -1155,19 +1140,19 @@ struct TechmapPass : public Pass { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - if (args[argidx] == "-map" && argidx+1 < args.size()) { + if (args[argidx] == "-map" && argidx + 1 < args.size()) { map_files.push_back(args[++argidx]); continue; } - if (args[argidx] == "-max_iter" && argidx+1 < args.size()) { + if (args[argidx] == "-max_iter" && argidx + 1 < args.size()) { max_iter = atoi(args[++argidx].c_str()); continue; } - if (args[argidx] == "-D" && argidx+1 < args.size()) { + if (args[argidx] == "-D" && argidx + 1 < args.size()) { verilog_frontend += " -D " + args[++argidx]; continue; } - if (args[argidx] == "-I" && argidx+1 < args.size()) { + if (args[argidx] == "-I" && argidx + 1 < args.size()) { verilog_frontend += " -I " + args[++argidx]; continue; } @@ -1203,13 +1188,15 @@ struct TechmapPass : public Pass { if (fn.compare(0, 1, "%") == 0) { if (!saved_designs.count(fn.substr(1))) { delete map; - log_cmd_error("Can't open saved design `%s'.\n", fn.c_str()+1); + log_cmd_error("Can't open saved design `%s'.\n", fn.c_str() + 1); } for (auto mod : saved_designs.at(fn.substr(1))->modules()) if (!map->module(mod->name)) map->add(mod->clone()); } else { - Frontend::frontend_call(map, nullptr, fn, (fn.size() > 3 && fn.compare(fn.size()-3, std::string::npos, ".il") == 0 ? "rtlil" : verilog_frontend)); + Frontend::frontend_call( + map, nullptr, fn, + (fn.size() > 3 && fn.compare(fn.size() - 3, std::string::npos, ".il") == 0 ? "rtlil" : verilog_frontend)); } } @@ -1235,15 +1222,15 @@ struct TechmapPass : public Pass { if (epos == std::string::npos) log_error("Malformed techmap_celltype pattern %s\n", q); for (size_t i = pos + 1; i < epos; i++) { - queue.push_back(name.substr(0, pos) + name[i] + name.substr(epos + 1, std::string::npos)); + queue.push_back(name.substr(0, pos) + name[i] + + name.substr(epos + 1, std::string::npos)); } } } } free(p); } else { - IdString module_name = module->name.begins_with("\\$") ? - module->name.substr(1) : module->name.str(); + IdString module_name = module->name.begins_with("\\$") ? module->name.substr(1) : module->name.str(); celltypeMap[module_name].insert(module->name); } } @@ -1260,14 +1247,13 @@ struct TechmapPass : public Pass { for (auto module : design->modules()) worker.module_queue.insert(module); - while (!worker.module_queue.empty()) - { + while (!worker.module_queue.empty()) { RTLIL::Module *module = *worker.module_queue.begin(); worker.module_queue.erase(module); int module_max_iter = max_iter; bool did_something = true; - pool handled_cells; + pool handled_cells; while (did_something) { did_something = false; if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false)) From 67f17004869c3aeea75c1e5620f73bfb1b34e7cd Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Fri, 29 Sep 2023 13:20:43 -0700 Subject: [PATCH 40/95] Revert formatting changes. --- passes/techmap/simplemap.cc | 200 ++++++++++++-------------- passes/techmap/techmap.cc | 274 +++++++++++++++++++----------------- 2 files changed, 235 insertions(+), 239 deletions(-) diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc index 14c07922b..7461460fe 100644 --- a/passes/techmap/simplemap.cc +++ b/passes/techmap/simplemap.cc @@ -18,10 +18,10 @@ */ #include "simplemap.h" -#include "kernel/ff.h" #include "kernel/sigtools.h" -#include +#include "kernel/ff.h" #include +#include #include USING_YOSYS_NAMESPACE @@ -64,16 +64,11 @@ void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell) } IdString gate_type; - if (cell->type == ID($and)) - gate_type = ID($_AND_); - if (cell->type == ID($or)) - gate_type = ID($_OR_); - if (cell->type == ID($xor)) - gate_type = ID($_XOR_); - if (cell->type == ID($xnor)) - gate_type = ID($_XNOR_); - if (cell->type == ID($bweqx)) - gate_type = ID($_XNOR_); + if (cell->type == ID($and)) gate_type = ID($_AND_); + if (cell->type == ID($or)) gate_type = ID($_OR_); + if (cell->type == ID($xor)) gate_type = ID($_XOR_); + if (cell->type == ID($xnor)) gate_type = ID($_XNOR_); + if (cell->type == ID($bweqx)) gate_type = ID($_XNOR_); log_assert(!gate_type.empty()); for (int i = 0; i < GetSize(sig_y); i++) { @@ -94,44 +89,36 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) return; if (sig_a.size() == 0) { - if (cell->type == ID($reduce_and)) - module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); - if (cell->type == ID($reduce_or)) - module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); - if (cell->type == ID($reduce_xor)) - module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); - if (cell->type == ID($reduce_xnor)) - module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); - if (cell->type == ID($reduce_bool)) - module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); + if (cell->type == ID($reduce_and)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); + if (cell->type == ID($reduce_or)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); + if (cell->type == ID($reduce_xor)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); + if (cell->type == ID($reduce_xnor)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); + if (cell->type == ID($reduce_bool)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); return; } if (sig_y.size() > 1) { - module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size() - 1), RTLIL::SigSpec(0, sig_y.size() - 1))); + module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1))); sig_y = sig_y.extract(0, 1); } IdString gate_type; - if (cell->type == ID($reduce_and)) - gate_type = ID($_AND_); - if (cell->type == ID($reduce_or)) - gate_type = ID($_OR_); - if (cell->type == ID($reduce_xor)) - gate_type = ID($_XOR_); - if (cell->type == ID($reduce_xnor)) - gate_type = ID($_XOR_); - if (cell->type == ID($reduce_bool)) - gate_type = ID($_OR_); + if (cell->type == ID($reduce_and)) gate_type = ID($_AND_); + if (cell->type == ID($reduce_or)) gate_type = ID($_OR_); + if (cell->type == ID($reduce_xor)) gate_type = ID($_XOR_); + if (cell->type == ID($reduce_xnor)) gate_type = ID($_XOR_); + if (cell->type == ID($reduce_bool)) gate_type = ID($_OR_); log_assert(!gate_type.empty()); RTLIL::Cell *last_output_cell = NULL; - while (sig_a.size() > 1) { + while (sig_a.size() > 1) + { RTLIL::SigSpec sig_t = module->addWire(NEW_ID, sig_a.size() / 2); - for (int i = 0; i < sig_a.size(); i += 2) { - if (i + 1 == sig_a.size()) { + for (int i = 0; i < sig_a.size(); i += 2) + { + if (i+1 == sig_a.size()) { sig_t.append(sig_a[i]); continue; } @@ -139,8 +126,8 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig_a[i]); - gate->setPort(ID::B, sig_a[i + 1]); - gate->setPort(ID::Y, sig_t[i / 2]); + gate->setPort(ID::B, sig_a[i+1]); + gate->setPort(ID::Y, sig_t[i/2]); last_output_cell = gate; } @@ -166,11 +153,13 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig, RTLIL::Cell *cell) { - while (sig.size() > 1) { + while (sig.size() > 1) + { RTLIL::SigSpec sig_t = module->addWire(NEW_ID, sig.size() / 2); - for (int i = 0; i < sig.size(); i += 2) { - if (i + 1 == sig.size()) { + for (int i = 0; i < sig.size(); i += 2) + { + if (i+1 == sig.size()) { sig_t.append(sig[i]); continue; } @@ -178,8 +167,8 @@ static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig, RTLIL::Cell RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_OR_)); gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, sig[i]); - gate->setPort(ID::B, sig[i + 1]); - gate->setPort(ID::Y, sig_t[i / 2]); + gate->setPort(ID::B, sig[i+1]); + gate->setPort(ID::Y, sig_t[i/2]); } sig = sig_t; @@ -200,7 +189,7 @@ void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell) return; if (sig_y.size() > 1) { - module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size() - 1), RTLIL::SigSpec(0, sig_y.size() - 1))); + module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1))); sig_y = sig_y.extract(0, 1); } @@ -224,15 +213,13 @@ void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell) return; if (sig_y.size() > 1) { - module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size() - 1), RTLIL::SigSpec(0, sig_y.size() - 1))); + module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1))); sig_y = sig_y.extract(0, 1); } IdString gate_type; - if (cell->type == ID($logic_and)) - gate_type = ID($_AND_); - if (cell->type == ID($logic_or)) - gate_type = ID($_OR_); + if (cell->type == ID($logic_and)) gate_type = ID($_AND_); + if (cell->type == ID($logic_or)) gate_type = ID($_OR_); log_assert(!gate_type.empty()); RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); @@ -253,22 +240,19 @@ void simplemap_eqne(RTLIL::Module *module, RTLIL::Cell *cell) RTLIL::SigSpec xor_out = module->addWire(NEW_ID, max(GetSize(sig_a), GetSize(sig_b))); RTLIL::Cell *xor_cell = module->addXor(NEW_ID, sig_a, sig_b, xor_out, is_signed); xor_cell->attributes[ID::src] = cell->attributes[ID::src]; - // xor_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); simplemap_bitop(module, xor_cell); module->remove(xor_cell); RTLIL::SigSpec reduce_out = is_ne ? sig_y : module->addWire(NEW_ID); RTLIL::Cell *reduce_cell = module->addReduceOr(NEW_ID, xor_out, reduce_out); reduce_cell->attributes[ID::src] = cell->attributes[ID::src]; - // reduce_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); simplemap_reduce(module, reduce_cell); module->remove(reduce_cell); if (!is_ne) { RTLIL::Cell *not_cell = module->addLogicNot(NEW_ID, reduce_out, sig_y); not_cell->attributes[ID::src] = cell->attributes[ID::src]; - // not_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); - simplemap_lognot(module, not_cell); + simplemap_lognot(module, not_cell); module->remove(not_cell); } } @@ -328,15 +312,15 @@ void simplemap_bmux(RTLIL::Module *module, RTLIL::Cell *cell) int width = GetSize(cell->getPort(ID::Y)); for (int idx = 0; idx < GetSize(sel); idx++) { - SigSpec new_data = module->addWire(NEW_ID, GetSize(data) / 2); + SigSpec new_data = module->addWire(NEW_ID, GetSize(data)/2); for (int i = 0; i < GetSize(new_data); i += width) { for (int k = 0; k < width; k++) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_)); gate->attributes[ID::src] = cell->attributes[ID::src]; - gate->setPort(ID::A, data[i * 2 + k]); - gate->setPort(ID::B, data[i * 2 + width + k]); + gate->setPort(ID::A, data[i*2+k]); + gate->setPort(ID::B, data[i*2+width+k]); gate->setPort(ID::S, sel[idx]); - gate->setPort(ID::Y, new_data[i + k]); + gate->setPort(ID::Y, new_data[i+k]); } } data = new_data; @@ -352,14 +336,14 @@ void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell) lut_data.extend_u0(1 << cell->getParam(ID::WIDTH).as_int()); for (int idx = 0; GetSize(lut_data) > 1; idx++) { - SigSpec new_lut_data = module->addWire(NEW_ID, GetSize(lut_data) / 2); + SigSpec new_lut_data = module->addWire(NEW_ID, GetSize(lut_data)/2); for (int i = 0; i < GetSize(lut_data); i += 2) { RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_)); gate->attributes[ID::src] = cell->attributes[ID::src]; gate->setPort(ID::A, lut_data[i]); - gate->setPort(ID::B, lut_data[i + 1]); + gate->setPort(ID::B, lut_data[i+1]); gate->setPort(ID::S, lut_ctrl[idx]); - gate->setPort(ID::Y, new_lut_data[i / 2]); + gate->setPort(ID::Y, new_lut_data[i/2]); } lut_data = new_lut_data; } @@ -381,11 +365,11 @@ void simplemap_sop(RTLIL::Module *module, RTLIL::Cell *cell) for (int i = 0; i < depth; i++) { SigSpec in, pat; for (int j = 0; j < width; j++) { - if (table[2 * i * width + 2 * j + 0] == State::S1) { + if (table[2*i*width + 2*j + 0] == State::S1) { in.append(ctrl[j]); pat.append(State::S0); } - if (table[2 * i * width + 2 * j + 1] == State::S1) { + if (table[2*i*width + 2*j + 1] == State::S1) { in.append(ctrl[j]); pat.append(State::S1); } @@ -423,56 +407,56 @@ void simplemap_ff(RTLIL::Module *, RTLIL::Cell *cell) } } -void simplemap_get_mappers(dict &mappers) +void simplemap_get_mappers(dict &mappers) { - mappers[ID($not)] = simplemap_not; - mappers[ID($pos)] = simplemap_pos; - mappers[ID($and)] = simplemap_bitop; - mappers[ID($or)] = simplemap_bitop; - mappers[ID($xor)] = simplemap_bitop; - mappers[ID($xnor)] = simplemap_bitop; - mappers[ID($bweqx)] = simplemap_bitop; - mappers[ID($reduce_and)] = simplemap_reduce; - mappers[ID($reduce_or)] = simplemap_reduce; - mappers[ID($reduce_xor)] = simplemap_reduce; + mappers[ID($not)] = simplemap_not; + mappers[ID($pos)] = simplemap_pos; + mappers[ID($and)] = simplemap_bitop; + mappers[ID($or)] = simplemap_bitop; + mappers[ID($xor)] = simplemap_bitop; + mappers[ID($xnor)] = simplemap_bitop; + mappers[ID($bweqx)] = simplemap_bitop; + mappers[ID($reduce_and)] = simplemap_reduce; + mappers[ID($reduce_or)] = simplemap_reduce; + mappers[ID($reduce_xor)] = simplemap_reduce; mappers[ID($reduce_xnor)] = simplemap_reduce; mappers[ID($reduce_bool)] = simplemap_reduce; - mappers[ID($logic_not)] = simplemap_lognot; - mappers[ID($logic_and)] = simplemap_logbin; - mappers[ID($logic_or)] = simplemap_logbin; - mappers[ID($eq)] = simplemap_eqne; - mappers[ID($eqx)] = simplemap_eqne; - mappers[ID($ne)] = simplemap_eqne; - mappers[ID($nex)] = simplemap_eqne; - mappers[ID($mux)] = simplemap_mux; - mappers[ID($bwmux)] = simplemap_bwmux; - mappers[ID($tribuf)] = simplemap_tribuf; - mappers[ID($bmux)] = simplemap_bmux; - mappers[ID($lut)] = simplemap_lut; - mappers[ID($sop)] = simplemap_sop; - mappers[ID($slice)] = simplemap_slice; - mappers[ID($concat)] = simplemap_concat; - mappers[ID($sr)] = simplemap_ff; - mappers[ID($ff)] = simplemap_ff; - mappers[ID($dff)] = simplemap_ff; - mappers[ID($dffe)] = simplemap_ff; - mappers[ID($dffsr)] = simplemap_ff; - mappers[ID($dffsre)] = simplemap_ff; - mappers[ID($adff)] = simplemap_ff; - mappers[ID($sdff)] = simplemap_ff; - mappers[ID($adffe)] = simplemap_ff; - mappers[ID($sdffe)] = simplemap_ff; - mappers[ID($sdffce)] = simplemap_ff; - mappers[ID($aldff)] = simplemap_ff; - mappers[ID($aldffe)] = simplemap_ff; - mappers[ID($dlatch)] = simplemap_ff; - mappers[ID($adlatch)] = simplemap_ff; - mappers[ID($dlatchsr)] = simplemap_ff; + mappers[ID($logic_not)] = simplemap_lognot; + mappers[ID($logic_and)] = simplemap_logbin; + mappers[ID($logic_or)] = simplemap_logbin; + mappers[ID($eq)] = simplemap_eqne; + mappers[ID($eqx)] = simplemap_eqne; + mappers[ID($ne)] = simplemap_eqne; + mappers[ID($nex)] = simplemap_eqne; + mappers[ID($mux)] = simplemap_mux; + mappers[ID($bwmux)] = simplemap_bwmux; + mappers[ID($tribuf)] = simplemap_tribuf; + mappers[ID($bmux)] = simplemap_bmux; + mappers[ID($lut)] = simplemap_lut; + mappers[ID($sop)] = simplemap_sop; + mappers[ID($slice)] = simplemap_slice; + mappers[ID($concat)] = simplemap_concat; + mappers[ID($sr)] = simplemap_ff; + mappers[ID($ff)] = simplemap_ff; + mappers[ID($dff)] = simplemap_ff; + mappers[ID($dffe)] = simplemap_ff; + mappers[ID($dffsr)] = simplemap_ff; + mappers[ID($dffsre)] = simplemap_ff; + mappers[ID($adff)] = simplemap_ff; + mappers[ID($sdff)] = simplemap_ff; + mappers[ID($adffe)] = simplemap_ff; + mappers[ID($sdffe)] = simplemap_ff; + mappers[ID($sdffce)] = simplemap_ff; + mappers[ID($aldff)] = simplemap_ff; + mappers[ID($aldffe)] = simplemap_ff; + mappers[ID($dlatch)] = simplemap_ff; + mappers[ID($adlatch)] = simplemap_ff; + mappers[ID($dlatchsr)] = simplemap_ff; } void simplemap(RTLIL::Module *module, RTLIL::Cell *cell) { - static dict mappers; + static dict mappers; static bool initialized_mappers = false; if (!initialized_mappers) { @@ -487,7 +471,7 @@ YOSYS_NAMESPACE_END PRIVATE_NAMESPACE_BEGIN struct SimplemapPass : public Pass { - SimplemapPass() : Pass("simplemap", "mapping simple coarse-grain cells") {} + SimplemapPass() : Pass("simplemap", "mapping simple coarse-grain cells") { } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -509,13 +493,13 @@ struct SimplemapPass : public Pass { log_header(design, "Executing SIMPLEMAP pass (map simple cells to gate primitives).\n"); extra_args(args, 1, design); - dict mappers; + dict mappers; simplemap_get_mappers(mappers); for (auto mod : design->modules()) { if (!design->selected(mod) || mod->get_blackbox_attribute()) continue; - std::vector cells = mod->cells(); + std::vector cells = mod->cells(); for (auto cell : cells) { if (mappers.count(cell->type) == 0) continue; diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 52a24dcf3..23d0d93fc 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -17,14 +17,14 @@ * */ -#include "kernel/ffinit.h" -#include "kernel/sigtools.h" -#include "kernel/utils.h" #include "kernel/yosys.h" +#include "kernel/utils.h" +#include "kernel/sigtools.h" +#include "kernel/ffinit.h" #include "libs/sha1/sha1.h" -#include #include +#include #include #include "simplemap.h" @@ -42,7 +42,7 @@ PRIVATE_NAMESPACE_BEGIN void apply_prefix(IdString prefix, IdString &id) { if (id[0] == '\\') - id = stringf("%s.%s", prefix.c_str(), id.c_str() + 1); + id = stringf("%s.%s", prefix.c_str(), id.c_str()+1); else id = stringf("$techmap%s.%s", prefix.c_str(), id.c_str()); } @@ -60,12 +60,13 @@ void apply_prefix(IdString prefix, RTLIL::SigSpec &sig, RTLIL::Module *module) sig = chunks; } -struct TechmapWorker { - dict simplemap_mappers; - dict>, RTLIL::Module *> techmap_cache; - dict techmap_do_cache; - pool module_queue; - dict sigmaps; +struct TechmapWorker +{ + dict simplemap_mappers; + dict>, RTLIL::Module*> techmap_cache; + dict techmap_do_cache; + pool module_queue; + dict sigmaps; pool log_msg_cache; @@ -97,9 +98,9 @@ struct TechmapWorker { } else if (connbits_map.count(bit)) { if (verbose) log(" Bit %d of port %s and bit %d of port %s are connected.\n", i, log_id(conn.first), - connbits_map.at(bit).second, log_id(connbits_map.at(bit).first)); - constmap_info += stringf("|%s %d %s %d", log_id(conn.first), i, log_id(connbits_map.at(bit).first), - connbits_map.at(bit).second); + connbits_map.at(bit).second, log_id(connbits_map.at(bit).first)); + constmap_info += stringf("|%s %d %s %d", log_id(conn.first), i, + log_id(connbits_map.at(bit).first), connbits_map.at(bit).second); } else { connbits_map.emplace(bit, std::make_pair(conn.first, i)); constmap_info += stringf("|%s %d", log_id(conn.first), i); @@ -133,8 +134,8 @@ struct TechmapWorker { if (!result.empty()) { SigMap sigmap(module); for (auto &it1 : result) - for (auto &it2 : it1.second) - sigmap.apply(it2.value); + for (auto &it2 : it1.second) + sigmap.apply(it2.value); } return result; @@ -145,7 +146,7 @@ struct TechmapWorker { if (tpl->processes.size() != 0) { log("Technology map yielded processes:"); for (auto &it : tpl->processes) - log(" %s", log_id(it.first)); + log(" %s",log_id(it.first)); log("\n"); if (autoproc_mode) { Pass::call_on_module(tpl->design, tpl, "proc"); @@ -155,7 +156,6 @@ struct TechmapWorker { } std::string orig_cell_name; - orig_cell_name = cell->name.str(); for (auto tpl_cell : tpl->cells()) if (tpl_cell->name.ends_with("_TECHMAP_REPLACE_")) { @@ -164,28 +164,32 @@ struct TechmapWorker { } dict memory_renames; + for (auto &it : tpl->memories) { IdString m_name = it.first; apply_prefix(cell->name, m_name); RTLIL::Memory *m = module->addMemory(m_name, it.second); if (m->attributes.count(ID::src)) - m->attributes[ID::src] = cell->attributes[ID::src]; + m->attributes[ID::src] = cell->attributes[ID::src]; memory_renames[it.first] = m->name; design->select(module, m); } dict positional_ports; - dict temp_renamed_wires; + dict temp_renamed_wires; pool autopurge_tpl_bits; - for (auto tpl_w : tpl->wires()) { - if (tpl_w->port_id > 0) { + for (auto tpl_w : tpl->wires()) + { + if (tpl_w->port_id > 0) + { IdString posportname = stringf("$%d", tpl_w->port_id); positional_ports.emplace(posportname, tpl_w->name); if (tpl_w->get_bool_attribute(ID::techmap_autopurge) && - (!cell->hasPort(tpl_w->name) || !GetSize(cell->getPort(tpl_w->name))) && - (!cell->hasPort(posportname) || !GetSize(cell->getPort(posportname)))) { + (!cell->hasPort(tpl_w->name) || !GetSize(cell->getPort(tpl_w->name))) && + (!cell->hasPort(posportname) || !GetSize(cell->getPort(posportname)))) + { if (sigmaps.count(tpl) == 0) sigmaps[tpl].set(tpl); @@ -211,7 +215,7 @@ struct TechmapWorker { if (tpl_w->get_bool_attribute(ID::_techmap_special_)) w->attributes.clear(); if (w->attributes.count(ID::src)) - w->attributes[ID::src] = cell->attributes[ID::src]; + w->attributes[ID::src] = cell->attributes[ID::src]; } design->select(module, w); @@ -224,24 +228,24 @@ struct TechmapWorker { pool tpl_written_bits; for (auto tpl_cell : tpl->cells()) - for (auto &conn : tpl_cell->connections()) - if (tpl_cell->output(conn.first)) - for (auto bit : conn.second) - tpl_written_bits.insert(bit); + for (auto &conn : tpl_cell->connections()) + if (tpl_cell->output(conn.first)) + for (auto bit : conn.second) + tpl_written_bits.insert(bit); for (auto &conn : tpl->connections()) for (auto bit : conn.first) tpl_written_bits.insert(bit); SigMap port_signal_map; - for (auto &it : cell->connections()) { + for (auto &it : cell->connections()) + { IdString portname = it.first; if (positional_ports.count(portname) > 0) portname = positional_ports.at(portname); if (tpl->wire(portname) == nullptr || tpl->wire(portname)->port_id == 0) { if (portname.begins_with("$")) - log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), - tpl->name.c_str()); + log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str()); continue; } @@ -291,7 +295,8 @@ struct TechmapWorker { if (w->port_output && !w->port_input) { port_signal_map.add(c.second, c.first); - } else if (!w->port_output && w->port_input) { + } else + if (!w->port_output && w->port_input) { port_signal_map.add(c.first, c.second); } else { module->connect(c); @@ -304,15 +309,16 @@ struct TechmapWorker { auto lhs = GetSize(extra_connect.first); auto rhs = GetSize(extra_connect.second); if (lhs > rhs) - extra_connect.first.remove(rhs, lhs - rhs); + extra_connect.first.remove(rhs, lhs-rhs); else if (rhs > lhs) - extra_connect.second.remove(lhs, rhs - lhs); + extra_connect.second.remove(lhs, rhs-lhs); module->connect(extra_connect); break; } } - for (auto tpl_cell : tpl->cells()) { + for (auto tpl_cell : tpl->cells()) + { IdString c_name = tpl_cell->name; bool techmap_replace_cell = c_name.ends_with("_TECHMAP_REPLACE_"); @@ -331,7 +337,8 @@ struct TechmapWorker { vector autopurge_ports; - for (auto &conn : c->connections()) { + for (auto &conn : c->connections()) + { bool autopurge = false; if (!autopurge_tpl_bits.empty()) { autopurge = GetSize(conn.second) != 0; @@ -366,7 +373,7 @@ struct TechmapWorker { } if (c->attributes.count(ID::src)) - c->attributes[ID::src] = cell->attributes[ID::src]; + c->attributes[ID::src] = cell->attributes[ID::src]; if (techmap_replace_cell) { for (auto attr : cell->attributes) @@ -387,7 +394,8 @@ struct TechmapWorker { module->remove(cell); - for (auto &it : temp_renamed_wires) { + for (auto &it : temp_renamed_wires) + { Wire *w = it.first; IdString name = it.second; IdString altname = module->uniquify(name); @@ -397,8 +405,8 @@ struct TechmapWorker { } } - bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, pool &handled_cells, - const dict> &celltypeMap, bool in_recursion) + bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, pool &handled_cells, + const dict> &celltypeMap, bool in_recursion) { std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping"; @@ -412,11 +420,12 @@ struct TechmapWorker { SigMap sigmap(module); FfInitVals initvals(&sigmap, module); - TopoSort> cells; - dict> cell_to_inbit; - dict> outbit_to_cell; + TopoSort> cells; + dict> cell_to_inbit; + dict> outbit_to_cell; - for (auto cell : module->selected_cells()) { + for (auto cell : module->selected_cells()) + { if (handled_cells.count(cell) > 0) continue; @@ -430,7 +439,8 @@ struct TechmapWorker { continue; } - for (auto &conn : cell->connections()) { + for (auto &conn : cell->connections()) + { RTLIL::SigSpec sig = sigmap(conn.second); sig.remove_const(); @@ -452,13 +462,14 @@ struct TechmapWorker { } for (auto &it_right : cell_to_inbit) - for (auto &it_sigbit : it_right.second) - for (auto &it_left : outbit_to_cell[it_sigbit]) - cells.edge(it_left, it_right.first); + for (auto &it_sigbit : it_right.second) + for (auto &it_left : outbit_to_cell[it_sigbit]) + cells.edge(it_left, it_right.first); cells.sort(); - for (auto cell : cells.sorted) { + for (auto cell : cells.sorted) + { log_assert(handled_cells.count(cell) == 0); log_assert(cell == module->cell(cell->name)); bool mapped_cell = false; @@ -468,7 +479,8 @@ struct TechmapWorker { if (in_recursion && cell->type.begins_with("\\$")) cell_type = cell_type.substr(1); - for (auto &tpl_name : celltypeMap.at(cell_type)) { + for (auto &tpl_name : celltypeMap.at(cell_type)) + { IdString derived_name = tpl_name; RTLIL::Module *tpl = map->module(tpl_name); dict parameters(cell->parameters); @@ -487,10 +499,12 @@ struct TechmapWorker { if (tpl->attributes.count(ID::techmap_wrap)) extmapper_name = "wrap"; - if (!extmapper_name.empty()) { + if (!extmapper_name.empty()) + { cell->type = cell_type; - if ((extern_mode && !in_recursion) || extmapper_name == "wrap") { + if ((extern_mode && !in_recursion) || extmapper_name == "wrap") + { std::string m_name = stringf("$extern:%s:%s", extmapper_name.c_str(), log_id(cell->type)); for (auto &c : cell->parameters) @@ -502,7 +516,8 @@ struct TechmapWorker { RTLIL::Design *extmapper_design = extern_mode && !in_recursion ? design : tpl->design; RTLIL::Module *extmapper_module = extmapper_design->module(m_name); - if (extmapper_module == nullptr) { + if (extmapper_module == nullptr) + { extmapper_module = extmapper_design->addModule(m_name); RTLIL::Cell *extmapper_cell = extmapper_module->addCell(cell->type, cell); @@ -525,8 +540,7 @@ struct TechmapWorker { if (extmapper_name == "simplemap") { log("Creating %s with simplemap.\n", log_id(extmapper_module)); if (simplemap_mappers.count(extmapper_cell->type) == 0) - log_error("No simplemap mapper for cell type %s found!\n", - log_id(extmapper_cell->type)); + log_error("No simplemap mapper for cell type %s found!\n", log_id(extmapper_cell->type)); simplemap_mappers.at(extmapper_cell->type)(extmapper_module, extmapper_cell); extmapper_module->remove(extmapper_cell); } @@ -534,8 +548,7 @@ struct TechmapWorker { if (extmapper_name == "maccmap") { log("Creating %s with maccmap.\n", log_id(extmapper_module)); if (extmapper_cell->type != ID($macc)) - log_error("The maccmap mapper can only map $macc (not %s) cells!\n", - log_id(extmapper_cell->type)); + log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(extmapper_cell->type)); maccmap(extmapper_module, extmapper_cell); extmapper_module->remove(extmapper_cell); } @@ -557,23 +570,21 @@ struct TechmapWorker { goto use_wrapper_tpl; } - auto msg = - stringf("Using extmapper %s for cells of type %s.", log_id(extmapper_module), log_id(cell->type)); + auto msg = stringf("Using extmapper %s for cells of type %s.", log_id(extmapper_module), log_id(cell->type)); if (!log_msg_cache.count(msg)) { log_msg_cache.insert(msg); log("%s\n", msg.c_str()); } - log_debug("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), - log_id(cell->type), log_id(extmapper_module)); - } else { - auto msg = - stringf("Using extmapper %s for cells of type %s.", extmapper_name.c_str(), log_id(cell->type)); + log_debug("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(extmapper_module)); + } + else + { + auto msg = stringf("Using extmapper %s for cells of type %s.", extmapper_name.c_str(), log_id(cell->type)); if (!log_msg_cache.count(msg)) { log_msg_cache.insert(msg); log("%s\n", msg.c_str()); } - log_debug("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), - log_id(cell->type), extmapper_name.c_str()); + log_debug("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), extmapper_name.c_str()); if (extmapper_name == "simplemap") { if (simplemap_mappers.count(cell->type) == 0) @@ -583,8 +594,7 @@ struct TechmapWorker { if (extmapper_name == "maccmap") { if (cell->type != ID($macc)) - log_error("The maccmap mapper can only map $macc (not %s) cells!\n", - log_id(cell->type)); + log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(cell->type)); maccmap(module, cell); } @@ -602,14 +612,13 @@ struct TechmapWorker { continue; if (tpl->wire(conn.first) != nullptr && tpl->wire(conn.first)->port_id > 0) continue; - if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || - tpl->avail_parameters.count(conn.first) == 0) + if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || tpl->avail_parameters.count(conn.first) == 0) goto next_tpl; parameters[conn.first] = conn.second.as_const(); } if (0) { - next_tpl: + next_tpl: continue; } @@ -623,16 +632,14 @@ struct TechmapWorker { std::vector v = sigmap(conn.second).to_sigbit_vector(); for (auto &bit : v) bit = RTLIL::SigBit(bit.wire == nullptr ? RTLIL::State::S1 : RTLIL::State::S0); - parameters.emplace(stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first)), - RTLIL::SigSpec(v).as_const()); + parameters.emplace(stringf("\\_TECHMAP_CONSTMSK_%s_", log_id(conn.first)), RTLIL::SigSpec(v).as_const()); } if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first))) != 0) { std::vector v = sigmap(conn.second).to_sigbit_vector(); for (auto &bit : v) if (bit.wire != nullptr) bit = RTLIL::SigBit(RTLIL::State::Sx); - parameters.emplace(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first)), - RTLIL::SigSpec(v).as_const()); + parameters.emplace(stringf("\\_TECHMAP_CONSTVAL_%s_", log_id(conn.first)), RTLIL::SigSpec(v).as_const()); } if (tpl->avail_parameters.count(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first))) != 0) { parameters.emplace(stringf("\\_TECHMAP_WIREINIT_%s_", log_id(conn.first)), initvals(conn.second)); @@ -657,7 +664,7 @@ struct TechmapWorker { // Find highest bit set int bits = 0; for (int i = 0; i < 32; i++) - if (((unique_bit_id_counter - 1) & (1 << i)) != 0) + if (((unique_bit_id_counter-1) & (1 << i)) != 0) bits = i; // Increment index by one to get number of bits bits++; @@ -679,7 +686,7 @@ struct TechmapWorker { } if (0) { - use_wrapper_tpl:; + use_wrapper_tpl:; // do not register techmap_wrap modules with techmap_cache } else { std::pair> key(tpl_name, parameters); @@ -701,13 +708,15 @@ struct TechmapWorker { if (constmapped_tpl != nullptr) tpl = constmapped_tpl; - if (techmap_do_cache.count(tpl) == 0) { + if (techmap_do_cache.count(tpl) == 0) + { bool keep_running = true; techmap_do_cache[tpl] = true; pool techmap_wire_names; - while (keep_running) { + while (keep_running) + { TechmapWires twd = techmap_find_special_wires(tpl); keep_running = false; @@ -720,9 +729,8 @@ struct TechmapWorker { for (const TechmapWireData &elem : it.second) { RTLIL::SigSpec value = elem.value; if (value.is_fully_const() && value.as_bool()) { - log("Not using module `%s' from techmap as it contains a %s marker wire with " - "non-zero value %s.\n", - derived_name.c_str(), log_id(elem.wire->name), log_signal(value)); + log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n", + derived_name.c_str(), log_id(elem.wire->name), log_signal(value)); techmap_do_cache[tpl] = false; } } @@ -731,26 +739,27 @@ struct TechmapWorker { if (!techmap_do_cache[tpl]) break; - for (auto &it : twd) { + for (auto &it : twd) + { if (!it.first.contains("_TECHMAP_DO_") || it.second.empty()) continue; auto &data = it.second.front(); if (!data.value.is_fully_const()) - log_error("Techmap yielded config wire %s with non-const value %s.\n", - log_id(data.wire->name), log_signal(data.value)); + log_error("Techmap yielded config wire %s with non-const value %s.\n", log_id(data.wire->name), log_signal(data.value)); techmap_wire_names.erase(it.first); const char *p = data.wire->name.c_str(); - const char *q = strrchr(p + 1, '.'); - q = q ? q + 1 : p + 1; + const char *q = strrchr(p+1, '.'); + q = q ? q+1 : p+1; std::string cmd_string = data.value.as_const().decode_string(); restart_eval_cmd_string: - if (cmd_string.rfind("CONSTMAP; ", 0) == 0) { + if (cmd_string.rfind("CONSTMAP; ", 0) == 0) + { cmd_string = cmd_string.substr(strlen("CONSTMAP; ")); log("Analyzing pattern of constant bits for this cell:\n"); @@ -769,7 +778,8 @@ struct TechmapWorker { dict port_connmap; dict cellbits_to_tplbits; - for (auto wire : tpl->wires().to_vector()) { + for (auto wire : tpl->wires().to_vector()) + { if (!wire->port_input || wire->port_output) continue; @@ -781,15 +791,14 @@ struct TechmapWorker { wire->port_id = 0; for (int i = 0; i < wire->width; i++) { - port_new2old_map.emplace(RTLIL::SigBit(new_wire, i), - RTLIL::SigBit(wire, i)); - port_connmap.emplace(RTLIL::SigBit(wire, i), - RTLIL::SigBit(new_wire, i)); + port_new2old_map.emplace(RTLIL::SigBit(new_wire, i), RTLIL::SigBit(wire, i)); + port_connmap.emplace(RTLIL::SigBit(wire, i), RTLIL::SigBit(new_wire, i)); } } // Handle outputs first, as these cannot be remapped. - for (auto &conn : cell->connections()) { + for (auto &conn : cell->connections()) + { Wire *twire = tpl->wire(conn.first); if (!twire->port_output) continue; @@ -802,22 +811,28 @@ struct TechmapWorker { } // Now handle inputs, remapping as necessary. - for (auto &conn : cell->connections()) { + for (auto &conn : cell->connections()) + { Wire *twire = tpl->wire(conn.first); if (twire->port_output) continue; - for (int i = 0; i < GetSize(conn.second); i++) { + for (int i = 0; i < GetSize(conn.second); i++) + { RTLIL::SigBit bit = sigmap(conn.second[i]); RTLIL::SigBit tplbit(twire, i); - if (bit.wire == nullptr) { + if (bit.wire == nullptr) + { RTLIL::SigBit oldbit = port_new2old_map.at(tplbit); port_connmap.at(oldbit) = bit; - } else if (cellbits_to_tplbits.count(bit)) { + } + else if (cellbits_to_tplbits.count(bit)) + { RTLIL::SigBit oldbit = port_new2old_map.at(tplbit); port_connmap.at(oldbit) = cellbits_to_tplbits[bit]; - } else + } + else cellbits_to_tplbits[bit] = tplbit; } } @@ -833,18 +848,17 @@ struct TechmapWorker { goto restart_eval_cmd_string; } - if (cmd_string.rfind("RECURSION; ", 0) == 0) { + if (cmd_string.rfind("RECURSION; ", 0) == 0) + { cmd_string = cmd_string.substr(strlen("RECURSION; ")); - while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { - } + while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { } goto restart_eval_cmd_string; } Pass::call_on_module(map, tpl, cmd_string); log_assert(!strncmp(q, "_TECHMAP_DO_", 12)); - std::string new_name = - data.wire->name.substr(0, q - p) + "_TECHMAP_DONE_" + data.wire->name.substr(q - p + 12); + std::string new_name = data.wire->name.substr(0, q-p) + "_TECHMAP_DONE_" + data.wire->name.substr(q-p+12); while (tpl->wire(new_name) != nullptr) new_name += "_"; tpl->rename(data.wire->name, new_name); @@ -856,15 +870,12 @@ struct TechmapWorker { TechmapWires twd = techmap_find_special_wires(tpl); for (auto &it : twd) { - if (!it.first.ends_with("_TECHMAP_FAIL_") && - (!it.first.begins_with("\\_TECHMAP_REMOVEINIT_") || !it.first.ends_with("_")) && - !it.first.contains("_TECHMAP_DO_") && !it.first.contains("_TECHMAP_DONE_")) + if (!it.first.ends_with("_TECHMAP_FAIL_") && (!it.first.begins_with("\\_TECHMAP_REMOVEINIT_") || !it.first.ends_with("_")) && !it.first.contains("_TECHMAP_DO_") && !it.first.contains("_TECHMAP_DONE_")) log_error("Techmap yielded unknown config wire %s.\n", log_id(it.first)); if (techmap_do_cache[tpl]) for (auto &it2 : it.second) if (!it2.value.is_fully_const()) - log_error("Techmap yielded config wire %s with non-const value %s.\n", - log_id(it2.wire->name), log_signal(it2.value)); + log_error("Techmap yielded config wire %s with non-const value %s.\n", log_id(it2.wire->name), log_signal(it2.value)); techmap_wire_names.erase(it.first); } @@ -877,8 +888,7 @@ struct TechmapWorker { log_continue = false; mkdebug.off(); } - while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { - } + while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { } } } @@ -908,10 +918,12 @@ struct TechmapWorker { } } - if (extern_mode && !in_recursion) { + if (extern_mode && !in_recursion) + { std::string m_name = stringf("$extern:%s", log_id(tpl)); - if (!design->module(m_name)) { + if (!design->module(m_name)) + { RTLIL::Module *m = design->addModule(m_name); tpl->cloneInto(m); @@ -926,14 +938,15 @@ struct TechmapWorker { log_debug("%s %s.%s to imported %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(m_name)); cell->type = m_name; cell->parameters.clear(); - } else { + } + else + { auto msg = stringf("Using template %s for cells of type %s.", log_id(tpl), log_id(cell->type)); if (!log_msg_cache.count(msg)) { log_msg_cache.insert(msg); log("%s\n", msg.c_str()); } - log_debug("%s %s.%s (%s) using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), - log_id(cell->type), log_id(tpl)); + log_debug("%s %s.%s (%s) using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(tpl)); techmap_module_worker(design, module, cell, tpl); cell = nullptr; } @@ -959,7 +972,7 @@ struct TechmapWorker { }; struct TechmapPass : public Pass { - TechmapPass() : Pass("techmap", "generic technology mapper") {} + TechmapPass() : Pass("techmap", "generic technology mapper") { } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -1140,19 +1153,19 @@ struct TechmapPass : public Pass { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - if (args[argidx] == "-map" && argidx + 1 < args.size()) { + if (args[argidx] == "-map" && argidx+1 < args.size()) { map_files.push_back(args[++argidx]); continue; } - if (args[argidx] == "-max_iter" && argidx + 1 < args.size()) { + if (args[argidx] == "-max_iter" && argidx+1 < args.size()) { max_iter = atoi(args[++argidx].c_str()); continue; } - if (args[argidx] == "-D" && argidx + 1 < args.size()) { + if (args[argidx] == "-D" && argidx+1 < args.size()) { verilog_frontend += " -D " + args[++argidx]; continue; } - if (args[argidx] == "-I" && argidx + 1 < args.size()) { + if (args[argidx] == "-I" && argidx+1 < args.size()) { verilog_frontend += " -I " + args[++argidx]; continue; } @@ -1188,15 +1201,13 @@ struct TechmapPass : public Pass { if (fn.compare(0, 1, "%") == 0) { if (!saved_designs.count(fn.substr(1))) { delete map; - log_cmd_error("Can't open saved design `%s'.\n", fn.c_str() + 1); + log_cmd_error("Can't open saved design `%s'.\n", fn.c_str()+1); } for (auto mod : saved_designs.at(fn.substr(1))->modules()) if (!map->module(mod->name)) map->add(mod->clone()); } else { - Frontend::frontend_call( - map, nullptr, fn, - (fn.size() > 3 && fn.compare(fn.size() - 3, std::string::npos, ".il") == 0 ? "rtlil" : verilog_frontend)); + Frontend::frontend_call(map, nullptr, fn, (fn.size() > 3 && fn.compare(fn.size()-3, std::string::npos, ".il") == 0 ? "rtlil" : verilog_frontend)); } } @@ -1222,15 +1233,15 @@ struct TechmapPass : public Pass { if (epos == std::string::npos) log_error("Malformed techmap_celltype pattern %s\n", q); for (size_t i = pos + 1; i < epos; i++) { - queue.push_back(name.substr(0, pos) + name[i] + - name.substr(epos + 1, std::string::npos)); + queue.push_back(name.substr(0, pos) + name[i] + name.substr(epos + 1, std::string::npos)); } } } } free(p); } else { - IdString module_name = module->name.begins_with("\\$") ? module->name.substr(1) : module->name.str(); + IdString module_name = module->name.begins_with("\\$") ? + module->name.substr(1) : module->name.str(); celltypeMap[module_name].insert(module->name); } } @@ -1247,13 +1258,14 @@ struct TechmapPass : public Pass { for (auto module : design->modules()) worker.module_queue.insert(module); - while (!worker.module_queue.empty()) { + while (!worker.module_queue.empty()) + { RTLIL::Module *module = *worker.module_queue.begin(); worker.module_queue.erase(module); int module_max_iter = max_iter; bool did_something = true; - pool handled_cells; + pool handled_cells; while (did_something) { did_something = false; if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false)) From 1bbc12f389a131e8af65dece57ba25d8c96b77d0 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Fri, 29 Sep 2023 15:17:42 -0700 Subject: [PATCH 41/95] Revert changes to techmap.cc. --- passes/techmap/techmap.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 23d0d93fc..144f596c8 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -156,6 +156,8 @@ struct TechmapWorker } std::string orig_cell_name; + pool extra_src_attrs = cell->get_strpool_attribute(ID::src); + orig_cell_name = cell->name.str(); for (auto tpl_cell : tpl->cells()) if (tpl_cell->name.ends_with("_TECHMAP_REPLACE_")) { @@ -170,7 +172,7 @@ struct TechmapWorker apply_prefix(cell->name, m_name); RTLIL::Memory *m = module->addMemory(m_name, it.second); if (m->attributes.count(ID::src)) - m->attributes[ID::src] = cell->attributes[ID::src]; + m->add_strpool_attribute(ID::src, extra_src_attrs); memory_renames[it.first] = m->name; design->select(module, m); } @@ -215,7 +217,7 @@ struct TechmapWorker if (tpl_w->get_bool_attribute(ID::_techmap_special_)) w->attributes.clear(); if (w->attributes.count(ID::src)) - w->attributes[ID::src] = cell->attributes[ID::src]; + w->add_strpool_attribute(ID::src, extra_src_attrs); } design->select(module, w); @@ -373,7 +375,7 @@ struct TechmapWorker } if (c->attributes.count(ID::src)) - c->attributes[ID::src] = cell->attributes[ID::src]; + c->add_strpool_attribute(ID::src, extra_src_attrs); if (techmap_replace_cell) { for (auto attr : cell->attributes) From bce984fa60fed1b46a95383d0737eb620fb0c340 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Mon, 2 Oct 2023 15:57:18 -0700 Subject: [PATCH 42/95] Speed up OptMergePass by 1.7x. The main speedup comes from swithing from using a SHA1 hash to std::hash. There is no need to use an expensive cryptographic hash for fingerprinting in this context. --- kernel/celltypes.h | 10 +++++----- kernel/rtlil.h | 6 +++++- passes/opt/opt_merge.cc | 11 +++++------ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/kernel/celltypes.h b/kernel/celltypes.h index cad505d9a..58c6907dc 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -56,7 +56,7 @@ struct CellTypes setup_stdcells_mem(); } - void setup_type(RTLIL::IdString type, const pool &inputs, const pool &outputs, bool is_evaluable = false) + void setup_type(const RTLIL::IdString& type, const pool &inputs, const pool &outputs, bool is_evaluable = false) { CellType ct = {type, inputs, outputs, is_evaluable}; cell_types[ct.type] = ct; @@ -298,24 +298,24 @@ struct CellTypes cell_types.clear(); } - bool cell_known(RTLIL::IdString type) const + bool cell_known(const RTLIL::IdString& type) const { return cell_types.count(type) != 0; } - bool cell_output(RTLIL::IdString type, RTLIL::IdString port) const + bool cell_output(const RTLIL::IdString& type, const RTLIL::IdString& port) const { auto it = cell_types.find(type); return it != cell_types.end() && it->second.outputs.count(port) != 0; } - bool cell_input(RTLIL::IdString type, RTLIL::IdString port) const + bool cell_input(const RTLIL::IdString& type, const RTLIL::IdString& port) const { auto it = cell_types.find(type); return it != cell_types.end() && it->second.inputs.count(port) != 0; } - bool cell_evaluable(RTLIL::IdString type) const + bool cell_evaluable(const RTLIL::IdString& type) const { auto it = cell_types.find(type); return it != cell_types.end() && it->second.is_evaluable; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index c50d75e90..f53d9df8c 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -308,10 +308,14 @@ namespace RTLIL bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; } char operator[](size_t i) const { - const char *p = c_str(); + const char *p = c_str(); +#ifndef NDEBUG for (; i != 0; i--, p++) log_assert(*p != 0); return *p; +#else + return *(p + i); +#endif } std::string substr(size_t pos = 0, size_t len = std::string::npos) const { diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index e9d98cd43..4bcd5a189 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -41,7 +41,7 @@ struct OptMergeWorker CellTypes ct; int total_count; - SHA1 checksum; + using FingerPrint = std::hash::result_type; static void sort_pmux_conn(dict &conn) { @@ -78,7 +78,7 @@ struct OptMergeWorker return str; } - std::string hash_cell_parameters_and_connections(const RTLIL::Cell *cell) + FingerPrint hash_cell_parameters_and_connections(const RTLIL::Cell *cell) { vector hash_conn_strings; std::string hash_string = cell->type.str() + "\n"; @@ -149,8 +149,7 @@ struct OptMergeWorker for (auto it : hash_conn_strings) hash_string += it; - checksum.update(hash_string); - return checksum.final(); + return std::hash{}(hash_string); } bool compare_cell_parameters_and_connections(const RTLIL::Cell *cell1, const RTLIL::Cell *cell2) @@ -268,13 +267,13 @@ struct OptMergeWorker } did_something = false; - dict sharemap; + std::unordered_map sharemap; for (auto cell : cells) { if ((!mode_share_all && !ct.cell_known(cell->type)) || !cell->known()) continue; - auto hash = hash_cell_parameters_and_connections(cell); + FingerPrint hash = hash_cell_parameters_and_connections(cell); auto r = sharemap.insert(std::make_pair(hash, cell)); if (!r.second) { if (compare_cell_parameters_and_connections(cell, r.first->second)) { From 058973faee14b822d4b68444b0cc09eea099f6f1 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Mon, 2 Oct 2023 16:15:47 -0700 Subject: [PATCH 43/95] Undo formatting change. --- kernel/rtlil.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index f53d9df8c..ef33ab2d7 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -308,7 +308,7 @@ namespace RTLIL bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; } char operator[](size_t i) const { - const char *p = c_str(); + const char *p = c_str(); #ifndef NDEBUG for (; i != 0; i--, p++) log_assert(*p != 0); From 11ffd7df40260f782c82b43be190a48ec88214a1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 00:15:18 +0000 Subject: [PATCH 44/95] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a96f3f549..ce76fda9a 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+79 +YOSYS_VER := 0.33+103 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 4968229efc2918365b2da0493fd33b6c57f09380 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Mon, 2 Oct 2023 11:00:00 -0700 Subject: [PATCH 45/95] Speed up stringf / vstringf by 1.8x. The main speedup is accomplished by avoiding a heap allocation in the common case where the final string length is less than 128. Inlining stringf & vstringf adds an additional improvement. --- kernel/yosys.cc | 46 +++--------------------------------- kernel/yosys.h | 63 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 64 insertions(+), 45 deletions(-) diff --git a/kernel/yosys.cc b/kernel/yosys.cc index bd8dded4b..82f1a9dd9 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -74,6 +74,7 @@ #include #include "libs/json11/json11.hpp" +#include "devtools/build/runtime/get_runfiles_dir.h" YOSYS_NAMESPACE_BEGIN @@ -175,48 +176,6 @@ int ceil_log2(int x) #endif } -std::string stringf(const char *fmt, ...) -{ - std::string string; - va_list ap; - - va_start(ap, fmt); - string = vstringf(fmt, ap); - va_end(ap); - - return string; -} - -std::string vstringf(const char *fmt, va_list ap) -{ - std::string string; - char *str = NULL; - -#if defined(_WIN32 )|| defined(__CYGWIN__) - int sz = 64, rc; - while (1) { - va_list apc; - va_copy(apc, ap); - str = (char*)realloc(str, sz); - rc = vsnprintf(str, sz, fmt, apc); - va_end(apc); - if (rc >= 0 && rc < sz) - break; - sz *= 2; - } -#else - if (vasprintf(&str, fmt, ap) < 0) - str = NULL; -#endif - - if (str != NULL) { - string = str; - free(str); - } - - return string; -} - int readsome(std::istream &f, char *s, int n) { int rc = int(f.readsome(s, n)); @@ -1025,7 +984,8 @@ void init_share_dirname() return; } # ifdef YOSYS_DATDIR - proc_share_path = YOSYS_DATDIR "/"; + proc_share_path = devtools_build::GetRunfilesDir() + "/"; + proc_share_path += YOSYS_DATDIR "/"; if (check_file_exists(proc_share_path, true)) { yosys_share_dirname = proc_share_path; return; diff --git a/kernel/yosys.h b/kernel/yosys.h index 29415ff84..57deb7236 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -272,8 +272,62 @@ inline void memhasher() { if (memhasher_active) memhasher_do(); } void yosys_banner(); 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); + +inline std::string vstringf(const char *fmt, va_list ap) +{ + // For the common case of strings shorter than 128 (including the trailing + // '\0'), save a heap allocation by using a stack allocated buffer. + const int kBufSize = 128; + char buf[kBufSize]; + buf[0] = '\0'; + va_list apc; + va_copy(apc, ap); + int n = vsnprintf(buf, kBufSize, fmt, apc); + va_end(apc); + if (n < kBufSize) + return std::string(buf); + + std::string string; + char *str = NULL; +#if defined(_WIN32 )|| defined(__CYGWIN__) + int sz = 2 * kBufSize, rc; + while (1) { + va_copy(apc, ap); + str = (char*)realloc(str, sz); + rc = vsnprintf(str, sz, fmt, apc); + va_end(apc); + if (rc >= 0 && rc < sz) + break; + sz *= 2; + } + if (str != NULL) { + string = str; + free(str); + } + return string; +#else + if (vasprintf(&str, fmt, ap) < 0) + str = NULL; + if (str != NULL) { + string = str; + free(str); + } + return string; +#endif +} + +inline std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)) +{ + std::string string; + va_list ap; + + va_start(ap, fmt); + string = vstringf(fmt, ap); + va_end(ap); + + return string; +} + int readsome(std::istream &f, char *s, int n); std::string next_token(std::string &text, const char *sep = " \t\r\n", bool long_strings = false); std::vector split_tokens(const std::string &text, const char *sep = " \t\r\n"); @@ -289,6 +343,11 @@ bool is_absolute_path(std::string filename); void remove_directory(std::string dirname); std::string escape_filename_spaces(const std::string& filename); +using ys_size_type = int64_t; // Large enough to deal with large number of data, but also not experiencing unsigned overflow. + +// TODO(hzeller): these need to return ys_size_type, but in the course of +// refactoring, each type will be handled separately (and gets their own GetSize() function). After all +// size types are converted, this template can be changed to return ys_size_type. template int GetSize(const T &obj) { return obj.size(); } inline int GetSize(RTLIL::Wire *wire); From ff915d21b67b2746573372568c51e5737b356083 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Mon, 2 Oct 2023 11:05:04 -0700 Subject: [PATCH 46/95] Update comment. --- kernel/yosys.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/yosys.h b/kernel/yosys.h index 57deb7236..5ee5eb75f 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -275,8 +275,8 @@ int ceil_log2(int x) YS_ATTRIBUTE(const); inline std::string vstringf(const char *fmt, va_list ap) { - // For the common case of strings shorter than 128 (including the trailing - // '\0'), save a heap allocation by using a stack allocated buffer. + // For the common case of strings shorter than 128, save a heap + // allocation by using a stack allocated buffer. const int kBufSize = 128; char buf[kBufSize]; buf[0] = '\0'; From cb9f318d37bdb557b7111914e8c25b3ed505ac3d Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Mon, 2 Oct 2023 11:07:28 -0700 Subject: [PATCH 47/95] Remove local modifications. --- kernel/yosys.cc | 4 +--- kernel/yosys.h | 5 ----- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 82f1a9dd9..559ce872c 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -74,7 +74,6 @@ #include #include "libs/json11/json11.hpp" -#include "devtools/build/runtime/get_runfiles_dir.h" YOSYS_NAMESPACE_BEGIN @@ -984,8 +983,7 @@ void init_share_dirname() return; } # ifdef YOSYS_DATDIR - proc_share_path = devtools_build::GetRunfilesDir() + "/"; - proc_share_path += YOSYS_DATDIR "/"; + proc_share_path = YOSYS_DATDIR "/"; if (check_file_exists(proc_share_path, true)) { yosys_share_dirname = proc_share_path; return; diff --git a/kernel/yosys.h b/kernel/yosys.h index 5ee5eb75f..99edfb700 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -343,11 +343,6 @@ bool is_absolute_path(std::string filename); void remove_directory(std::string dirname); std::string escape_filename_spaces(const std::string& filename); -using ys_size_type = int64_t; // Large enough to deal with large number of data, but also not experiencing unsigned overflow. - -// TODO(hzeller): these need to return ys_size_type, but in the course of -// refactoring, each type will be handled separately (and gets their own GetSize() function). After all -// size types are converted, this template can be changed to return ys_size_type. template int GetSize(const T &obj) { return obj.size(); } inline int GetSize(RTLIL::Wire *wire); From a6247cba42d126fe429dba37c62145b24ac8f500 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Mon, 2 Oct 2023 11:24:53 -0700 Subject: [PATCH 48/95] Fix compiler warnings from GCC. --- kernel/yosys.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/yosys.h b/kernel/yosys.h index 99edfb700..97a79861e 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -316,7 +316,9 @@ inline std::string vstringf(const char *fmt, va_list ap) #endif } -inline std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)) +std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)); + +inline std::string stringf(const char *fmt, ...) { std::string string; va_list ap; From c1745970147bb17d65943297c8b9369cacec2bd3 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 3 Oct 2023 11:46:43 +0200 Subject: [PATCH 49/95] Fix sva_value_change_changed test for updated verific --- tests/sva/sva_value_change_changed.sv | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/sva/sva_value_change_changed.sv b/tests/sva/sva_value_change_changed.sv index 8f3a05a2f..3ce207850 100644 --- a/tests/sva/sva_value_change_changed.sv +++ b/tests/sva/sva_value_change_changed.sv @@ -8,9 +8,11 @@ module top ( $changed(b) ); + wire x = 'x; + `ifndef FAIL assume property ( - b !== 'x ##1 $changed(b) + b !== x ##1 $changed(b) ); `endif From 563a56d9ff07cadd93b8b64977d1b8b83f94170d Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 3 Oct 2023 15:52:01 +0200 Subject: [PATCH 50/95] verific: Improve interaction between -L, -work and bind statements --- frontends/verific/verific.cc | 40 +++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 310e39180..9138bb63c 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -3063,6 +3063,7 @@ struct VerificPass : public Pass { int argidx = 1; std::string work = "work"; bool is_work_set = false; + (void)is_work_set; veri_file::RegisterCallBackVerificStream(&verific_read_cb); if (GetSize(args) > argidx && (args[argidx] == "-set-error" || args[argidx] == "-set-warning" || @@ -3140,7 +3141,20 @@ struct VerificPass : public Pass { } veri_file::RemoveAllLOptions(); - veri_file::AddLOption("work"); + for (int i = argidx; i < GetSize(args); i++) + { + if (args[i] == "-work" && i+1 < GetSize(args)) { + work = args[++i]; + is_work_set = true; + continue; + } + if (args[i] == "-L" && i+1 < GetSize(args)) { + ++i; + continue; + } + break; + } + veri_file::AddLOption(work.c_str()); for (int i = argidx; i < GetSize(args); i++) { if (args[i] == "-work" && i+1 < GetSize(args)) { @@ -3148,7 +3162,7 @@ struct VerificPass : public Pass { continue; } if (args[i] == "-L" && i+1 < GetSize(args)) { - if (args[++i] == "work") + if (args[++i] == work) veri_file::RemoveAllLOptions(); continue; } @@ -3641,7 +3655,7 @@ struct VerificPass : public Pass { if (module_name && module_name->IsHierName()) { VeriName *prefix = module_name->GetPrefix() ; const char *lib_name = (prefix) ? prefix->GetName() : 0 ; - if (!Strings::compare("work", lib_name)) lib = veri_file::GetLibrary(lib_name, 1) ; + if (work != lib_name) lib = veri_file::GetLibrary(lib_name, 1) ; } if (lib && module_name) top_mod_names.insert(lib->GetModule(module_name->GetName(), 1)->GetName()); @@ -3663,13 +3677,19 @@ struct VerificPass : public Pass { log_error("Can't find module/unit '%s'.\n", name); } - if (veri_lib) { - // Also elaborate all root modules since they may contain bind statements - MapIter mi; - VeriModule *veri_module; - FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) { - if (!veri_module->IsRootModule()) continue; - veri_modules.InsertLast(veri_module); + + const char *lib_name = nullptr; + SetIter si; + FOREACH_SET_ITEM(veri_file::GetAllLOptions(), si, &lib_name) { + VeriLibrary* veri_lib = veri_file::GetLibrary(lib_name, 0); + if (veri_lib) { + // Also elaborate all root modules since they may contain bind statements + MapIter mi; + VeriModule *veri_module; + FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) { + if (!veri_module->IsRootModule()) continue; + veri_modules.InsertLast(veri_module); + } } } From 7b454d4633c12dd7ee55f52911116524a3a6da41 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Tue, 3 Oct 2023 14:06:41 -0700 Subject: [PATCH 51/95] Revert changes to celltypes.h. --- kernel/celltypes.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 58c6907dc..cad505d9a 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -56,7 +56,7 @@ struct CellTypes setup_stdcells_mem(); } - void setup_type(const RTLIL::IdString& type, const pool &inputs, const pool &outputs, bool is_evaluable = false) + void setup_type(RTLIL::IdString type, const pool &inputs, const pool &outputs, bool is_evaluable = false) { CellType ct = {type, inputs, outputs, is_evaluable}; cell_types[ct.type] = ct; @@ -298,24 +298,24 @@ struct CellTypes cell_types.clear(); } - bool cell_known(const RTLIL::IdString& type) const + bool cell_known(RTLIL::IdString type) const { return cell_types.count(type) != 0; } - bool cell_output(const RTLIL::IdString& type, const RTLIL::IdString& port) const + bool cell_output(RTLIL::IdString type, RTLIL::IdString port) const { auto it = cell_types.find(type); return it != cell_types.end() && it->second.outputs.count(port) != 0; } - bool cell_input(const RTLIL::IdString& type, const RTLIL::IdString& port) const + bool cell_input(RTLIL::IdString type, RTLIL::IdString port) const { auto it = cell_types.find(type); return it != cell_types.end() && it->second.inputs.count(port) != 0; } - bool cell_evaluable(const RTLIL::IdString& type) const + bool cell_evaluable(RTLIL::IdString type) const { auto it = cell_types.find(type); return it != cell_types.end() && it->second.is_evaluable; From 8e0308b5e7b0c0bbe10c072123d2e7b945f4b6b0 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Tue, 3 Oct 2023 14:25:59 -0700 Subject: [PATCH 52/95] Revert changes to celltypes.h. Use dict instead of std::unordered_map and most hash function for uint64_t to hashlib.h to support this. --- kernel/hashlib.h | 6 ++++++ passes/opt/opt_merge.cc | 2 +- passes/sat/recover_names.cc | 9 +-------- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index be759fdf0..9cf43da6c 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -90,6 +90,12 @@ template<> struct hash_ops : hash_int_ops return a; } }; +template<> struct hash_ops : hash_int_ops +{ + static inline unsigned int hash(uint64_t a) { + return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); + } +}; template<> struct hash_ops { static inline bool cmp(const std::string &a, const std::string &b) { diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index 4bcd5a189..87ad01f00 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -267,7 +267,7 @@ struct OptMergeWorker } did_something = false; - std::unordered_map sharemap; + dict sharemap; for (auto cell : cells) { if ((!mode_share_all && !ct.cell_known(cell->type)) || !cell->known()) diff --git a/passes/sat/recover_names.cc b/passes/sat/recover_names.cc index 2d7e7f01c..4c30a3632 100644 --- a/passes/sat/recover_names.cc +++ b/passes/sat/recover_names.cc @@ -29,13 +29,6 @@ USING_YOSYS_NAMESPACE -template<> struct hashlib::hash_ops : hashlib::hash_int_ops -{ - static inline unsigned int hash(uint64_t a) { - return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); - } -}; - PRIVATE_NAMESPACE_BEGIN // xorshift128 params @@ -453,7 +446,7 @@ struct RecoverNamesWorker { pool comb_whiteboxes, buffer_types; // class -> (gold, (gate, inverted)) - dict, dict>> cls2bits; + dict, dict>> cls2bits; void analyse_boxes() { From 57a2b4b0cd542f2053616bbc8ece614a28d72f3a Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Tue, 3 Oct 2023 15:02:02 -0700 Subject: [PATCH 53/95] Explicitly use uint64_t as the type of fingerprint to avoid type mismatch with some compilers. --- passes/opt/opt_merge.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index 87ad01f00..248ba8091 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -41,7 +41,6 @@ struct OptMergeWorker CellTypes ct; int total_count; - using FingerPrint = std::hash::result_type; static void sort_pmux_conn(dict &conn) { @@ -78,7 +77,7 @@ struct OptMergeWorker return str; } - FingerPrint hash_cell_parameters_and_connections(const RTLIL::Cell *cell) + uint64_t hash_cell_parameters_and_connections(const RTLIL::Cell *cell) { vector hash_conn_strings; std::string hash_string = cell->type.str() + "\n"; @@ -267,13 +266,13 @@ struct OptMergeWorker } did_something = false; - dict sharemap; + dict sharemap; for (auto cell : cells) { if ((!mode_share_all && !ct.cell_known(cell->type)) || !cell->known()) continue; - FingerPrint hash = hash_cell_parameters_and_connections(cell); + uint64_t hash = hash_cell_parameters_and_connections(cell); auto r = sharemap.insert(std::make_pair(hash, cell)); if (!r.second) { if (compare_cell_parameters_and_connections(cell, r.first->second)) { From 294844137bb1fd8854a18cc2a0c703aa30726761 Mon Sep 17 00:00:00 2001 From: Lofty Date: Tue, 3 Oct 2023 10:32:18 +0100 Subject: [PATCH 54/95] gowin: fix abc9 attributes and specify blocks --- techlibs/gowin/cells_sim.v | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/techlibs/gowin/cells_sim.v b/techlibs/gowin/cells_sim.v index 86bd677e2..b26869080 100644 --- a/techlibs/gowin/cells_sim.v +++ b/techlibs/gowin/cells_sim.v @@ -197,7 +197,7 @@ module DFFE (output reg Q, input D, CLK, CE); end endmodule // DFFE (positive clock edge; clock enable) -(* abc9_box, lib_whitebox *) +(* abc9_flop, lib_whitebox *) module DFFS (output reg Q, input D, CLK, SET); parameter [0:0] INIT = 1'b1; initial Q = INIT; @@ -216,7 +216,7 @@ module DFFS (output reg Q, input D, CLK, SET); end endmodule // DFFS (positive clock edge; synchronous set) -(* abc9_box, lib_whitebox *) +(* abc9_flop, lib_whitebox *) module DFFSE (output reg Q, input D, CLK, CE, SET); parameter [0:0] INIT = 1'b1; initial Q = INIT; @@ -282,7 +282,7 @@ module DFFP (output reg Q, input D, CLK, PRESET); specify (posedge CLK => (Q : D)) = (480, 660); - (posedge PRESET => (Q : 1'b1)) = (1800, 2679); + (PRESET => Q) = (1800, 2679); $setup(D, posedge CLK, 576); endspecify @@ -301,7 +301,7 @@ module DFFPE (output reg Q, input D, CLK, CE, PRESET); specify if (CE) (posedge CLK => (Q : D)) = (480, 660); - (posedge PRESET => (Q : 1'b1)) = (1800, 2679); + (PRESET => Q) = (1800, 2679); $setup(D, posedge CLK &&& CE, 576); $setup(CE, posedge CLK, 63); endspecify @@ -321,7 +321,7 @@ module DFFC (output reg Q, input D, CLK, CLEAR); specify (posedge CLK => (Q : D)) = (480, 660); - (posedge CLEAR => (Q : 1'b0)) = (1800, 2679); + (CLEAR => Q) = (1800, 2679); $setup(D, posedge CLK, 576); endspecify @@ -340,7 +340,7 @@ module DFFCE (output reg Q, input D, CLK, CE, CLEAR); specify if (CE) (posedge CLK => (Q : D)) = (480, 660); - (posedge CLEAR => (Q : 1'b0)) = (1800, 2679); + (CLEAR => Q) = (1800, 2679); $setup(D, posedge CLK &&& CE, 576); $setup(CE, posedge CLK, 63); endspecify @@ -384,7 +384,7 @@ module DFFNE (output reg Q, input D, CLK, CE); end endmodule // DFFNE (negative clock edge; clock enable) -(* abc9_box, lib_whitebox *) +(* abc9_flop, lib_whitebox *) module DFFNS (output reg Q, input D, CLK, SET); parameter [0:0] INIT = 1'b1; initial Q = INIT; @@ -403,7 +403,7 @@ module DFFNS (output reg Q, input D, CLK, SET); end endmodule // DFFNS (negative clock edge; synchronous set) -(* abc9_box, lib_whitebox *) +(* abc9_flop, lib_whitebox *) module DFFNSE (output reg Q, input D, CLK, CE, SET); parameter [0:0] INIT = 1'b1; initial Q = INIT; @@ -469,7 +469,7 @@ module DFFNP (output reg Q, input D, CLK, PRESET); specify (negedge CLK => (Q : D)) = (480, 660); - (posedge PRESET => (Q : 1'b1)) = (1800, 2679); + (PRESET => Q) = (1800, 2679); $setup(D, negedge CLK, 576); endspecify @@ -488,7 +488,7 @@ module DFFNPE (output reg Q, input D, CLK, CE, PRESET); specify if (CE) (negedge CLK => (Q : D)) = (480, 660); - (posedge PRESET => (Q : 1'b1)) = (1800, 2679); + (PRESET => Q) = (1800, 2679); $setup(D, negedge CLK &&& CE, 576); $setup(CE, negedge CLK, 63); endspecify @@ -508,7 +508,7 @@ module DFFNC (output reg Q, input D, CLK, CLEAR); specify (negedge CLK => (Q : D)) = (480, 660); - (posedge CLEAR => (Q : 1'b0)) = (1800, 2679); + (CLEAR => Q) = (1800, 2679); $setup(D, negedge CLK, 576); endspecify @@ -527,7 +527,7 @@ module DFFNCE (output reg Q, input D, CLK, CE, CLEAR); specify if (CE) (negedge CLK => (Q : D)) = (480, 660); - (posedge CLEAR => (Q : 1'b0)) = (1800, 2679); + (CLEAR => Q) = (1800, 2679); $setup(D, negedge CLK &&& CE, 576); $setup(CE, negedge CLK, 63); endspecify @@ -957,7 +957,7 @@ end endmodule - +(* abc9_flop, lib_whitebox *) module RAM16S1 (DO, DI, AD, WRE, CLK); parameter INIT_0 = 16'h0000; @@ -992,7 +992,7 @@ end endmodule - +(* abc9_flop, lib_whitebox *) module RAM16S2 (DO, DI, AD, WRE, CLK); parameter INIT_0 = 16'h0000; @@ -1031,7 +1031,7 @@ end endmodule - +(* abc9_flop, lib_whitebox *) module RAM16S4 (DO, DI, AD, WRE, CLK); parameter INIT_0 = 16'h0000; From f00d6f3c12071c741abe6248ff03a026f6509dae Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 4 Oct 2023 00:15:12 +0000 Subject: [PATCH 55/95] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ce76fda9a..92b0a5d2e 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+103 +YOSYS_VER := 0.33+112 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 0434f9d3d1decc563877f73a3b963bc3d0cdef6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 4 Oct 2023 23:21:40 +0200 Subject: [PATCH 56/95] booth: Fix vacancy check when summing down result In commit fedd12261 ("booth: Move away from explicit `Wire` pointers") a bug was introduced when checking for vacant slots in arrays holding some intermediate results. Non-wire SigBit values were taken to imply a vacant slot, but actually a constant one can make its way into those results, if the multiplier cell configuration is just right. Fix the vacancy check to address the bug. --- passes/techmap/booth.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index 000dcff14..e1e6b360a 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -533,7 +533,7 @@ struct BoothPassWorker { // get the bits in this column. SigSpec column_bits; for (int row_ix = 0; row_ix < row_size; row_ix++) { - if (bits_to_reduce[row_ix][column_ix].wire) + if (bits_to_reduce[row_ix][column_ix] != State::S0) column_bits.append(bits_to_reduce[row_ix][column_ix]); } for (auto c : carry_bits_to_add_to_next_column) { @@ -750,7 +750,7 @@ struct BoothPassWorker { SigSpec first_csa_ips; // get the first 3 inputs, if possible for (var_ix = 0; var_ix < column_bits.size() && first_csa_ips.size() != 3; var_ix++) { - if (column_bits[var_ix].is_wire()) + if (column_bits[var_ix] != State::S0) first_csa_ips.append(column_bits[var_ix]); } @@ -782,7 +782,7 @@ struct BoothPassWorker { // get the next two variables to sum for (; var_ix <= column_bits.size() - 1 && csa_ips.size() < 2;) { // skip any empty bits - if (column_bits[var_ix].is_wire()) + if (column_bits[var_ix] != State::S0) csa_ips.append(column_bits[var_ix]); var_ix++; } From 4506e11d0fd1cd05a795203dc95a39f921c492b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 4 Oct 2023 23:29:40 +0200 Subject: [PATCH 57/95] booth: Extend test to catch bug from previous commit --- tests/techmap/booth.ys | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/techmap/booth.ys b/tests/techmap/booth.ys index ab7efc7b7..55dfdb8e9 100644 --- a/tests/techmap/booth.ys +++ b/tests/techmap/booth.ys @@ -1 +1,15 @@ -test_cell -s 1694091355 -n 100 -script booth_map_script.ys_ $mul +read_verilog < Date: Thu, 5 Oct 2023 09:14:12 +0200 Subject: [PATCH 58/95] Release version 0.34 --- CHANGELOG | 19 ++++++++++++++++++- Makefile | 4 ++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a662ba4da..60ad78b72 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,13 +2,30 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.33 .. Yosys 0.34-dev +Yosys 0.33 .. Yosys 0.34 -------------------------- + * New commands and options + - Added option "-assert" to "sim" pass. + - Added option "-noinitstate" to "sim" pass. + - Added option "-dont_use" to "abc" pass. + - Added "dft_tag" pass to create tagging logic for data flow tracking. + - Added "future" pass to resolve future sampled value functions. + - Added "booth" pass to map $mul cells to Booth multipliers. + - Added option "-booth" to "synth" pass. * SystemVerilog - Added support for assignments within expressions, e.g., `x[y++] = z;` or `x = (y *= 2) - 1;`. + * Verific support + - "src" attribute contain full location info. + - module parameters are kept after import. + - accurate access order semantics in memory inference. + - better "bind" support for mixed language projects. + + * Various + - "show" command displays dot instead of box for wire aliases. + Yosys 0.32 .. Yosys 0.33 -------------------------- * Various diff --git a/Makefile b/Makefile index 92b0a5d2e..b9c108981 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.33+112 +YOSYS_VER := 0.34 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -157,7 +157,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: - sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 2584903.. | wc -l`/;" Makefile +# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 2584903.. | wc -l`/;" Makefile # set 'ABCREV = default' to use abc/ as it is # From b88f7fc6e899ebed361b71efe12d095a8eeb61d2 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 5 Oct 2023 09:16:05 +0200 Subject: [PATCH 59/95] Next dev cycle --- CHANGELOG | 3 +++ Makefile | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 60ad78b72..ee5f6b43d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,9 @@ List of major changes and improvements between releases ======================================================= +Yosys 0.34 .. Yosys 0.35-dev +-------------------------- + Yosys 0.33 .. Yosys 0.34 -------------------------- * New commands and options diff --git a/Makefile b/Makefile index b9c108981..650e553c9 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.34 +YOSYS_VER := 0.34+0 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -157,7 +157,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: -# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 2584903.. | wc -l`/;" Makefile + sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 4a1b559.. | wc -l`/;" Makefile # set 'ABCREV = default' to use abc/ as it is # From 824fdaadf62fa58b81d268340a56bf847dc5724b Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 5 Oct 2023 09:55:53 +0200 Subject: [PATCH 60/95] mingw build fix --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 650e553c9..688b5939d 100644 --- a/Makefile +++ b/Makefile @@ -357,7 +357,7 @@ CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s LDLIBS := $(filter-out -lrt,$(LDLIBS)) ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w" -ABCMKARGS += LIBS="-lpthread -s" ABC_USE_NO_READLINE=0 CC="i686-w64-mingw32-gcc" CXX="$(CXX)" +ABCMKARGS += LIBS="-lpthread -lshlwapi -s" ABC_USE_NO_READLINE=0 CC="i686-w64-mingw32-gcc" CXX="$(CXX)" EXE = .exe else ifeq ($(CONFIG),msys2-64) @@ -368,7 +368,7 @@ CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s LDLIBS := $(filter-out -lrt,$(LDLIBS)) ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w" -ABCMKARGS += LIBS="-lpthread -s" ABC_USE_NO_READLINE=0 CC="x86_64-w64-mingw32-gcc" CXX="$(CXX)" +ABCMKARGS += LIBS="-lpthread -lshlwapi -s" ABC_USE_NO_READLINE=0 CC="x86_64-w64-mingw32-gcc" CXX="$(CXX)" EXE = .exe else ifneq ($(CONFIG),none) From 268fe92d22536525b3c88b1dc14fff2e4a319294 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 5 Oct 2023 11:22:40 +0200 Subject: [PATCH 61/95] verific: save original module name --- frontends/verific/verific.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 9138bb63c..85a685376 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1275,6 +1275,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma log("Importing module %s.\n", RTLIL::id2cstr(module->name)); } import_attributes(module->attributes, nl, nl); + module->set_string_attribute(ID::hdlname, nl->CellBaseName()); const char *param_name ; const char *param_value ; MapIter mi; From 23b9e61c477277b00cf34e593b8979f8f15a3600 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Thu, 5 Oct 2023 16:28:17 +0200 Subject: [PATCH 62/95] verific: Pass list of top modules to static elaboration --- frontends/verific/verific.cc | 147 ++++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 63 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 9138bb63c..da449e2d7 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -3595,15 +3595,16 @@ struct VerificPass : public Pass { std::set top_mod_names; -#ifdef YOSYSHQ_VERIFIC_EXTENSIONS - VerificExtensions::ElaborateAndRewrite(work, ¶meters); - verific_error_msg.clear(); -#endif - if (!ppfile.empty()) - veri_file::PrettyPrint(ppfile.c_str(), nullptr, work.c_str()); - if (mode_all) { + +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS + VerificExtensions::ElaborateAndRewrite(work, ¶meters); + verific_error_msg.clear(); +#endif + if (!ppfile.empty()) + veri_file::PrettyPrint(ppfile.c_str(), nullptr, work.c_str()); + log("Running hier_tree::ElaborateAll().\n"); VeriLibrary *veri_lib = veri_file::GetLibrary(work.c_str(), 1); @@ -3628,73 +3629,93 @@ struct VerificPass : public Pass { if (argidx == GetSize(args)) cmd_error(args, argidx, "No top module specified.\n"); - VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1); -#ifdef VERIFIC_VHDL_SUPPORT - VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1); -#endif + Array *netlists = nullptr; - Array veri_modules, vhdl_units; - for (; argidx < GetSize(args); argidx++) +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS + for (int static_elaborate = 1; static_elaborate >= 0; static_elaborate--) +#endif { - const char *name = args[argidx].c_str(); - top_mod_names.insert(name); - VeriModule *veri_module = veri_lib ? veri_lib->GetModule(name, 1) : nullptr; - if (veri_module) { - if (veri_module->IsConfiguration()) { - log("Adding Verilog configuration '%s' to elaboration queue.\n", name); - veri_modules.InsertLast(veri_module); - - top_mod_names.erase(name); - - VeriConfiguration *cfg = (VeriConfiguration*)veri_module; - VeriName *module_name; - int i; - FOREACH_ARRAY_ITEM(cfg->GetTopModuleNames(), i, module_name) { - VeriLibrary *lib = veri_module->GetLibrary() ; - if (module_name && module_name->IsHierName()) { - VeriName *prefix = module_name->GetPrefix() ; - const char *lib_name = (prefix) ? prefix->GetName() : 0 ; - if (work != lib_name) lib = veri_file::GetLibrary(lib_name, 1) ; - } - if (lib && module_name) - top_mod_names.insert(lib->GetModule(module_name->GetName(), 1)->GetName()); - } - } else { - log("Adding Verilog module '%s' to elaboration queue.\n", name); - veri_modules.InsertLast(veri_module); - } - continue; - } + VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1); #ifdef VERIFIC_VHDL_SUPPORT - VhdlDesignUnit *vhdl_unit = vhdl_lib ? vhdl_lib->GetPrimUnit(name) : nullptr; - if (vhdl_unit) { - log("Adding VHDL unit '%s' to elaboration queue.\n", name); - vhdl_units.InsertLast(vhdl_unit); + VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1); +#endif + + Array veri_modules, vhdl_units; + for (int i = argidx; i < GetSize(args); i++) + { + const char *name = args[i].c_str(); + top_mod_names.insert(name); + + VeriModule *veri_module = veri_lib ? veri_lib->GetModule(name, 1) : nullptr; + if (veri_module) { + if (veri_module->IsConfiguration()) { + log("Adding Verilog configuration '%s' to elaboration queue.\n", name); + veri_modules.InsertLast(veri_module); + + top_mod_names.erase(name); + + VeriConfiguration *cfg = (VeriConfiguration*)veri_module; + VeriName *module_name; + int i; + FOREACH_ARRAY_ITEM(cfg->GetTopModuleNames(), i, module_name) { + VeriLibrary *lib = veri_module->GetLibrary() ; + if (module_name && module_name->IsHierName()) { + VeriName *prefix = module_name->GetPrefix() ; + const char *lib_name = (prefix) ? prefix->GetName() : 0 ; + if (work != lib_name) lib = veri_file::GetLibrary(lib_name, 1) ; + } + if (lib && module_name) + top_mod_names.insert(lib->GetModule(module_name->GetName(), 1)->GetName()); + } + } else { + log("Adding Verilog module '%s' to elaboration queue.\n", name); + veri_modules.InsertLast(veri_module); + } + continue; + } +#ifdef VERIFIC_VHDL_SUPPORT + VhdlDesignUnit *vhdl_unit = vhdl_lib ? vhdl_lib->GetPrimUnit(name) : nullptr; + if (vhdl_unit) { + log("Adding VHDL unit '%s' to elaboration queue.\n", name); + vhdl_units.InsertLast(vhdl_unit); + continue; + } +#endif + log_error("Can't find module/unit '%s'.\n", name); + } + +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS + if (static_elaborate) { + VerificExtensions::ElaborateAndRewrite(work, &veri_modules, &vhdl_units, ¶meters); + verific_error_msg.clear(); +#endif + if (!ppfile.empty()) + veri_file::PrettyPrint(ppfile.c_str(), nullptr, work.c_str()); + +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS continue; } #endif - log_error("Can't find module/unit '%s'.\n", name); - } - - - const char *lib_name = nullptr; - SetIter si; - FOREACH_SET_ITEM(veri_file::GetAllLOptions(), si, &lib_name) { - VeriLibrary* veri_lib = veri_file::GetLibrary(lib_name, 0); - if (veri_lib) { - // Also elaborate all root modules since they may contain bind statements - MapIter mi; - VeriModule *veri_module; - FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) { - if (!veri_module->IsRootModule()) continue; - veri_modules.InsertLast(veri_module); + const char *lib_name = nullptr; + SetIter si; + FOREACH_SET_ITEM(veri_file::GetAllLOptions(), si, &lib_name) { + VeriLibrary* veri_lib = veri_file::GetLibrary(lib_name, 0); + if (veri_lib) { + // Also elaborate all root modules since they may contain bind statements + MapIter mi; + VeriModule *veri_module; + FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) { + if (!veri_module->IsRootModule()) continue; + veri_modules.InsertLast(veri_module); + } } } + + log("Running hier_tree::Elaborate().\n"); + netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, ¶meters); } - log("Running hier_tree::Elaborate().\n"); - Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, ¶meters); Netlist *nl; int i; From 47a4b790f8162451d91cf8a04f23f2893e0a3824 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Thu, 5 Oct 2023 16:40:43 +0200 Subject: [PATCH 63/95] verific: Pass top modules to static elaboration when using hierarchy --- frontends/verific/verific.cc | 88 ++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 34 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index da449e2d7..62307a459 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -2495,51 +2495,71 @@ std::string verific_import(Design *design, const std::mapGetModule(top.c_str(), 1); - if (veri_module) { - veri_modules.InsertLast(veri_module); - if (veri_module->IsConfiguration()) { - VeriConfiguration *cfg = (VeriConfiguration*)veri_module; - VeriName *module_name = (VeriName*)cfg->GetTopModuleNames()->GetLast(); - VeriLibrary *lib = veri_module->GetLibrary() ; - if (module_name && module_name->IsHierName()) { - VeriName *prefix = module_name->GetPrefix() ; - const char *lib_name = (prefix) ? prefix->GetName() : 0 ; - if (!Strings::compare("work", lib_name)) lib = veri_file::GetLibrary(lib_name, 1) ; +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS + for (int static_elaborate = 1; static_elaborate >= 0; static_elaborate--) +#endif + { + Array veri_modules, vhdl_units; + + if (veri_lib) { + VeriModule *veri_module = veri_lib->GetModule(top.c_str(), 1); + if (veri_module) { + veri_modules.InsertLast(veri_module); + if (veri_module->IsConfiguration()) { + VeriConfiguration *cfg = (VeriConfiguration*)veri_module; + VeriName *module_name = (VeriName*)cfg->GetTopModuleNames()->GetLast(); + VeriLibrary *lib = veri_module->GetLibrary() ; + if (module_name && module_name->IsHierName()) { + VeriName *prefix = module_name->GetPrefix() ; + const char *lib_name = (prefix) ? prefix->GetName() : 0 ; + if (!Strings::compare("work", lib_name)) lib = veri_file::GetLibrary(lib_name, 1) ; + } + if (lib && module_name) + top = lib->GetModule(module_name->GetName(), 1)->GetName(); + } + } + +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS + if (!static_elaborate) +#endif + { + // 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); } - if (lib && module_name) - top = lib->GetModule(module_name->GetName(), 1)->GetName(); } } - // 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); - } - } - #ifdef VERIFIC_VHDL_SUPPORT - if (vhdl_lib) { - VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(top.c_str()); - if (vhdl_unit) - vhdl_units.InsertLast(vhdl_unit); - } + if (vhdl_lib) { + VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(top.c_str()); + if (vhdl_unit) + vhdl_units.InsertLast(vhdl_unit); + } #endif - netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, &verific_params); + +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS + if (static_elaborate) { + VerificExtensions::ElaborateAndRewrite("work", &veri_modules, &vhdl_units, &verific_params); + verific_error_msg.clear(); + continue; + } +#endif + + netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, &verific_params); + } } Netlist *nl; From 6ac43e49bc7db6a6c13b0ff302ef193db1fa7064 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 5 Oct 2023 19:21:52 +0200 Subject: [PATCH 64/95] sim: Change clocked read port suggestion to `memory_nordff` `memory_nordff` has the advantage that it can be called just ahead of the simulation step no matter whether the clocked read port has been inferred or was explicitly instantiated in a flow. --- passes/sat/sim.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 963c6481b..314905914 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -579,7 +579,7 @@ struct SimInstance Const data = Const(State::Sx, mem.width << port.wide_log2); if (port.clk_enable) - log_error("Memory %s.%s has clocked read ports. Run 'memory' with -nordff.\n", log_id(module), log_id(mem.memid)); + log_error("Memory %s.%s has clocked read ports. Run 'memory_nordff' to transform the circuit to remove those.\n", log_id(module), log_id(mem.memid)); if (addr.is_fully_def()) { int addr_int = addr.as_int(); From a782b15aae8890c819c133566f77dc5ac8362b99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 5 Oct 2023 19:22:08 +0200 Subject: [PATCH 65/95] sim: s/instanced/instantiated/ --- passes/sat/sim.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 314905914..9ce799735 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -219,7 +219,7 @@ struct SimInstance log_assert(module); if (module->get_blackbox_attribute(true)) - log_error("Cannot simulate blackbox module %s (instanced at %s).\n", + log_error("Cannot simulate blackbox module %s (instantiated at %s).\n", log_id(module->name), hiername().c_str()); if (parent) { From c3fd88624a53c3778ea8ec1a43fc68d0686143ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 5 Oct 2023 19:23:48 +0200 Subject: [PATCH 66/95] sim: Bail on processes Instead of silently missimulating, error out when there are processes found in the simulation hierarchy. --- passes/sat/sim.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 9ce799735..a8516470c 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -222,6 +222,10 @@ struct SimInstance log_error("Cannot simulate blackbox module %s (instantiated at %s).\n", log_id(module->name), hiername().c_str()); + if (module->has_processes()) + log_error("Found processes in simulation hierarchy (in module %s at %s). Run 'proc' first.\n", + log_id(module), hiername().c_str()); + if (parent) { log_assert(parent->children.count(instance) == 0); parent->children[instance] = this; From e38c9e01c901e0f5d0eb9fe18981a2c5c95ddf61 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Thu, 5 Oct 2023 15:24:26 -0700 Subject: [PATCH 67/95] Undo formatting changes in kernel/utils.h. --- kernel/utils.h | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/kernel/utils.h b/kernel/utils.h index 4679a23f2..9b64ed8e1 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -31,30 +31,34 @@ YOSYS_NAMESPACE_BEGIN // A map-like container, but you can save and restore the state // ------------------------------------------------ -template > struct stackmap { - private: - std::vector> backup_state; +template> +struct stackmap +{ +private: + std::vector> backup_state; dict current_state; static T empty_tuple; - public: - stackmap() {} - stackmap(const dict &other) : current_state(other) {} +public: + stackmap() { } + stackmap(const dict &other) : current_state(other) { } - template stackmap &operator=(const Other &other) + template + void operator=(const Other &other) { - for (const auto &it : current_state) + for (auto &it : current_state) if (!backup_state.empty() && backup_state.back().count(it.first) == 0) backup_state.back()[it.first] = new T(it.second); current_state.clear(); - for (const auto &it : other) + for (auto &it : other) set(it.first, it.second); - - return *this; } - bool has(const Key &k) { return current_state.count(k) != 0; } + bool has(const Key &k) + { + return current_state.count(k) != 0; + } void set(const Key &k, const T &v) { @@ -79,7 +83,7 @@ template > struct stackma void reset(const Key &k) { - for (int i = GetSize(backup_state) - 1; i >= 0; i--) + for (int i = GetSize(backup_state)-1; i >= 0; i--) if (backup_state[i].count(k) != 0) { if (backup_state[i].at(k) == nullptr) current_state.erase(k); @@ -90,14 +94,20 @@ template > struct stackma current_state.erase(k); } - const dict &stdmap() { return current_state; } + const dict &stdmap() + { + return current_state; + } - void save() { backup_state.resize(backup_state.size() + 1); } + void save() + { + backup_state.resize(backup_state.size()+1); + } void restore() { log_assert(!backup_state.empty()); - for (const auto &it : backup_state.back()) + for (auto &it : backup_state.back()) if (it.second != nullptr) { current_state[it.first] = *it.second; delete it.second; From fd7bd420b3d9f1b031adced3add1f15f29048906 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Thu, 5 Oct 2023 15:26:29 -0700 Subject: [PATCH 68/95] Add back newline. --- kernel/utils.h | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/utils.h b/kernel/utils.h index 9b64ed8e1..255f875c3 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -123,6 +123,7 @@ public: } }; + // ------------------------------------------------ // A simple class for topological sorting // ------------------------------------------------ From 0a37c2a301f3518df0d3a9ced7b2b9477b4fe9a0 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Thu, 5 Oct 2023 17:01:42 -0700 Subject: [PATCH 69/95] Fix translation bug: The old code really checks for the presense of a node, not an edge in glift and flatten. Add back statement that inserts nodes in order in opt_expr.cc. --- kernel/utils.h | 8 +------- passes/cmds/glift.cc | 2 +- passes/opt/opt_expr.cc | 1 + passes/techmap/flatten.cc | 2 +- 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/kernel/utils.h b/kernel/utils.h index 255f875c3..5a1279ef0 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -174,11 +174,7 @@ template , typename OPS = hash_ops> cla void edge(T left, T right) { edge(node(left), node(right)); } - bool has_edges(const T &node) - { - auto it = node_to_index.find(node); - return it == node_to_index.end() || !edges[it->second].empty(); - } + bool has_node(const T &node) { return node_to_index.find(node) != node_to_index.end(); } bool sort() { @@ -192,8 +188,6 @@ template , typename OPS = hash_ops> cla std::vector marked_cells(edges.size(), false); std::vector active_cells(edges.size(), false); std::vector active_stack; - - marked_cells.reserve(edges.size()); sorted.reserve(edges.size()); for (const auto &it : node_to_index) diff --git a/passes/cmds/glift.cc b/passes/cmds/glift.cc index faa4289e3..8553b02a5 100644 --- a/passes/cmds/glift.cc +++ b/passes/cmds/glift.cc @@ -582,7 +582,7 @@ struct GliftPass : public Pass { for (auto cell : module->selected_cells()) { RTLIL::Module *tpl = design->module(cell->type); if (tpl != nullptr) { - if (!topo_modules.has_edges(tpl)) + if (!topo_modules.has_node(tpl)) worklist.push_back(tpl); topo_modules.edge(tpl, module); non_top_modules.insert(cell->type); diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 7331d72a6..3eadd35c6 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -424,6 +424,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons for (auto &bit : sig) outbit_to_cell[bit].insert(cell); } + cells.node(cell); } // Build the graph for the topological sort. diff --git a/passes/techmap/flatten.cc b/passes/techmap/flatten.cc index f49589b82..4ddc4aff1 100644 --- a/passes/techmap/flatten.cc +++ b/passes/techmap/flatten.cc @@ -312,7 +312,7 @@ struct FlattenPass : public Pass { for (auto cell : module->selected_cells()) { RTLIL::Module *tpl = design->module(cell->type); if (tpl != nullptr) { - if (!topo_modules.has_edges(tpl)) + if (!topo_modules.has_node(tpl)) worklist.insert(tpl); topo_modules.edge(tpl, module); } From fc815fdb478056247d46deee597e09df138a168d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 00:14:52 +0000 Subject: [PATCH 70/95] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 688b5939d..c6b5706cc 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.34+0 +YOSYS_VER := 0.34+7 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 6a5799cc2ed65a7481f9d1e9142b9039f78db188 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Thu, 5 Oct 2023 17:27:26 -0700 Subject: [PATCH 71/95] Add missing initialization of node_cmp_ member. --- kernel/utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/utils.h b/kernel/utils.h index 5a1279ef0..31a8681f1 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -134,7 +134,7 @@ template , typename OPS = hash_ops> cla // We use this ordering of the edges in the adjacency matrix for // exact compatibility with an older implementation. struct IndirectCmp { - IndirectCmp(const std::vector &nodes) : nodes_(nodes) {} + IndirectCmp(const std::vector &nodes) : node_cmp_(), nodes_(nodes) {} bool operator()(int a, int b) const { log_assert(static_cast(a) < nodes_.size()); From 8367f06188edf750b32bd603552ba9d75995baf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 5 Oct 2023 19:39:28 +0200 Subject: [PATCH 72/95] ast/simplify: Remove unused in_param code --- frontends/ast/simplify.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index c5f046704..2a500b56b 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1749,13 +1749,8 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin bool const_fold_here = const_fold; int width_hint_here = width_hint; bool sign_hint_here = sign_hint; - bool in_param_here = in_param; if (i == 0 && (type == AST_REPLICATE || type == AST_WIRE)) const_fold_here = true; - if (i == 0 && (type == AST_GENIF || type == AST_GENCASE)) - in_param_here = true; - if (i == 1 && (type == AST_FOR || type == AST_GENFOR)) - in_param_here = true; if (type == AST_PARAMETER || type == AST_LOCALPARAM) const_fold_here = true; if (type == AST_BLOCK) { From 2ab7d1d0c85cf128f8711075584b76738e0d9b11 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 6 Oct 2023 16:05:44 +0200 Subject: [PATCH 73/95] Fix readline/editline memory leak --- kernel/yosys.cc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 559ce872c..4409dc91d 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -1353,8 +1353,12 @@ void shell(RTLIL::Design *design) if ((command = fgets(command_buffer, 4096, stdin)) == NULL) break; #endif - if (command[strspn(command, " \t\r\n")] == 0) + if (command[strspn(command, " \t\r\n")] == 0) { +#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) + free(command); +#endif continue; + } #if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) add_history(command); #endif @@ -1376,10 +1380,17 @@ void shell(RTLIL::Design *design) log_reset_stack(); } design->check(); +#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) + if (command) + free(command); +#endif } if (command == NULL) printf("exit\n"); - +#if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) + else + free(command); +#endif recursion_counter--; log_cmd_error_throw = false; } From bc0df04e065d53f3f1e2053861a94de29eb9e013 Mon Sep 17 00:00:00 2001 From: Rasmus Munk Larsen Date: Fri, 6 Oct 2023 12:53:05 -0700 Subject: [PATCH 74/95] Get rid of double lookup in TopoSort::node(). This speeds up typical TopoSort time overall by ~10%. --- kernel/utils.h | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/kernel/utils.h b/kernel/utils.h index 31a8681f1..8fa223824 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -159,15 +159,12 @@ template , typename OPS = hash_ops> cla int node(T n) { - auto it = node_to_index.find(n); - if (it == node_to_index.end()) { - int index = static_cast(nodes.size()); - node_to_index[n] = index; - nodes.push_back(n); - edges.push_back(std::set(indirect_cmp)); - return index; + auto rv = node_to_index.emplace(n, static_cast(nodes.size())); + if (rv.second) { + nodes.push_back(n); + edges.push_back(std::set(indirect_cmp)); } - return it->second; + return rv.first->second; } void edge(int l_index, int r_index) { edges[r_index].insert(l_index); } From 51e9b0882bf099ee28ba88d6cc14be1f877f6cff Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 7 Oct 2023 00:14:44 +0000 Subject: [PATCH 75/95] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c6b5706cc..907be74af 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.34+7 +YOSYS_VER := 0.34+9 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 0ca39e233b8d7aa4736830cad383bc59214da12b Mon Sep 17 00:00:00 2001 From: Marcus Comstedt Date: Sat, 7 Oct 2023 10:43:00 +0200 Subject: [PATCH 76/95] scc: Use hashlib instead of STL for deterministic behaviour --- passes/cmds/scc.cc | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/passes/cmds/scc.cc b/passes/cmds/scc.cc index 81881832c..197bd9319 100644 --- a/passes/cmds/scc.cc +++ b/passes/cmds/scc.cc @@ -27,7 +27,6 @@ #include "kernel/log.h" #include #include -#include USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -39,18 +38,18 @@ struct SccWorker SigMap sigmap; CellTypes ct, specifyCells; - std::set workQueue; - std::map> cellToNextCell; - std::map cellToPrevSig, cellToNextSig; + pool workQueue; + dict> cellToNextCell; + dict cellToPrevSig, cellToNextSig; - std::map> cellLabels; - std::map cellDepth; - std::set cellsOnStack; + dict> cellLabels; + dict cellDepth; + pool cellsOnStack; std::vector cellStack; int labelCounter; - std::map cell2scc; - std::vector> sccList; + dict cell2scc; + std::vector> sccList; void run(RTLIL::Cell *cell, int depth, int maxDepth) { @@ -85,7 +84,7 @@ struct SccWorker else { log("Found an SCC:"); - std::set scc; + pool scc; while (cellsOnStack.count(cell) > 0) { RTLIL::Cell *c = cellStack.back(); cellStack.pop_back(); @@ -199,11 +198,11 @@ struct SccWorker for (auto cell : workQueue) { - cellToNextCell[cell] = sigToNextCells.find(cellToNextSig[cell]); + sigToNextCells.find(cellToNextSig[cell], cellToNextCell[cell]); if (!nofeedbackMode && cellToNextCell[cell].count(cell)) { log("Found an SCC:"); - std::set scc; + pool scc; log(" %s", RTLIL::id2cstr(cell->name)); cell2scc[cell] = sccList.size(); scc.insert(cell); @@ -231,7 +230,7 @@ struct SccWorker { for (int i = 0; i < int(sccList.size()); i++) { - std::set &cells = sccList[i]; + pool &cells = sccList[i]; RTLIL::SigSpec prevsig, nextsig, sig; for (auto cell : cells) { @@ -295,7 +294,7 @@ struct SccPass : public Pass { } void execute(std::vector args, RTLIL::Design *design) override { - std::map setAttr; + dict setAttr; bool allCellTypes = false; bool selectMode = false; bool nofeedbackMode = false; From c36cf9c5ac26ff6bdad8c505e0bcac677af25938 Mon Sep 17 00:00:00 2001 From: Wanda Date: Sun, 8 Oct 2023 01:11:30 +0200 Subject: [PATCH 77/95] write_verilog: avoid emitting empty cases. The Verilog grammar does not allow an empty case. Most synthesis tools are quite permissive about this, but Quartus is not. This causes problems for amaranth with Quartus (see amaranth-lang/amaranth#931). --- backends/verilog/verilog_backend.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 7099c18c3..735672a43 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -2008,6 +2008,11 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw dump_case_body(f, indent + " ", *it); } + if (sw->cases.empty()) { + // Verilog does not allow empty cases. + f << stringf("%s default: ;\n", indent.c_str()); + } + f << stringf("%s" "endcase\n", indent.c_str()); } From 11b9deba9f05a107c70f66139fc988be46567719 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 9 Oct 2023 00:15:38 +0000 Subject: [PATCH 78/95] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 907be74af..0a9a7a2c3 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.34+9 +YOSYS_VER := 0.34+14 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 4ed708836addfd406f290aa3f191bae3b471136f Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 10 Oct 2023 11:41:33 +0200 Subject: [PATCH 79/95] verific: Use CellBaseName to identify top modules --- frontends/verific/verific.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 804b6676b..716b4dc13 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -2573,7 +2573,7 @@ std::string verific_import(Design *design, const std::mapAddAtt(new Att(" \\top", NULL)); nl_todo.emplace(nl->CellBaseName(), nl); - cell_name = nl->Owner()->Name(); + cell_name = nl->CellBaseName(); } if (top.empty()) cell_name = top; @@ -2595,7 +2595,7 @@ std::string verific_import(Design *design, const std::mapfirst) == 0) { VerificImporter importer(false, false, false, false, false, false, false); nl_done[it->first] = it->second; - importer.import_netlist(design, nl, nl_todo, nl->Owner()->Name() == cell_name); + importer.import_netlist(design, nl, nl_todo, nl->CellBaseName() == cell_name); } nl_todo.erase(it); } @@ -3801,7 +3801,7 @@ struct VerificPass : public Pass { VerificImporter importer(mode_gates, mode_keep, mode_nosva, mode_names, mode_verific, mode_autocover, mode_fullinit); nl_done[it->first] = it->second; - importer.import_netlist(design, nl, nl_todo, top_mod_names.count(nl->Owner()->Name())); + importer.import_netlist(design, nl, nl_todo, top_mod_names.count(nl->CellBaseName())); } nl_todo.erase(it); } From 59fbee4009f02f807d3b60888ff5eca6670e3a7f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 12 Oct 2023 00:13:29 +0000 Subject: [PATCH 80/95] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 0a9a7a2c3..ebe988143 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.34+14 +YOSYS_VER := 0.34+23 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From d473a207a1692f6587516cc2b93d6f11aeff1d85 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 12 Oct 2023 09:17:06 +0200 Subject: [PATCH 81/95] Preserve VHDL architecture name in attribute --- frontends/verific/verific.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 716b4dc13..115a42e33 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -52,6 +52,7 @@ USING_YOSYS_NAMESPACE #ifdef VERIFIC_VHDL_SUPPORT #include "vhdl_file.h" #include "VhdlUnits.h" +#include "NameSpace.h" #endif #ifdef VERIFIC_EDIF_SUPPORT @@ -1276,6 +1277,13 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma } import_attributes(module->attributes, nl, nl); module->set_string_attribute(ID::hdlname, nl->CellBaseName()); +#ifdef VERIFIC_VHDL_SUPPORT + if (nl->IsFromVhdl()) { + NameSpace name_space(0); + char *architecture_name = name_space.ReName(nl->Name()) ; + module->set_string_attribute(ID(architecture), (architecture_name) ? architecture_name : nl->Name()); + } +#endif const char *param_name ; const char *param_value ; MapIter mi; From 62d63386886dcfec7d0087e10f52ff7c4a7796cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Thu, 12 Oct 2023 12:45:11 +0200 Subject: [PATCH 82/95] quicklogic: Fix pp3 `dffs` test Fix name confusion which was making the test look into the vendor's cell blackbox rather than into the synthesis results. --- tests/arch/quicklogic/dffs.ys | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/tests/arch/quicklogic/dffs.ys b/tests/arch/quicklogic/dffs.ys index 2e0a34540..e1fbef635 100644 --- a/tests/arch/quicklogic/dffs.ys +++ b/tests/arch/quicklogic/dffs.ys @@ -7,14 +7,27 @@ hierarchy -top my_dff proc equiv_opt -async2sync -assert -map +/quicklogic/pp3_cells_sim.v -map +/quicklogic/cells_sim.v synth_quicklogic # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) -cd dff # Constrain all select calls below inside the top module -select -assert-none t:* +cd my_dff # Constrain all select calls below inside the top module +select -assert-count 1 t:ckpad +select -assert-count 1 t:dffepc +select -assert-count 1 t:inpad +select -assert-count 1 t:logic_0 +select -assert-count 1 t:logic_1 +select -assert-count 1 t:outpad + +select -assert-none t:ckpad t:dffepc t:inpad t:logic_0 t:logic_1 t:outpad %% t:* %D design -load read hierarchy -top my_dffe proc equiv_opt -async2sync -assert -map +/quicklogic/pp3_cells_sim.v -map +/quicklogic/cells_sim.v synth_quicklogic # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) -cd dffe # Constrain all select calls below inside the top module +cd my_dffe # Constrain all select calls below inside the top module -select -assert-none t:* \ No newline at end of file +select -assert-count 1 t:ckpad +select -assert-count 1 t:dffepc +select -assert-count 2 t:inpad +select -assert-count 1 t:logic_0 +select -assert-count 1 t:outpad + +select -assert-none t:ckpad t:dffepc t:inpad t:logic_0 t:outpad %% t:* %D From 69c252f2476e01f2ea95ecb2b2f218568638f370 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 13 Oct 2023 14:32:11 +0200 Subject: [PATCH 83/95] Update abc --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ebe988143..6274e71a3 100644 --- a/Makefile +++ b/Makefile @@ -165,7 +165,7 @@ bumpversion: # is just a symlink to your actual ABC working directory, as 'make mrproper' # will remove the 'abc' directory and you do not want to accidentally # delete your work on ABC.. -ABCREV = daad9ed +ABCREV = 896e5e7 ABCPULL = 1 ABCURL ?= https://github.com/YosysHQ/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) From 7d30f716e82ff4782b653cb2c448062f7878c308 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 14 Oct 2023 00:14:36 +0000 Subject: [PATCH 84/95] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 6274e71a3..c75bb0c66 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.34+23 +YOSYS_VER := 0.34+27 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From a0c3be3aaeb2bbb87161432748aa349712e35dc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 2 Aug 2023 13:52:40 +0200 Subject: [PATCH 85/95] peepopt: Drop unused 'initbits' code Drop code that was once used by the 'dffmux' pattern but now is unused after that pattern has been obsoleted by the 'opt_dff' pass. --- passes/pmgen/peepopt.cc | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index 9a497c914..1d27d77a0 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -24,8 +24,6 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN bool did_something; -dict initbits; -pool rminitbits; #include "passes/pmgen/peepopt_pm.h" #include "generate.h" @@ -60,9 +58,6 @@ struct PeepoptPass : public Pass { if (!genmode.empty()) { - initbits.clear(); - rminitbits.clear(); - if (genmode == "shiftmul") GENERATE_PATTERN(peepopt_pm, shiftmul); else if (genmode == "muldiv") @@ -79,47 +74,13 @@ struct PeepoptPass : public Pass { while (did_something) { did_something = false; - initbits.clear(); - rminitbits.clear(); peepopt_pm pm(module); - for (auto w : module->wires()) { - auto it = w->attributes.find(ID::init); - if (it != w->attributes.end()) { - SigSpec sig = pm.sigmap(w); - Const val = it->second; - int len = std::min(GetSize(sig), GetSize(val)); - for (int i = 0; i < len; i++) { - if (sig[i].wire == nullptr) - continue; - if (val[i] != State::S0 && val[i] != State::S1) - continue; - initbits[sig[i]] = val[i]; - } - } - } - pm.setup(module->selected_cells()); pm.run_shiftmul(); pm.run_muldiv(); - - for (auto w : module->wires()) { - auto it = w->attributes.find(ID::init); - if (it != w->attributes.end()) { - SigSpec sig = pm.sigmap(w); - Const &val = it->second; - int len = std::min(GetSize(sig), GetSize(val)); - for (int i = 0; i < len; i++) { - if (rminitbits.count(sig[i])) - val[i] = State::Sx; - } - } - } - - initbits.clear(); - rminitbits.clear(); } } } From bd8a81a907f0307254387a2b74aa1d1ebc582505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 2 Aug 2023 15:44:41 +0200 Subject: [PATCH 86/95] peepopt: Clean up 'shiftmul' a bit No functional change intended. --- passes/pmgen/peepopt_shiftmul.pmg | 66 +++++++++++++++++-------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/passes/pmgen/peepopt_shiftmul.pmg b/passes/pmgen/peepopt_shiftmul.pmg index d71fbf744..92e902d3e 100644 --- a/passes/pmgen/peepopt_shiftmul.pmg +++ b/passes/pmgen/peepopt_shiftmul.pmg @@ -3,61 +3,67 @@ pattern shiftmul // Optimize mul+shift pairs that result from expressions such as foo[s*W+:W] // -state shamt - match shift select shift->type.in($shift, $shiftx, $shr) + filter !port(shift, \B).empty() 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()) { +state shift_amount + +code shift_amount + shift_amount = port(shift, \B); + if (shift->type.in($shr) || !param(shift, \B_SIGNED).as_bool()) + shift_amount.append(State::S0); + + // at this point shift_amount is signed, make + // sure we can never go negative + if (shift_amount.bits().back() != State::S0) reject; + + while (shift_amount.bits().back() == State::S0) { + shift_amount.remove(GetSize(shift_amount) - 1); + if (shift_amount.empty()) reject; } - if (GetSize(shamt) > 20) + + if (GetSize(shift_amount) > 20) reject; endcode +state mul_din +state mul_const + match mul select mul->type.in($mul) - select port(mul, \A).is_fully_const() || port(mul, \B).is_fully_const() - index port(mul, \Y) === shamt + index port(mul, \Y) === shift_amount filter !param(mul, \A_SIGNED).as_bool() + + choice constport {\A, \B} + filter port(mul, constport).is_fully_const() + + define varport (constport == \A ? \B : \A) + set mul_const port(mul, constport).as_const() + set mul_din port(mul, varport) endmatch code { - IdString const_factor_port = port(mul, \A).is_fully_const() ? \A : \B; - 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) + if (mul_const.empty() || GetSize(mul_const) > 20) reject; - if (GetSize(const_factor_cnst) > 20) + // make sure there's no overlap in the signal + // selections by the shiftmul pattern + if (GetSize(port(shift, \Y)) > mul_const.as_int()) reject; - if (GetSize(port(shift, \Y)) > const_factor) - reject; - - int factor_bits = ceil_log2(const_factor); - SigSpec mul_din = port(mul, const_factor_port == \A ? \B : \A); - - if (GetSize(shamt) < factor_bits+GetSize(mul_din)) + int factor_bits = ceil_log2(mul_const.as_int()); + // make sure the multiplication never wraps around + if (GetSize(shift_amount) < factor_bits + GetSize(mul_din)) reject; did_something = true; log("shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul)); + int const_factor = mul_const.as_int(); int new_const_factor = 1 << factor_bits; SigSpec padding(State::Sx, new_const_factor-const_factor); SigSpec old_a = port(shift, \A), new_a; From dd1a8ae49a54b00407afef92f5dac1b36e7efefa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 2 Aug 2023 15:46:50 +0200 Subject: [PATCH 87/95] peepopt: Try to use original wires --- passes/pmgen/peepopt_shiftmul.pmg | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/passes/pmgen/peepopt_shiftmul.pmg b/passes/pmgen/peepopt_shiftmul.pmg index 92e902d3e..177d97371 100644 --- a/passes/pmgen/peepopt_shiftmul.pmg +++ b/passes/pmgen/peepopt_shiftmul.pmg @@ -42,7 +42,11 @@ match mul define varport (constport == \A ? \B : \A) set mul_const port(mul, constport).as_const() - set mul_din port(mul, varport) + // get mul_din unmapped (so no `port()` shorthand) + // because we will be using it to set the \A port + // on the shift cell, and we want to stay close + // to the original design + set mul_din mul->getPort(varport) endmatch code From 038a5e1ed4d31a1ad1fde63971939abd8885fe2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 2 Aug 2023 16:10:27 +0200 Subject: [PATCH 88/95] peepopt: Support shift amounts zero-padded from below The `opt_expr` pass running before `peepopt` can interfere with the detection of a shiftmul pattern due to some of the bottom bits of the shift amount being replaced with constant zero. Extend the detection to cover those situations as well. --- passes/pmgen/peepopt_shiftmul.pmg | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/passes/pmgen/peepopt_shiftmul.pmg b/passes/pmgen/peepopt_shiftmul.pmg index 177d97371..4808430b4 100644 --- a/passes/pmgen/peepopt_shiftmul.pmg +++ b/passes/pmgen/peepopt_shiftmul.pmg @@ -8,9 +8,13 @@ match shift filter !port(shift, \B).empty() endmatch +// the right shift amount state shift_amount +// log2 scale factor in interpreting of shift_amount +// due to zero padding on the shift cell's B port +state log2scale -code shift_amount +code shift_amount log2scale shift_amount = port(shift, \B); if (shift->type.in($shr) || !param(shift, \B_SIGNED).as_bool()) shift_amount.append(State::S0); @@ -25,6 +29,13 @@ code shift_amount if (shift_amount.empty()) reject; } + log2scale = 0; + while (shift_amount[0] == State::S0) { + shift_amount.remove(0); + if (shift_amount.empty()) reject; + log2scale++; + } + if (GetSize(shift_amount) > 20) reject; endcode @@ -41,7 +52,7 @@ match mul filter port(mul, constport).is_fully_const() define varport (constport == \A ? \B : \A) - set mul_const port(mul, constport).as_const() + set mul_const SigSpec({port(mul, constport), SigSpec(State::S0, log2scale)}).as_const() // get mul_din unmapped (so no `port()` shorthand) // because we will be using it to set the \A port // on the shift cell, and we want to stay close @@ -61,7 +72,7 @@ code int factor_bits = ceil_log2(mul_const.as_int()); // make sure the multiplication never wraps around - if (GetSize(shift_amount) < factor_bits + GetSize(mul_din)) + if (GetSize(shift_amount) + log2scale < factor_bits + GetSize(mul_din)) reject; did_something = true; From aa9b86aeec1b1b2ea2d3344098963300b4f624f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Wed, 2 Aug 2023 18:04:54 +0200 Subject: [PATCH 89/95] peepopt: Add left-shift 'shiftmul' variant Add a separate shiftmul pattern to match on left shifts which implement demuxing. This mirrors the right shift pattern matcher but is probably best kept separate instead of merging the two into a single matcher. In any case the diff of the two matchers should be easily readable. --- passes/pmgen/Makefile.inc | 3 +- passes/pmgen/peepopt.cc | 5 +- passes/pmgen/peepopt_shiftmul_left.pmg | 160 ++++++++++++++++++ ...hiftmul.pmg => peepopt_shiftmul_right.pmg} | 4 +- 4 files changed, 167 insertions(+), 5 deletions(-) create mode 100644 passes/pmgen/peepopt_shiftmul_left.pmg rename passes/pmgen/{peepopt_shiftmul.pmg => peepopt_shiftmul_right.pmg} (95%) diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index a7ef64282..c2257b720 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -42,7 +42,8 @@ GENFILES += passes/pmgen/peepopt_pm.h passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h $(eval $(call add_extra_objs,passes/pmgen/peepopt_pm.h)) -PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul.pmg +PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul_right.pmg +PEEPOPT_PATTERN += passes/pmgen/peepopt_shiftmul_left.pmg PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN) diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index 1d27d77a0..2b225623d 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -59,7 +59,7 @@ struct PeepoptPass : public Pass { if (!genmode.empty()) { if (genmode == "shiftmul") - GENERATE_PATTERN(peepopt_pm, shiftmul); + GENERATE_PATTERN(peepopt_pm, shiftmul_right); else if (genmode == "muldiv") GENERATE_PATTERN(peepopt_pm, muldiv); else @@ -79,7 +79,8 @@ struct PeepoptPass : public Pass { pm.setup(module->selected_cells()); - pm.run_shiftmul(); + pm.run_shiftmul_right(); + pm.run_shiftmul_left(); pm.run_muldiv(); } } diff --git a/passes/pmgen/peepopt_shiftmul_left.pmg b/passes/pmgen/peepopt_shiftmul_left.pmg new file mode 100644 index 000000000..607f8368c --- /dev/null +++ b/passes/pmgen/peepopt_shiftmul_left.pmg @@ -0,0 +1,160 @@ +pattern shiftmul_left +// +// Optimize mul+shift pairs that result from expressions such as foo[s*W+:W] +// + +match shift + select shift->type.in($shift, $shiftx, $shl) + select shift->type.in($shl) || param(shift, \B_SIGNED).as_bool() + filter !port(shift, \B).empty() +endmatch + +match neg + if shift->type.in($shift, $shiftx) + select neg->type == $neg + index port(neg, \Y) === port(shift, \B) + filter !port(shift, \A).empty() +endmatch + +// the left shift amount +state shift_amount +// log2 scale factor in interpreting of shift_amount +// due to zero padding on the shift cell's B port +state log2scale + +code shift_amount log2scale + if (neg) { + // case of `$shift`, `$shiftx` + shift_amount = port(neg, \A); + if (!param(neg, \A_SIGNED).as_bool()) + shift_amount.append(State::S0); + } else { + // case of `$shl` + shift_amount = port(shift, \B); + if (!param(shift, \B_SIGNED).as_bool()) + shift_amount.append(State::S0); + } + + // at this point shift_amount is signed, make + // sure we can never go negative + if (shift_amount.bits().back() != State::S0) + reject; + + while (shift_amount.bits().back() == State::S0) { + shift_amount.remove(GetSize(shift_amount) - 1); + if (shift_amount.empty()) reject; + } + + log2scale = 0; + while (shift_amount[0] == State::S0) { + shift_amount.remove(0); + if (shift_amount.empty()) reject; + log2scale++; + } + + if (GetSize(shift_amount) > 20) + reject; +endcode + +state mul_din +state mul_const + +match mul + select mul->type.in($mul) + index port(mul, \Y) === shift_amount + filter !param(mul, \A_SIGNED).as_bool() + + choice constport {\A, \B} + filter port(mul, constport).is_fully_const() + + define varport (constport == \A ? \B : \A) + set mul_const SigSpec({port(mul, constport), SigSpec(State::S0, log2scale)}).as_const() + // get mul_din unmapped (so no `port()` shorthand) + // because we will be using it to set the \A port + // on the shift cell, and we want to stay close + // to the original design + set mul_din mul->getPort(varport) +endmatch + +code +{ + if (mul_const.empty() || GetSize(mul_const) > 20) + reject; + + // make sure there's no overlap in the signal + // selections by the shiftmul pattern + if (GetSize(port(shift, \A)) > mul_const.as_int()) + reject; + + int factor_bits = ceil_log2(mul_const.as_int()); + // make sure the multiplication never wraps around + if (GetSize(shift_amount) < factor_bits + GetSize(mul_din)) + reject; + + if (neg) { + // make sure the negation never wraps around + if (GetSize(port(shift, \B)) < factor_bits + GetSize(mul_din) + + log2scale + 1) + reject; + } + + did_something = true; + log("left shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul)); + + int const_factor = mul_const.as_int(); + int new_const_factor = 1 << factor_bits; + SigSpec padding(State::Sm, new_const_factor-const_factor); + SigSpec old_y = port(shift, \Y), new_y; + int trunc = 0; + + if (GetSize(old_y) % const_factor != 0) { + trunc = const_factor - GetSize(old_y) % const_factor; + old_y.append(SigSpec(State::Sm, trunc)); + } + + for (int i = 0; i*const_factor < GetSize(old_y); i++) { + SigSpec slice = old_y.extract(i*const_factor, const_factor); + new_y.append(slice); + new_y.append(padding); + } + + if (trunc > 0) + new_y.remove(GetSize(new_y)-trunc, trunc); + + { + // Now replace occurences of Sm in new_y with bits + // of a dummy wire + int padbits = 0; + for (auto bit : new_y) + if (bit == SigBit(State::Sm)) + padbits++; + + SigSpec padwire = module->addWire(NEW_ID, padbits); + + for (int i = new_y.size() - 1; i >= 0; i--) + if (new_y[i] == SigBit(State::Sm)) { + new_y[i] = padwire.bits().back(); + padwire.remove(padwire.size() - 1); + } + } + + SigSpec new_b = {mul_din, SigSpec(State::S0, factor_bits)}; + + shift->setPort(\Y, new_y); + shift->setParam(\Y_WIDTH, GetSize(new_y)); + if (shift->type == $shl) { + if (param(shift, \B_SIGNED).as_bool()) + new_b.append(State::S0); + shift->setPort(\B, new_b); + shift->setParam(\B_WIDTH, GetSize(new_b)); + } else { + SigSpec b_neg = module->addWire(NEW_ID, GetSize(new_b) + 1); + module->addNeg(NEW_ID, new_b, b_neg); + shift->setPort(\B, b_neg); + shift->setParam(\B_WIDTH, GetSize(b_neg)); + } + + blacklist(shift); + accept; +} +endcode diff --git a/passes/pmgen/peepopt_shiftmul.pmg b/passes/pmgen/peepopt_shiftmul_right.pmg similarity index 95% rename from passes/pmgen/peepopt_shiftmul.pmg rename to passes/pmgen/peepopt_shiftmul_right.pmg index 4808430b4..71e098023 100644 --- a/passes/pmgen/peepopt_shiftmul.pmg +++ b/passes/pmgen/peepopt_shiftmul_right.pmg @@ -1,4 +1,4 @@ -pattern shiftmul +pattern shiftmul_right // // Optimize mul+shift pairs that result from expressions such as foo[s*W+:W] // @@ -76,7 +76,7 @@ code reject; did_something = true; - log("shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul)); + log("right shiftmul pattern in %s: shift=%s, mul=%s\n", log_id(module), log_id(shift), log_id(mul)); int const_factor = mul_const.as_int(); int new_const_factor = 1 << factor_bits; From 5c0c8251c38f103aa63e5cf1e689c64803ba7e16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 16 Oct 2023 13:54:17 +0200 Subject: [PATCH 90/95] peepopt: Remove broken `-generate` option --- passes/pmgen/peepopt.cc | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index 2b225623d..f03495254 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -26,7 +26,6 @@ PRIVATE_NAMESPACE_BEGIN bool did_something; #include "passes/pmgen/peepopt_pm.h" -#include "generate.h" struct PeepoptPass : public Pass { PeepoptPass() : Pass("peepopt", "collection of peephole optimizers") { } @@ -41,32 +40,15 @@ struct PeepoptPass : public Pass { } void execute(std::vector args, RTLIL::Design *design) override { - std::string genmode; - log_header(design, "Executing PEEPOPT pass (run peephole optimizers).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - if (args[argidx] == "-generate" && argidx+1 < args.size()) { - genmode = args[++argidx]; - continue; - } break; } extra_args(args, argidx, design); - if (!genmode.empty()) - { - if (genmode == "shiftmul") - GENERATE_PATTERN(peepopt_pm, shiftmul_right); - else if (genmode == "muldiv") - GENERATE_PATTERN(peepopt_pm, muldiv); - else - log_abort(); - return; - } - for (auto module : design->selected_modules()) { did_something = true; From 660be4a31e58f7d348fea9b3fe41553ac061f26a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 16 Oct 2023 14:08:42 +0200 Subject: [PATCH 91/95] peepopt: Describe rules in help message --- passes/pmgen/peepopt.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc index f03495254..aef464d79 100644 --- a/passes/pmgen/peepopt.cc +++ b/passes/pmgen/peepopt.cc @@ -37,6 +37,17 @@ struct PeepoptPass : public Pass { log("\n"); log("This pass applies a collection of peephole optimizers to the current design.\n"); log("\n"); + log("This pass employs the following rules:\n"); + log("\n"); + log(" * muldiv - Replace (A*B)/B with A\n"); + log("\n"); + log(" * shiftmul - Replace A>>(B*C) with A'>>(B< args, RTLIL::Design *design) override { From d6d1cc705e524264361bfc16f7a2ef5a96b0b717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 16 Oct 2023 14:16:36 +0200 Subject: [PATCH 92/95] pmgen: Fix sample syntax --- passes/pmgen/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/pmgen/README.md b/passes/pmgen/README.md index 39560839f..3205be1b5 100644 --- a/passes/pmgen/README.md +++ b/passes/pmgen/README.md @@ -212,7 +212,7 @@ second argument, and the matcher will iterate over those options: index port(eq, BA) === bar set eq_ab AB set eq_ba BA - generate + endmatch Notice how `define` can be used to define additional local variables similar to the loop variables defined by `slice` and `choice`. From a5c04dd72e3d02d36dadf1c60ae76bb149969970 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 17 Oct 2023 00:15:28 +0000 Subject: [PATCH 93/95] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c75bb0c66..b89c87ae9 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.34+27 +YOSYS_VER := 0.34+43 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo From 6ffc3159360d8d7992af02cbc483718dd07c812e Mon Sep 17 00:00:00 2001 From: Catherine Date: Mon, 9 Oct 2023 11:45:12 +0000 Subject: [PATCH 94/95] cxxrtl: export wire attributes through the C API. Co-authored-by: Charlotte --- backends/cxxrtl/cxxrtl.h | 46 +++++++++++++--- backends/cxxrtl/cxxrtl_backend.cc | 91 ++++++++++++++++++++----------- backends/cxxrtl/cxxrtl_capi.cc | 43 +++++++++++++++ backends/cxxrtl/cxxrtl_capi.h | 65 ++++++++++++++++++++++ 4 files changed, 206 insertions(+), 39 deletions(-) diff --git a/backends/cxxrtl/cxxrtl.h b/backends/cxxrtl/cxxrtl.h index 8f5e4035a..b2871ee19 100644 --- a/backends/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/cxxrtl.h @@ -1019,14 +1019,14 @@ struct metadata { // In debug mode, using the wrong .as_*() function will assert. // In release mode, using the wrong .as_*() function will safely return a default value. - const unsigned uint_value = 0; - const signed sint_value = 0; + const uint64_t uint_value = 0; + const int64_t sint_value = 0; const std::string string_value = ""; const double double_value = 0.0; metadata() : value_type(MISSING) {} - metadata(unsigned value) : value_type(UINT), uint_value(value) {} - metadata(signed value) : value_type(SINT), sint_value(value) {} + metadata(uint64_t value) : value_type(UINT), uint_value(value) {} + metadata(int64_t value) : value_type(SINT), sint_value(value) {} metadata(const std::string &value) : value_type(STRING), string_value(value) {} metadata(const char *value) : value_type(STRING), string_value(value) {} metadata(double value) : value_type(DOUBLE), double_value(value) {} @@ -1034,12 +1034,12 @@ struct metadata { metadata(const metadata &) = default; metadata &operator=(const metadata &) = delete; - unsigned as_uint() const { + uint64_t as_uint() const { assert(value_type == UINT); return uint_value; } - signed as_sint() const { + int64_t as_sint() const { assert(value_type == SINT); return sint_value; } @@ -1068,6 +1068,9 @@ using debug_outline = ::_cxxrtl_outline; // // To avoid violating strict aliasing rules, this structure has to be a subclass of the one used // in the C API, or it would not be possible to cast between the pointers to these. +// +// The `attrs` member cannot be owned by this structure because a `cxxrtl_object` can be created +// from external C code. struct debug_item : ::cxxrtl_object { // Object types. enum : uint32_t { @@ -1103,6 +1106,7 @@ struct debug_item : ::cxxrtl_object { curr = item.data; next = item.data; outline = nullptr; + attrs = nullptr; } template @@ -1118,6 +1122,7 @@ struct debug_item : ::cxxrtl_object { curr = const_cast(item.data); next = nullptr; outline = nullptr; + attrs = nullptr; } template @@ -1134,6 +1139,7 @@ struct debug_item : ::cxxrtl_object { curr = item.curr.data; next = item.next.data; outline = nullptr; + attrs = nullptr; } template @@ -1149,6 +1155,7 @@ struct debug_item : ::cxxrtl_object { curr = item.data ? item.data[0].data : nullptr; next = nullptr; outline = nullptr; + attrs = nullptr; } template @@ -1164,6 +1171,7 @@ struct debug_item : ::cxxrtl_object { curr = const_cast(item.data); next = nullptr; outline = nullptr; + attrs = nullptr; } template @@ -1180,6 +1188,7 @@ struct debug_item : ::cxxrtl_object { curr = const_cast(item.curr.data); next = nullptr; outline = nullptr; + attrs = nullptr; } template @@ -1195,6 +1204,7 @@ struct debug_item : ::cxxrtl_object { curr = const_cast(item.data); next = nullptr; outline = &group; + attrs = nullptr; } template @@ -1215,10 +1225,28 @@ struct debug_item : ::cxxrtl_object { }; static_assert(std::is_standard_layout::value, "debug_item is not compatible with C layout"); +} // namespace cxxrtl + +typedef struct _cxxrtl_attr_set { + cxxrtl::metadata_map map; +} *cxxrtl_attr_set; + +namespace cxxrtl { + +// Representation of an attribute set in the C++ interface. +using debug_attrs = ::_cxxrtl_attr_set; + struct debug_items { std::map> table; + std::map> attrs_table; - void add(const std::string &name, debug_item &&item) { + void add(const std::string &name, debug_item &&item, metadata_map &&item_attrs = {}) { + std::unique_ptr &attrs = attrs_table[name]; + if (attrs.get() == nullptr) + attrs = std::unique_ptr(new debug_attrs); + for (auto attr : item_attrs) + attrs->map.insert(attr); + item.attrs = attrs.get(); std::vector &parts = table[name]; parts.emplace_back(item); std::sort(parts.begin(), parts.end(), @@ -1246,6 +1274,10 @@ struct debug_items { const debug_item &operator [](const std::string &name) const { return at(name); } + + const metadata_map &attrs(const std::string &name) const { + return attrs_table.at(name)->map; + } }; // Tag class to disambiguate the default constructor used by the toplevel module that calls reset(), diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index 7696ae574..3fd4857bd 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -2120,6 +2120,46 @@ struct CxxrtlWorker { dec_indent(); } + void dump_metadata_map(const dict &metadata_map) + { + if (metadata_map.empty()) { + f << "metadata_map()"; + return; + } + f << "metadata_map({\n"; + inc_indent(); + for (auto metadata_item : metadata_map) { + if (!metadata_item.first.isPublic()) + continue; + if (metadata_item.second.size() > 64 && (metadata_item.second.flags & RTLIL::CONST_FLAG_STRING) == 0) { + f << indent << "/* attribute " << metadata_item.first.str().substr(1) << " is over 64 bits wide */"; + continue; + } + f << indent << "{ " << escape_cxx_string(metadata_item.first.str().substr(1)) << ", "; + // In Yosys, a real is a type of string. + if (metadata_item.second.flags & RTLIL::CONST_FLAG_REAL) { + f << std::showpoint << std::stod(metadata_item.second.decode_string()) << std::noshowpoint; + } else if (metadata_item.second.flags & RTLIL::CONST_FLAG_STRING) { + f << escape_cxx_string(metadata_item.second.decode_string()); + } else if (metadata_item.second.flags & RTLIL::CONST_FLAG_SIGNED) { + f << "INT64_C(" << metadata_item.second.as_int(/*is_signed=*/true) << ")"; + } else { + f << "UINT64_C(" << metadata_item.second.as_int(/*is_signed=*/false) << ")"; + } + f << " },\n"; + } + dec_indent(); + f << indent << "})"; + } + + void dump_debug_attrs(const RTLIL::AttrObject *object) + { + dict attributes = object->attributes; + // Inherently necessary to get access to the object, so a waste of space to emit. + attributes.erase(ID::hdlname); + dump_metadata_map(attributes); + } + void dump_debug_info_method(RTLIL::Module *module) { size_t count_public_wires = 0; @@ -2205,7 +2245,9 @@ struct CxxrtlWorker { } f << "debug_item::" << flag; } - f << "));\n"; + f << "), "; + dump_debug_attrs(wire); + f << ");\n"; count_member_wires++; break; } @@ -2220,7 +2262,9 @@ struct CxxrtlWorker { f << "debug_eval_outline"; else f << "debug_alias()"; - f << ", " << mangle(aliasee) << ", " << wire->start_offset << "));\n"; + f << ", " << mangle(aliasee) << ", " << wire->start_offset << "), "; + dump_debug_attrs(aliasee); + f << ");\n"; count_alias_wires++; break; } @@ -2230,14 +2274,18 @@ struct CxxrtlWorker { dump_const(debug_wire_type.sig_subst.as_const()); f << ";\n"; f << indent << "items.add(path + " << escape_cxx_string(get_hdl_name(wire)); - f << ", debug_item(const_" << mangle(wire) << ", " << wire->start_offset << "));\n"; + f << ", debug_item(const_" << mangle(wire) << ", " << wire->start_offset << "), "; + dump_debug_attrs(wire); + f << ");\n"; count_const_wires++; break; } case WireType::OUTLINE: { // Localized or inlined, but rematerializable wire f << indent << "items.add(path + " << escape_cxx_string(get_hdl_name(wire)); - f << ", debug_item(debug_eval_outline, " << mangle(wire) << ", " << wire->start_offset << "));\n"; + f << ", debug_item(debug_eval_outline, " << mangle(wire) << ", " << wire->start_offset << "), "; + dump_debug_attrs(wire); + f << ");\n"; count_inline_wires++; break; } @@ -2254,7 +2302,13 @@ struct CxxrtlWorker { continue; f << indent << "items.add(path + " << escape_cxx_string(mem.packed ? get_hdl_name(mem.cell) : get_hdl_name(mem.mem)); f << ", debug_item(" << mangle(&mem) << ", "; - f << mem.start_offset << "));\n"; + f << mem.start_offset << "), "; + if (mem.packed) { + dump_debug_attrs(mem.cell); + } else { + dump_debug_attrs(mem.mem); + } + f << ");\n"; } for (auto cell : module->cells()) { if (is_internal_cell(cell->type)) @@ -2282,33 +2336,6 @@ struct CxxrtlWorker { } } - void dump_metadata_map(const dict &metadata_map) - { - if (metadata_map.empty()) { - f << "metadata_map()"; - return; - } - f << "metadata_map({\n"; - inc_indent(); - for (auto metadata_item : metadata_map) { - if (!metadata_item.first.begins_with("\\")) - continue; - f << indent << "{ " << escape_cxx_string(metadata_item.first.str().substr(1)) << ", "; - if (metadata_item.second.flags & RTLIL::CONST_FLAG_REAL) { - f << std::showpoint << std::stod(metadata_item.second.decode_string()) << std::noshowpoint; - } else if (metadata_item.second.flags & RTLIL::CONST_FLAG_STRING) { - f << escape_cxx_string(metadata_item.second.decode_string()); - } else { - f << metadata_item.second.as_int(/*is_signed=*/metadata_item.second.flags & RTLIL::CONST_FLAG_SIGNED); - if (!(metadata_item.second.flags & RTLIL::CONST_FLAG_SIGNED)) - f << "u"; - } - f << " },\n"; - } - dec_indent(); - f << indent << "})"; - } - void dump_module_intf(RTLIL::Module *module) { dump_attrs(module); diff --git a/backends/cxxrtl/cxxrtl_capi.cc b/backends/cxxrtl/cxxrtl_capi.cc index 227173ba8..d50ddcd69 100644 --- a/backends/cxxrtl/cxxrtl_capi.cc +++ b/backends/cxxrtl/cxxrtl_capi.cc @@ -90,3 +90,46 @@ void cxxrtl_enum(cxxrtl_handle handle, void *data, void cxxrtl_outline_eval(cxxrtl_outline outline) { outline->eval(); } + +int cxxrtl_attr_type(cxxrtl_attr_set attrs_, const char *name) { + auto attrs = (cxxrtl::metadata_map*)attrs_; + if (!attrs->count(name)) + return CXXRTL_ATTR_NONE; + switch (attrs->at(name).value_type) { + case cxxrtl::metadata::UINT: + return CXXRTL_ATTR_UNSIGNED_INT; + case cxxrtl::metadata::SINT: + return CXXRTL_ATTR_SIGNED_INT; + case cxxrtl::metadata::STRING: + return CXXRTL_ATTR_STRING; + case cxxrtl::metadata::DOUBLE: + return CXXRTL_ATTR_DOUBLE; + default: + // Present unsupported attribute type the same way as no attribute at all. + return CXXRTL_ATTR_NONE; + } +} + +uint64_t cxxrtl_attr_get_unsigned_int(cxxrtl_attr_set attrs_, const char *name) { + auto &attrs = *(cxxrtl::metadata_map*)attrs_; + assert(attrs.count(name) && attrs.at(name).value_type == cxxrtl::metadata::UINT); + return attrs[name].as_uint(); +} + +int64_t cxxrtl_attr_get_signed_int(cxxrtl_attr_set attrs_, const char *name) { + auto &attrs = *(cxxrtl::metadata_map*)attrs_; + assert(attrs.count(name) && attrs.at(name).value_type == cxxrtl::metadata::SINT); + return attrs[name].as_sint(); +} + +const char *cxxrtl_attr_get_string(cxxrtl_attr_set attrs_, const char *name) { + auto &attrs = *(cxxrtl::metadata_map*)attrs_; + assert(attrs.count(name) && attrs.at(name).value_type == cxxrtl::metadata::STRING); + return attrs[name].as_string().c_str(); +} + +double cxxrtl_attr_get_double(cxxrtl_attr_set attrs_, const char *name) { + auto &attrs = *(cxxrtl::metadata_map*)attrs_; + assert(attrs.count(name) && attrs.at(name).value_type == cxxrtl::metadata::DOUBLE); + return attrs[name].as_double(); +} diff --git a/backends/cxxrtl/cxxrtl_capi.h b/backends/cxxrtl/cxxrtl_capi.h index 2df2b7287..e5c84bf65 100644 --- a/backends/cxxrtl/cxxrtl_capi.h +++ b/backends/cxxrtl/cxxrtl_capi.h @@ -249,6 +249,15 @@ struct cxxrtl_object { // this field to NULL. struct _cxxrtl_outline *outline; + // Opaque reference to an attribute set. + // + // See the documentation of `cxxrtl_attr_set` for details. When creating a `cxxrtl_object`, set + // this field to NULL. + // + // The lifetime of the pointers returned by `cxxrtl_attr_*` family of functions is the same as + // the lifetime of this structure. + struct _cxxrtl_attr_set *attrs; + // More description fields may be added in the future, but the existing ones will never change. }; @@ -304,6 +313,62 @@ typedef struct _cxxrtl_outline *cxxrtl_outline; // re-evaluated, otherwise the bits read from that object are meaningless. void cxxrtl_outline_eval(cxxrtl_outline outline); +// Opaque reference to an attribute set. +// +// An attribute set is a map between attribute names (always strings) and values (which may have +// several different types). To find out the type of an attribute, use `cxxrtl_attr_type`, and +// to retrieve the value of an attribute, use `cxxrtl_attr_as_string`. +typedef struct _cxxrtl_attr_set *cxxrtl_attr_set; + +// Type of an attribute. +enum cxxrtl_attr_type { + // Attribute is not present. + CXXRTL_ATTR_NONE = 0, + + // Attribute has an unsigned integer value. + CXXRTL_ATTR_UNSIGNED_INT = 1, + + // Attribute has an unsigned integer value. + CXXRTL_ATTR_SIGNED_INT = 2, + + // Attribute has a string value. + CXXRTL_ATTR_STRING = 3, + + // Attribute has a double precision floating point value. + CXXRTL_ATTR_DOUBLE = 4, + + // More attribute types may be defined in the future, but the existing values will never change. +}; + +// Determine the presence and type of an attribute in an attribute set. +// +// This function returns one of the possible `cxxrtl_attr_type` values. +int cxxrtl_attr_type(cxxrtl_attr_set attrs, const char *name); + +// Retrieve an unsigned integer valued attribute from an attribute set. +// +// This function asserts that `cxxrtl_attr_type(attrs, name) == CXXRTL_ATTR_UNSIGNED_INT`. +// If assertions are disabled, returns 0 if the attribute is missing or has an incorrect type. +uint64_t cxxrtl_attr_get_unsigned_int(cxxrtl_attr_set attrs, const char *name); + +// Retrieve a signed integer valued attribute from an attribute set. +// +// This function asserts that `cxxrtl_attr_type(attrs, name) == CXXRTL_ATTR_SIGNED_INT`. +// If assertions are disabled, returns 0 if the attribute is missing or has an incorrect type. +int64_t cxxrtl_attr_get_signed_int(cxxrtl_attr_set attrs, const char *name); + +// Retrieve a string valued attribute from an attribute set. The returned string is zero-terminated. +// +// This function asserts that `cxxrtl_attr_type(attrs, name) == CXXRTL_ATTR_STRING`. If assertions +// are disabled, returns NULL if the attribute is missing or has an incorrect type. +const char *cxxrtl_attr_get_string(cxxrtl_attr_set attrs, const char *name); + +// Retrieve a double precision floating point valued attribute from an attribute set. +// +// This function asserts that `cxxrtl_attr_type(attrs, name) == CXXRTL_ATTR_DOUBLE`. If assertions +// are disabled, returns NULL if the attribute is missing or has an incorrect type. +double cxxrtl_attr_get_double(cxxrtl_attr_set attrs, const char *name); + #ifdef __cplusplus } #endif From 672375ed02be68733856e616a5f4fbf281fe7733 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 26 Oct 2023 00:14:46 +0000 Subject: [PATCH 95/95] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b89c87ae9..670d44d32 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.34+43 +YOSYS_VER := 0.34+55 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo