From 39fa1e160d4af42aa6d186e8e684ea1cafdc2391 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 15 May 2020 14:05:28 -0700 Subject: [PATCH 001/287] verific: rewrite initial assume/asserts prior to elaboration --- frontends/verific/verific.cc | 53 ++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 5f8a78e4839..ae0970aac58 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -48,6 +48,7 @@ USING_YOSYS_NAMESPACE #include "VeriWrite.h" #include "VhdlUnits.h" #include "VeriLibrary.h" +#include "VeriExtensions.h" #ifndef SYMBIOTIC_VERIFIC_API_VERSION # error "Only Symbiotic EDA flavored Verific is supported. Please contact office@symbioticeda.com for commercial support for Yosys+Verific." @@ -1450,6 +1451,16 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se continue; } + if (inst->Type() == PRIM_SEDA_INITSTATE) + { + SigBit initstate = module->Initstate(new_verific_id(inst)); + SigBit sig_o = net_map_at(inst->GetOutput()); + module->connect(sig_o, initstate); + + if (!mode_keep) + continue; + } + if (!mode_keep && verific_sva_prims.count(inst->Type())) { if (verific_verbose) log(" skipping SVA cell in non k-mode\n"); @@ -1927,6 +1938,9 @@ void verific_import(Design *design, const std::map &par for (const auto &i : parameters) verific_params.Insert(i.first.c_str(), i.second.c_str()); + InitialAssertionRewriter rw; + rw.RegisterCallBack(); + if (top.empty()) { netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, &verific_params); } @@ -2469,6 +2483,9 @@ struct VerificPass : public Pass { std::set top_mod_names; + InitialAssertionRewriter rw; + rw.RegisterCallBack(); + if (mode_all) { log("Running hier_tree::ElaborateAll().\n"); @@ -2493,31 +2510,23 @@ 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); + VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1); + Array veri_modules, vhdl_units; for (; argidx < GetSize(args); argidx++) { const char *name = args[argidx].c_str(); top_mod_names.insert(name); - VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1); - - if (veri_lib) { - VeriModule *veri_module = veri_lib->GetModule(name, 1); - if (veri_module) { - log("Adding Verilog module '%s' to elaboration queue.\n", name); - veri_modules.InsertLast(veri_module); - continue; - } - // Also elaborate all root modules since they may contain bind statements - MapIter mi; - FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) { - if (!veri_module->IsRootModule()) continue; - veri_modules.InsertLast(veri_module); - } + VeriModule *veri_module = veri_lib ? veri_lib->GetModule(name, 1) : nullptr; + if (veri_module) { + log("Adding Verilog module '%s' to elaboration queue.\n", name); + veri_modules.InsertLast(veri_module); + continue; } - VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1); - VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(name); + 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); @@ -2527,6 +2536,16 @@ 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); + } + } + log("Running hier_tree::Elaborate().\n"); Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, ¶meters); Netlist *nl; From 01ec6813730b0d4d83316b22352b5431456a8388 Mon Sep 17 00:00:00 2001 From: Peter Crozier Date: Mon, 8 Jun 2020 20:34:52 +0100 Subject: [PATCH 002/287] Support 2D bit arrays in structures. Optimise array indexing. --- frontends/ast/simplify.cc | 124 ++++++++++++++++++++++++++-------- tests/svtypes/struct_array.sv | 7 +- 2 files changed, 101 insertions(+), 30 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 6970135d06a..c9da8ba4886 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -380,31 +380,100 @@ static int size_packed_struct(AstNode *snode, int base_offset) static AstNode *node_int(int ival) { - // maybe mkconst_int should have default values for the common integer case - return AstNode::mkconst_int(ival, true, 32); + return AstNode::mkconst_int(ival, true); } -static AstNode *offset_indexed_range(int offset_right, int stride, AstNode *left_expr, AstNode *right_expr) +static AstNode *node_uint(uint ival) +{ + return AstNode::mkconst_int(ival, false); +} + +static unsigned int power_of_two(int n) +{ + // iff n is a power of two then return the power, else return 0 + // caller must ensure n > 1 + log_assert(n > 1); + if (n & (n - 1)) { + // not a power of 2 + return 0; + } + // brute force the shift + for (unsigned int i = 1; i < 32; i++) { + n >>= 1; + if (n & 1) { + return i; + } + } + return 0; +} + +static AstNode *multiply_by_const(AstNode *expr_node, int stride) +{ + // the stride is very likely a power of 2, e.g. 8 for bytes + // and so could be optimised with a shift + AstNode *node; + unsigned int shift; + if ((shift = power_of_two(stride)) > 0) { + node = new AstNode(AST_SHIFT_LEFT, expr_node, node_uint(shift)); + } + else { + node = new AstNode(AST_MUL, expr_node, node_int(stride)); + } + return node; +} + +static AstNode *offset_indexed_range(int offset, int stride, AstNode *left_expr, AstNode *right_expr) { // adjust the range expressions to add an offset into the struct // and maybe index using an array stride auto left = left_expr->clone(); auto right = right_expr->clone(); - if (stride == 1) { - // just add the offset - left = new AstNode(AST_ADD, node_int(offset_right), left); - right = new AstNode(AST_ADD, node_int(offset_right), right); + if (stride > 1) { + // newleft = (left + 1) * stride - 1 + left = new AstNode(AST_SUB, multiply_by_const(new AstNode(AST_ADD, left, node_int(1)), stride), node_int(1)); + // newright = right * stride + right = multiply_by_const(right, stride); + } + // add the offset + if (offset) { + left = new AstNode(AST_ADD, node_int(offset), left); + right = new AstNode(AST_ADD, node_int(offset), right); + } + return new AstNode(AST_RANGE, left, right); +} + +static AstNode *make_struct_index_range(AstNode *node, AstNode *rnode, int stride, int offset) +{ + // generate a range node to perform either bit or array indexing + if (rnode->children.size() == 1) { + // index e.g. s.a[i] + return offset_indexed_range(offset, stride, rnode->children[0], rnode->children[0]); + } + else if (rnode->children.size() == 2) { + // slice e.g. s.a[i:j] + return offset_indexed_range(offset, stride, rnode->children[0], rnode->children[1]); } else { - // newleft = offset_right - 1 + (left + 1) * stride - left = new AstNode(AST_ADD, new AstNode(AST_SUB, node_int(offset_right), node_int(1)), - new AstNode(AST_MUL, node_int(stride), new AstNode(AST_ADD, left, node_int(1)))); - // newright = offset_right + right * stride - right = new AstNode(AST_ADD, node_int(offset_right), new AstNode(AST_MUL, right, node_int(stride))); + struct_op_error(node); } +} + +static AstNode *slice_range(AstNode *rnode, AstNode *snode) +{ + // apply the bit slice indicated by snode to the range rnode + log_assert(rnode->type==AST_RANGE); + auto left = rnode->children[0]; + auto right = rnode->children[1]; + log_assert(snode->type==AST_RANGE); + auto slice_left = snode->children[0]; + auto slice_right = snode->children[1]; + auto width = new AstNode(AST_SUB, slice_left->clone(), slice_right->clone()); + right = new AstNode(AST_ADD, right->clone(), slice_right->clone()); + left = new AstNode(AST_ADD, right->clone(), width); return new AstNode(AST_RANGE, left, right); } + static AstNode *make_struct_member_range(AstNode *node, AstNode *member_node) { // Work out the range in the packed array that corresponds to a struct member @@ -414,27 +483,26 @@ static AstNode *make_struct_member_range(AstNode *node, AstNode *member_node) int range_right = member_node->range_right; if (node->children.empty()) { // no range operations apply, return the whole width + return make_range(range_left, range_right); } - else if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) { - auto rnode = node->children[0]; - int stride = get_struct_array_width(member_node); - if (rnode->children.size() == 1) { - // index e.g. s.a[i] - return offset_indexed_range(range_right, stride, rnode->children[0], rnode->children[0]); - } - else if (rnode->children.size() == 2) { - // slice e.g. s.a[i:j] - return offset_indexed_range(range_right, stride, rnode->children[0], rnode->children[1]); - } - else { - struct_op_error(node); - } + int stride = get_struct_array_width(member_node); + if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) { + // bit or array indexing e.g. s.a[2] or s.a[1:0] + return make_struct_index_range(node, node->children[0], stride, range_right); + } + else if (node->children.size() == 1 && node->children[0]->type == AST_MULTIRANGE) { + // multirange, i.e. bit slice after array index, e.g. s.a[i][p:q] + log_assert(stride > 1); + auto mrnode = node->children[0]; + auto element_range = make_struct_index_range(node, mrnode->children[0], stride, range_right); + // then apply bit slice range + auto range = slice_range(element_range, mrnode->children[1]); + delete element_range; + return range; } else { - // TODO multirange, i.e. bit slice after array index s.a[i][p:q] struct_op_error(node); } - return make_range(range_left, range_right); } static void add_members_to_scope(AstNode *snode, std::string name) diff --git a/tests/svtypes/struct_array.sv b/tests/svtypes/struct_array.sv index 022ad56c67e..9c90375ee35 100644 --- a/tests/svtypes/struct_array.sv +++ b/tests/svtypes/struct_array.sv @@ -3,7 +3,7 @@ module top; struct packed { - bit [5:0] [7:0] a; // 6 element packed array of bytes + bit [7:0] [7:0] a; // 8 element packed array of bytes bit [15:0] b; // filler for non-zero offset } s; @@ -13,10 +13,13 @@ module top; s.a[2:1] = 16'h1234; s.a[5] = 8'h42; + s.a[7] = '1; + s.a[7][1:0] = '0; + s.b = '1; s.b[1:0] = '0; end - always_comb assert(s==64'h4200_0012_3400_FFFC); + always_comb assert(s==80'hFC00_4200_0012_3400_FFFC); endmodule From f80b09fc5853da904dad902b3dfaa5fa44fc51af Mon Sep 17 00:00:00 2001 From: Peter Crozier Date: Tue, 9 Jun 2020 13:52:09 +0100 Subject: [PATCH 003/287] Support 2D packed bit arrays in struct/union. --- frontends/ast/simplify.cc | 36 +----------------------------------- 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index c9da8ba4886..f11383b9665 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -383,43 +383,9 @@ static AstNode *node_int(int ival) return AstNode::mkconst_int(ival, true); } -static AstNode *node_uint(uint ival) -{ - return AstNode::mkconst_int(ival, false); -} - -static unsigned int power_of_two(int n) -{ - // iff n is a power of two then return the power, else return 0 - // caller must ensure n > 1 - log_assert(n > 1); - if (n & (n - 1)) { - // not a power of 2 - return 0; - } - // brute force the shift - for (unsigned int i = 1; i < 32; i++) { - n >>= 1; - if (n & 1) { - return i; - } - } - return 0; -} - static AstNode *multiply_by_const(AstNode *expr_node, int stride) { - // the stride is very likely a power of 2, e.g. 8 for bytes - // and so could be optimised with a shift - AstNode *node; - unsigned int shift; - if ((shift = power_of_two(stride)) > 0) { - node = new AstNode(AST_SHIFT_LEFT, expr_node, node_uint(shift)); - } - else { - node = new AstNode(AST_MUL, expr_node, node_int(stride)); - } - return node; + return new AstNode(AST_MUL, expr_node, node_int(stride)); } static AstNode *offset_indexed_range(int offset, int stride, AstNode *left_expr, AstNode *right_expr) From 185bbbe681d02874796e70a1ee147f4b8dca6cbb Mon Sep 17 00:00:00 2001 From: Kazuki Sakamoto Date: Sun, 14 Jun 2020 15:15:59 -0700 Subject: [PATCH 004/287] static cast: support changing size and signedness Support SystemVerilog Static Cast - size - signedness - (type is not supposted yet) Fix #535 --- frontends/ast/ast.cc | 1 + frontends/ast/ast.h | 1 + frontends/ast/genrtlil.cc | 24 ++++++++++++++++++++++++ frontends/ast/simplify.cc | 1 + frontends/verilog/verilog_lexer.l | 2 ++ frontends/verilog/verilog_parser.y | 19 +++++++++++++++++++ 6 files changed, 48 insertions(+) diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 03fd272dafd..9520ae32c76 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -95,6 +95,7 @@ std::string AST::type2str(AstNodeType type) X(AST_TO_SIGNED) X(AST_TO_UNSIGNED) X(AST_SELFSZ) + X(AST_CAST_SIZE) X(AST_CONCAT) X(AST_REPLICATE) X(AST_BIT_NOT) diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 46864a4e1b6..9a5aa15f941 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -76,6 +76,7 @@ namespace AST AST_TO_SIGNED, AST_TO_UNSIGNED, AST_SELFSZ, + AST_CAST_SIZE, AST_CONCAT, AST_REPLICATE, AST_BIT_NOT, diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 9546558aae3..e878d0dd2ba 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -814,6 +814,16 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun children.at(0)->detectSignWidthWorker(sub_width_hint, sign_hint); break; + case AST_CAST_SIZE: + while (children.at(0)->simplify(true, false, false, 1, -1, false, false)) { } + if (children.at(0)->type != AST_CONSTANT) + log_file_error(filename, location.first_line, "Static cast with non constant expression!\n"); + children.at(1)->detectSignWidthWorker(width_hint, sign_hint); + width_hint = children.at(0)->bitsAsConst().as_int(); + if (width_hint <= 0) + log_file_error(filename, location.first_line, "Static cast with zero or negative size!\n"); + break; + case AST_CONCAT: for (auto child : children) { sub_width_hint = 0; @@ -1289,6 +1299,20 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) return sig; } + // changing the size of signal can be done directly using RTLIL::SigSpec + case AST_CAST_SIZE: { + RTLIL::SigSpec size = children[0]->genRTLIL(); + RTLIL::SigSpec sig = children[1]->genRTLIL(); + if (!size.is_fully_const()) + log_file_error(filename, location.first_line, "Static cast with non constant expression!\n"); + int width = size.as_int(); + if (width <= 0) + log_file_error(filename, location.first_line, "Static cast with zero or negative size!\n"); + sig.extend_u0(width, sign_hint); + is_signed = sign_hint; + return sig; + } + // concatenation of signals can be done directly using RTLIL::SigSpec case AST_CONCAT: { RTLIL::SigSpec sig; diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 5f026dfed89..1d5dd91a7ac 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -950,6 +950,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, case AST_TO_SIGNED: case AST_TO_UNSIGNED: case AST_SELFSZ: + case AST_CAST_SIZE: case AST_CONCAT: case AST_REPLICATE: case AST_REDUCE_AND: diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index e6fa6361e07..6195bb14962 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -517,6 +517,8 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { "<<<" { return OP_SSHL; } ">>>" { return OP_SSHR; } +"'" { return OP_CAST; } + "::" { return TOK_PACKAGESEP; } "++" { return TOK_INCREMENT; } "--" { return TOK_DECREMENT; } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 15c231f3b98..bbf1a436b80 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -298,6 +298,7 @@ static void rewriteAsMemoryNode(AstNode *node, AstNode *rangeNode) %left '+' '-' %left '*' '/' '%' %left OP_POW +%left OP_CAST %right UNARY_OPS %define parse.error verbose @@ -3001,6 +3002,24 @@ basic_expr: $$ = new AstNode(AST_LOGIC_NOT, $3); SET_AST_NODE_LOC($$, @1, @3); append_attr($$, $2); + } | + TOK_SIGNED OP_CAST '(' expr ')' { + if (!sv_mode) + frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode."); + $$ = new AstNode(AST_TO_SIGNED, $4); + SET_AST_NODE_LOC($$, @1, @4); + } | + TOK_UNSIGNED OP_CAST '(' expr ')' { + if (!sv_mode) + frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode."); + $$ = new AstNode(AST_TO_UNSIGNED, $4); + SET_AST_NODE_LOC($$, @1, @4); + } | + basic_expr OP_CAST '(' expr ')' { + if (!sv_mode) + frontend_verilog_yyerror("Static cast is only supported in SystemVerilog mode."); + $$ = new AstNode(AST_CAST_SIZE, $1, $4); + SET_AST_NODE_LOC($$, @1, @4); }; concat_list: From 6bf75be73bc0767b5df9e3fa33a58cfe6aae9f89 Mon Sep 17 00:00:00 2001 From: Kazuki Sakamoto Date: Sun, 14 Jun 2020 15:26:47 -0700 Subject: [PATCH 005/287] static cast: add tests --- tests/svtypes/static_cast_negative.ys | 4 ++ tests/svtypes/static_cast_nonconst.ys | 4 ++ tests/svtypes/static_cast_simple.sv | 64 +++++++++++++++++++++++++++ tests/svtypes/static_cast_verilog.ys | 4 ++ tests/svtypes/static_cast_zero.ys | 4 ++ 5 files changed, 80 insertions(+) create mode 100644 tests/svtypes/static_cast_negative.ys create mode 100644 tests/svtypes/static_cast_nonconst.ys create mode 100644 tests/svtypes/static_cast_simple.sv create mode 100644 tests/svtypes/static_cast_verilog.ys create mode 100644 tests/svtypes/static_cast_zero.ys diff --git a/tests/svtypes/static_cast_negative.ys b/tests/svtypes/static_cast_negative.ys new file mode 100644 index 00000000000..4f9e8cf6e2d --- /dev/null +++ b/tests/svtypes/static_cast_negative.ys @@ -0,0 +1,4 @@ +logger -expect error "Static cast with zero or negative size" 1 +read_verilog -sv <> 8; + assign d = (16'(a) * b) >> 8; + + parameter P = 16; + + wire signed [7:0] s0, s1, s2; + wire [7:0] u0, u1, u2, u3, u4, u5, u6; + assign s0 = -8'd1; + assign s1 = 4'(s0); + assign s2 = 4'(unsigned'(s0)); + assign u0 = -8'd1; + assign u1 = 4'(u0); + assign u2 = 4'(signed'(u0)); + assign u3 = 8'(4'(s0)); + assign u4 = 8'(4'(u0)); + assign u5 = 8'(4'(signed'(-8'd1))); + assign u6 = 8'(4'(unsigned'(-8'd1))); + + wire [8:0] n0, n1, n2, n3, n4, n5, n6, n7, n8, n9; + assign n0 = s1; + assign n1 = s2; + assign n2 = 9'(s1); + assign n3 = 9'(s2); + assign n4 = 9'(unsigned'(s1)); + assign n5 = 9'(unsigned'(s2)); + assign n6 = 9'(u0); + assign n7 = 9'(u1); + assign n8 = 9'(signed'(u0)); + assign n9 = 9'(signed'(u1)); + + always_comb begin + assert(c == 8'b0000_0000); + assert(d == 8'b0000_0001); + + assert((P + 1)'(a) == 17'b0_0000_0000_0001_0000); + assert((P + 1)'(d - 2) == 17'b1_1111_1111_1111_1111); + + assert(s0 == 8'b1111_1111); + assert(s1 == 8'b1111_1111); + assert(s2 == 8'b0000_1111); + assert(u0 == 8'b1111_1111); + assert(u1 == 8'b0000_1111); + assert(u2 == 8'b1111_1111); + assert(u3 == 8'b1111_1111); + assert(u4 == 8'b0000_1111); + assert(u5 == 8'b1111_1111); + assert(u6 == 8'b0000_1111); + + assert(n0 == 9'b1_1111_1111); + assert(n1 == 9'b0_0000_1111); + assert(n2 == 9'b1_1111_1111); + assert(n3 == 9'b0_0000_1111); + assert(n4 == 9'b0_1111_1111); + assert(n5 == 9'b0_0000_1111); + assert(n6 == 9'b0_1111_1111); + assert(n7 == 9'b0_0000_1111); + assert(n8 == 9'b1_1111_1111); + assert(n9 == 9'b0_0000_1111); + end +endmodule diff --git a/tests/svtypes/static_cast_verilog.ys b/tests/svtypes/static_cast_verilog.ys new file mode 100644 index 00000000000..fa3680b6866 --- /dev/null +++ b/tests/svtypes/static_cast_verilog.ys @@ -0,0 +1,4 @@ +logger -expect error "Static cast is only supported in SystemVerilog mode" 1 +read_verilog < Date: Fri, 19 Jun 2020 19:09:43 -0700 Subject: [PATCH 006/287] static cast: simplify --- frontends/ast/simplify.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 1d5dd91a7ac..e2da17c0909 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -3484,6 +3484,13 @@ replace_fcall_later:; } } break; + case AST_CAST_SIZE: + if (children.at(0)->type == AST_CONSTANT && children.at(1)->type == AST_CONSTANT) { + int width = children[0]->bitsAsConst().as_int(); + RTLIL::Const val = children[1]->bitsAsConst(width); + newNode = mkconst_bits(val.bits, children[1]->is_signed); + } + break; case AST_CONCAT: string_op = !children.empty(); for (auto it = children.begin(); it != children.end(); it++) { From 7cb56f34b06de666935fbda315ce7c7bd45048b3 Mon Sep 17 00:00:00 2001 From: Lukasz Dalek Date: Mon, 18 May 2020 21:01:16 +0200 Subject: [PATCH 007/287] Fix integer signing grammar This commit fixes signed/unsigned grammar in parameters as defined in SV LRM A2.2.1. Example of correct parameters: parameter integer signed i = 0; parameter integer unsigned i = 0; Example of incorrect parameters: parameter signed integer i = 0; parameter unsigned integer i = 0; Signed-off-by: Lukasz Dalek Signed-off-by: Kamil Rakoczy --- frontends/verilog/verilog_parser.y | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 15c231f3b98..18745e38eec 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -1329,6 +1329,8 @@ ignspec_id: param_signed: TOK_SIGNED { astbuf1->is_signed = true; + } | TOK_UNSIGNED { + astbuf1->is_signed = false; } | /* empty */; param_integer: @@ -1339,14 +1341,14 @@ param_integer: astbuf1->children.back()->children.push_back(AstNode::mkconst_int(31, true)); astbuf1->children.back()->children.push_back(AstNode::mkconst_int(0, true)); astbuf1->is_signed = true; - } | /* empty */; + } param_real: TOK_REAL { if (astbuf1->children.size() != 1) frontend_verilog_yyerror("Parameter already declared as integer, cannot set to real."); astbuf1->children.push_back(new AstNode(AST_REALVALUE)); - } | /* empty */; + } param_range: range { @@ -1357,8 +1359,12 @@ param_range: } }; +param_integer_type: param_integer param_signed +param_range_type: type_vec param_signed param_range +param_implicit_type: param_signed param_range + param_type: - param_signed param_integer param_real param_range | + param_integer_type | param_real | param_range_type | param_implicit_type | hierarchical_type_id { astbuf1->is_custom_type = true; astbuf1->children.push_back(new AstNode(AST_WIRETYPE)); From 6f9be939bd7653b0bdcae93a1033a086a4561b68 Mon Sep 17 00:00:00 2001 From: Lukasz Dalek Date: Mon, 1 Jun 2020 15:25:24 +0200 Subject: [PATCH 008/287] Parse macro call attached semicolon as empty expression Signed-off-by: Lukasz Dalek --- frontends/verilog/verilog_parser.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 18745e38eec..35e34a124f0 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -745,7 +745,7 @@ module_body: module_body_stmt: task_func_decl | specify_block | param_decl | localparam_decl | typedef_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt | enum_decl | struct_decl | - always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block; + always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block | /* empty statement */ ';'; checker_decl: TOK_CHECKER TOK_ID ';' { From 76a34dc5f3a60c89efeaa3378ca0e2700a8aebd2 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Fri, 26 Jun 2020 15:35:35 +0200 Subject: [PATCH 009/287] Add signed/unsigned tests Signed-off-by: Kamil Rakoczy --- tests/various/signed.ys | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/various/signed.ys diff --git a/tests/various/signed.ys b/tests/various/signed.ys new file mode 100644 index 00000000000..2319a5da1f9 --- /dev/null +++ b/tests/various/signed.ys @@ -0,0 +1,28 @@ +# SV LRM A2.2.1 + +read_verilog -sv < Date: Fri, 26 Jun 2020 17:16:00 +0200 Subject: [PATCH 010/287] Add a few more gate types to the manual. --- manual/CHAPTER_CellLib.tex | 44 +++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex index 25adcda8614..8b4da3fd845 100644 --- a/manual/CHAPTER_CellLib.tex +++ b/manual/CHAPTER_CellLib.tex @@ -490,6 +490,7 @@ \section{Gates} \begin{tabular}[t]{ll} Verilog & Cell Type \\ \hline +\lstinline[language=Verilog]; Y = A; & {\tt \$\_BUF\_} \\ \lstinline[language=Verilog]; Y = ~A; & {\tt \$\_NOT\_} \\ \lstinline[language=Verilog]; Y = A & B; & {\tt \$\_AND\_} \\ \lstinline[language=Verilog]; Y = ~(A & B); & {\tt \$\_NAND\_} \\ @@ -499,8 +500,16 @@ \section{Gates} \lstinline[language=Verilog]; Y = A | ~B; & {\tt \$\_ORNOT\_} \\ \lstinline[language=Verilog]; Y = A ^ B; & {\tt \$\_XOR\_} \\ \lstinline[language=Verilog]; Y = ~(A ^ B); & {\tt \$\_XNOR\_} \\ +\lstinline[language=Verilog]; Y = ~((A & B) | C); & {\tt \$\_AOI3\_} \\ +\lstinline[language=Verilog]; Y = ~((A | B) & C); & {\tt \$\_OAI3\_} \\ +\lstinline[language=Verilog]; Y = ~((A & B) | (C & D)); & {\tt \$\_AOI4\_} \\ +\lstinline[language=Verilog]; Y = ~((A | B) & (C | D)); & {\tt \$\_OAI4\_} \\ \lstinline[language=Verilog]; Y = S ? B : A; & {\tt \$\_MUX\_} \\ -\lstinline[language=Verilog]; Y = EN ? A : 'bz; & {\tt \$\_TBUF\_} \\ +\lstinline[language=Verilog]; Y = ~(S ? B : A); & {\tt \$\_NMUX\_} \\ +(see below) & {\tt \$\_MUX4\_} \\ +(see below) & {\tt \$\_MUX8\_} \\ +(see below) & {\tt \$\_MUX16\_} \\ +\lstinline[language=Verilog]; Y = EN ? A : 1'bz; & {\tt \$\_TBUF\_} \\ \hline \lstinline[language=Verilog]; always @(negedge C) Q <= D; & {\tt \$\_DFF\_N\_} \\ \lstinline[language=Verilog]; always @(posedge C) Q <= D; & {\tt \$\_DFF\_P\_} \\ @@ -611,10 +620,34 @@ \section{Gates} \end{table} Tables~\ref{tab:CellLib_gates}, \ref{tab:CellLib_gates_dffe}, \ref{tab:CellLib_gates_adff}, \ref{tab:CellLib_gates_adffe}, \ref{tab:CellLib_gates_dffsr} and \ref{tab:CellLib_gates_dffsre} list all cell types used for gate level logic. The cell types -{\tt \$\_NOT\_}, {\tt \$\_AND\_}, {\tt \$\_NAND\_}, {\tt \$\_ANDNOT\_}, {\tt \$\_OR\_}, {\tt \$\_NOR\_}, -{\tt \$\_ORNOT\_}, {\tt \$\_XOR\_}, {\tt \$\_XNOR\_} and {\tt \$\_MUX\_} are used to model combinatorial logic. +{\tt \$\_BUF\_}, {\tt \$\_NOT\_}, {\tt \$\_AND\_}, {\tt \$\_NAND\_}, {\tt \$\_ANDNOT\_}, +{\tt \$\_OR\_}, {\tt \$\_NOR\_}, {\tt \$\_ORNOT\_}, {\tt \$\_XOR\_}, {\tt \$\_XNOR\_}, +{\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, {\tt \$\_OAI4\_}, +{\tt \$\_MUX\_}, {\tt \$\_MUX4\_}, {\tt \$\_MUX8\_}, {\tt \$\_MUX16\_} and {\tt \$\_NMUX\_} are used to model combinatorial logic. The cell type {\tt \$\_TBUF\_} is used to model tristate logic. +The {\tt \$\_MUX4\_}, {\tt \$\_MUX8\_} and {\tt \$\_MUX16\_} cells are used to model wide muxes, and correspond to the following Verilog code: + +\begin{lstlisting}[language=Verilog] +// $_MUX4_ +assign Y = T ? (S ? D : C) : + (S ? B : A); +// $_MUX8_ +assign Y = U ? T ? (S ? H : G) : + (S ? F : E) : + T ? (S ? D : C) : + (S ? B : A); +// $_MUX16_ +assign Y = V ? U ? T ? (S ? P : O) : + (S ? N : M) : + T ? (S ? L : K) : + (S ? J : I) : + U ? T ? (S ? H : G) : + (S ? F : E) : + T ? (S ? D : C) : + (S ? B : A); +\end{lstlisting} + The cell types {\tt \$\_DFF\_N\_} and {\tt \$\_DFF\_P\_} represent d-type flip-flops. The cell types {\tt \$\_DFFE\_NN\_}, {\tt \$\_DFFE\_NP\_}, {\tt \$\_DFFE\_PN\_} and {\tt \$\_DFFE\_PP\_} @@ -765,8 +798,3 @@ \section{Gates} \begin{fixme} Add information about {\tt \$\_DLATCH\_?\_}, and {\tt \$\_DLATCHSR\_???\_} cells. \end{fixme} - -\begin{fixme} -Add information about {\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, {\tt \$\_OAI4\_}, and {\tt \$\_NMUX\_} cells. -\end{fixme} - From 2db270cbc7e0884124ca9efdc1e9e4716885c85c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Fri, 26 Jun 2020 20:57:39 +0200 Subject: [PATCH 011/287] Add latches to the manual. --- manual/CHAPTER_CellLib.tex | 207 +++++++++++++++++++++++++++++-------- 1 file changed, 165 insertions(+), 42 deletions(-) diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex index 8b4da3fd845..d4572a88a29 100644 --- a/manual/CHAPTER_CellLib.tex +++ b/manual/CHAPTER_CellLib.tex @@ -221,6 +221,26 @@ \subsection{Multiplexers} \subsection{Registers} +SR-type latches are represented by {\tt \$sr} cells. These cells have input ports +\B{SET} and \B{CLR} and an output port \B{Q}. They have the following parameters: + +\begin{itemize} +\item \B{WIDTH} \\ +The width of inputs \B{SET} and \B{CLR} and output \B{Q}. + +\item \B{SET\_POLARITY} \\ +The set input bits are active-high if this parameter has the value {\tt 1'b1} and active-low +if this parameter is {\tt 1'b0}. + +\item \B{CLR\_POLARITY} \\ +The reset input bits are active-high if this parameter has the value {\tt 1'b1} and active-low +if this parameter is {\tt 1'b0}. +\end{itemize} + +Both set and reset inputs have separate bits for every output bit. +When both the set and reset inputs of an {\tt \$sr} cell are active for a given bit +index, the reset input takes precedence. + D-type flip-flops are represented by {\tt \$dff} cells. These cells have a clock port \B{CLK}, an input port \B{D} and an output port \B{Q}. The following parameters are available for {\tt \$dff} cells: @@ -269,21 +289,8 @@ \subsection{Registers} D-type flip-flops with asynchronous set and reset are represented by {\tt \$dffsr} cells. As the {\tt \$dff} cells they have \B{CLK}, \B{D} and \B{Q} ports. In addition they also have -a single-bit \B{SET} input port for the set pin, a single-bit \B{CLR} input port for the reset pin, -and the following two parameters: - -\begin{itemize} -\item \B{SET\_POLARITY} \\ -The set input is active-high if this parameter has the value {\tt 1'b1} and active-low -if this parameter is {\tt 1'b0}. - -\item \B{CLR\_POLARITY} \\ -The reset input is active-high if this parameter has the value {\tt 1'b1} and active-low -if this parameter is {\tt 1'b0}. -\end{itemize} - -When both the set and reset inputs of a {\tt \$dffsr} cell are active, the reset input takes -precedence. +multi-bit \B{SET} and \B{CLR} input ports and the corresponding polarity parameters, like +{\tt \$sr} cells. D-type flip-flops with enable are represented by {\tt \$dffe}, {\tt \$adffe}, {\tt \$dffsre}, {\tt \$sdffe}, and {\tt \$sdffce} cells, which are enhanced variants of {\tt \$dff}, {\tt \$adff}, {\tt \$dffsr}, @@ -297,10 +304,36 @@ \subsection{Registers} if this parameter is {\tt 1'b0}. \end{itemize} -\begin{fixme} -Add information about {\tt \$sr} cells (set-reset flip-flops), {\tt \$dlatch} cells (d-type latches), -{\tt \$adlatch} and {\tt \$dlatchsr} cells (d-type latches with set/reset). -\end{fixme} +D-type latches are represented by {\tt \$dlatch} cells. These cells have an enable port \B{EN}, +an input port \B{D}, and an output port \B{Q}. The following parameters are available for {\tt \$dlatch} cells: + +\begin{itemize} +\item \B{WIDTH} \\ +The width of input \B{D} and output \B{Q}. + +\item \B{EN\_POLARITY} \\ +The enable input is active-high if this parameter has the value {\tt 1'b1} and active-low +if this parameter is {\tt 1'b0}. +\end{itemize} + +The latch is transparent when the \B{EN} input is active. + +D-type latches with reset are represented by {\tt \$adlatch} cells. In addition to {\tt \$dlatch} +ports and parameters, they also have a single-bit \B{ARST} input port for the reset pin and the following additional parameters: + +\begin{itemize} +\item \B{ARST\_POLARITY} \\ +The asynchronous reset is active-high if this parameter has the value {\tt 1'b1} and active-low +if this parameter is {\tt 1'b0}. + +\item \B{ARST\_VALUE} \\ +The state of \B{Q} will be set to this value when the reset is active. +\end{itemize} + +D-type latches with set and reset are represented by {\tt \$dlatchsr} cells. +In addition to {\tt \$dlatch} ports and parameters, they also have multi-bit +\B{SET} and \B{CLR} input ports and the corresponding polarity parameters, like +{\tt \$sr} cells. \subsection{Memories} \label{sec:memcells} @@ -476,6 +509,23 @@ \subsection{Finite State Machines} Add a brief description of the {\tt \$fsm} cell type. \end{fixme} +\subsection{Specify rules} + +\begin{fixme} +Add information about {\tt \$specify2}, {\tt \$specify3}, and {\tt \$specrule} cells. +\end{fixme} + +\subsection{Formal verification cells} + +\begin{fixme} +Add information about {\tt \$assert}, {\tt \$assume}, {\tt \$live}, {\tt \$fair}, {\tt \$cover}, {\tt \$equiv}, +{\tt \$initstate}, {\tt \$anyconst}, {\tt \$anyseq}, {\tt \$allconst}, {\tt \$allseq} cells. +\end{fixme} + +\begin{fixme} +Add information about {\tt \$ff} and {\tt \$\_FF\_} cells. +\end{fixme} + \section{Gates} \label{sec:celllib_gates} @@ -513,6 +563,8 @@ \section{Gates} \hline \lstinline[language=Verilog]; always @(negedge C) Q <= D; & {\tt \$\_DFF\_N\_} \\ \lstinline[language=Verilog]; always @(posedge C) Q <= D; & {\tt \$\_DFF\_P\_} \\ +\lstinline[language=Verilog]; always @* if (!E) Q <= D; & {\tt \$\_DLATCH\_N\_} \\ +\lstinline[language=Verilog]; always @* if (E) Q <= D; & {\tt \$\_DLATCH\_P\_} \\ \end{tabular} \caption{Cell types for gate level logic networks (main list)} \label{tab:CellLib_gates} @@ -619,7 +671,57 @@ \section{Gates} \label{tab:CellLib_gates_dffsre} \end{table} -Tables~\ref{tab:CellLib_gates}, \ref{tab:CellLib_gates_dffe}, \ref{tab:CellLib_gates_adff}, \ref{tab:CellLib_gates_adffe}, \ref{tab:CellLib_gates_dffsr} and \ref{tab:CellLib_gates_dffsre} list all cell types used for gate level logic. The cell types +\begin{table}[t] +\hfil +\begin{tabular}[t]{llll} +$EnLvl$ & $RstLvl$ & $RstVal$ & Cell Type \\ +\hline +\lstinline[language=Verilog];0; & \lstinline[language=Verilog];0; & \lstinline[language=Verilog];0; & {\tt \$\_DLATCH\_NN0\_} \\ +\lstinline[language=Verilog];0; & \lstinline[language=Verilog];0; & \lstinline[language=Verilog];1; & {\tt \$\_DLATCH\_NN1\_} \\ +\lstinline[language=Verilog];0; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];0; & {\tt \$\_DLATCH\_NP0\_} \\ +\lstinline[language=Verilog];0; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];1; & {\tt \$\_DLATCH\_NP1\_} \\ +\lstinline[language=Verilog];1; & \lstinline[language=Verilog];0; & \lstinline[language=Verilog];0; & {\tt \$\_DLATCH\_PN0\_} \\ +\lstinline[language=Verilog];1; & \lstinline[language=Verilog];0; & \lstinline[language=Verilog];1; & {\tt \$\_DLATCH\_PN1\_} \\ +\lstinline[language=Verilog];1; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];0; & {\tt \$\_DLATCH\_PP0\_} \\ +\lstinline[language=Verilog];1; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];1; & {\tt \$\_DLATCH\_PP1\_} \\ +\end{tabular} +\caption{Cell types for gate level logic networks (latches with reset)} +\label{tab:CellLib_gates_adlatch} +\end{table} + +\begin{table}[t] +\hfil +\begin{tabular}[t]{llll} +$EnLvl$ & $SetLvl$ & $RstLvl$ & Cell Type \\ +\hline +\lstinline[language=Verilog];0; & \lstinline[language=Verilog];0; & \lstinline[language=Verilog];0; & {\tt \$\_DLATCHSR\_NNN\_} \\ +\lstinline[language=Verilog];0; & \lstinline[language=Verilog];0; & \lstinline[language=Verilog];1; & {\tt \$\_DLATCHSR\_NNP\_} \\ +\lstinline[language=Verilog];0; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];0; & {\tt \$\_DLATCHSR\_NPN\_} \\ +\lstinline[language=Verilog];0; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];1; & {\tt \$\_DLATCHSR\_NPP\_} \\ +\lstinline[language=Verilog];1; & \lstinline[language=Verilog];0; & \lstinline[language=Verilog];0; & {\tt \$\_DLATCHSR\_PNN\_} \\ +\lstinline[language=Verilog];1; & \lstinline[language=Verilog];0; & \lstinline[language=Verilog];1; & {\tt \$\_DLATCHSR\_PNP\_} \\ +\lstinline[language=Verilog];1; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];0; & {\tt \$\_DLATCHSR\_PPN\_} \\ +\lstinline[language=Verilog];1; & \lstinline[language=Verilog];1; & \lstinline[language=Verilog];1; & {\tt \$\_DLATCHSR\_PPP\_} \\ +\end{tabular} +\caption{Cell types for gate level logic networks (latches with set and reset)} +\label{tab:CellLib_gates_dlatchsr} +\end{table} + +\begin{table}[t] +\hfil +\begin{tabular}[t]{llll} +$SetLvl$ & $RstLvl$ & Cell Type \\ +\hline +\lstinline[language=Verilog];0; & \lstinline[language=Verilog];0; & {\tt \$\_SR\_NN\_} \\ +\lstinline[language=Verilog];0; & \lstinline[language=Verilog];1; & {\tt \$\_SR\_NP\_} \\ +\lstinline[language=Verilog];1; & \lstinline[language=Verilog];0; & {\tt \$\_SR\_PN\_} \\ +\lstinline[language=Verilog];1; & \lstinline[language=Verilog];1; & {\tt \$\_SR\_PP\_} \\ +\end{tabular} +\caption{Cell types for gate level logic networks (SR latches)} +\label{tab:CellLib_gates_sr} +\end{table} + +Tables~\ref{tab:CellLib_gates}, \ref{tab:CellLib_gates_dffe}, \ref{tab:CellLib_gates_adff}, \ref{tab:CellLib_gates_adffe}, \ref{tab:CellLib_gates_dffsr}, \ref{tab:CellLib_gates_dffsre}, \ref{tab:CellLib_gates_adlatch}, \ref{tab:CellLib_gates_dlatchsr} and \ref{tab:CellLib_gates_sr} list all cell types used for gate level logic. The cell types {\tt \$\_BUF\_}, {\tt \$\_NOT\_}, {\tt \$\_AND\_}, {\tt \$\_NAND\_}, {\tt \$\_ANDNOT\_}, {\tt \$\_OR\_}, {\tt \$\_NOR\_}, {\tt \$\_ORNOT\_}, {\tt \$\_XOR\_}, {\tt \$\_XNOR\_}, {\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, {\tt \$\_OAI4\_}, @@ -650,7 +752,7 @@ \section{Gates} The cell types {\tt \$\_DFF\_N\_} and {\tt \$\_DFF\_P\_} represent d-type flip-flops. -The cell types {\tt \$\_DFFE\_NN\_}, {\tt \$\_DFFE\_NP\_}, {\tt \$\_DFFE\_PN\_} and {\tt \$\_DFFE\_PP\_} +The cell types {\tt \$\_DFFE\_[NP][NP]\_} implement d-type flip-flops with enable. The values in the table for these cell types relate to the following Verilog code template. @@ -660,8 +762,7 @@ \section{Gates} Q <= D; \end{lstlisting} -The cell types {\tt \$\_DFF\_NN0\_}, {\tt \$\_DFF\_NN1\_}, {\tt \$\_DFF\_NP0\_}, {\tt \$\_DFF\_NP1\_}, -{\tt \$\_DFF\_PN0\_}, {\tt \$\_DFF\_PN1\_}, {\tt \$\_DFF\_PP0\_} and {\tt \$\_DFF\_PP1\_} implement +The cell types {\tt \$\_DFF\_[NP][NP][01]\_} implement d-type flip-flops with asynchronous reset. The values in the table for these cell types relate to the following Verilog code template, where \lstinline[mathescape,language=Verilog];$RstEdge$; is \lstinline[language=Verilog];posedge; if \lstinline[mathescape,language=Verilog];$RstLvl$; if \lstinline[language=Verilog];1;, and \lstinline[language=Verilog];negedge; @@ -675,8 +776,7 @@ \section{Gates} Q <= D; \end{lstlisting} -The cell types {\tt \$\_SDFF\_NN0\_}, {\tt \$\_SDFF\_NN1\_}, {\tt \$\_SDFF\_NP0\_}, {\tt \$\_SDFF\_NP1\_}, -{\tt \$\_SDFF\_PN0\_}, {\tt \$\_SDFF\_PN1\_}, {\tt \$\_SDFF\_PP0\_} and {\tt \$\_SDFF\_PP1\_} implement +The cell types {\tt \$\_SDFF\_[NP][NP][01]\_} implement d-type flip-flops with synchronous reset. The values in the table for these cell types relate to the following Verilog code template: @@ -765,20 +865,51 @@ \section{Gates} Q <= D; \end{lstlisting} +The cell types {\tt \$\_DLATCH\_N\_} and {\tt \$\_DLATCH\_P\_} represent d-type latches. + +The cell types {\tt \$\_DLATCH\_[NP][NP][01]\_} implement +d-type latches with reset. The values in the table for these cell types relate to the +following Verilog code template: + +\begin{lstlisting}[mathescape,language=Verilog] + always @* + if (R == $RstLvl$) + Q <= $RstVal$; + else if (E == $EnLvl$) + Q <= D; +\end{lstlisting} + +The cell types {\tt \$\_DLATCHSR\_[NP][NP][NP]\_} implement +d-type latches with set and reset. The values in the table for these cell types relate to the +following Verilog code template: + +\begin{lstlisting}[mathescape,language=Verilog] + always @* + if (R == $RstLvl$) + Q <= 0; + else if (S == $SetLvl$) + Q <= 1; + else if (E == $EnLvl$) + Q <= D; +\end{lstlisting} + +The cell types {\tt \$\_SR\_[NP][NP]\_} implement +sr-type latches. The values in the table for these cell types relate to the +following Verilog code template: + +\begin{lstlisting}[mathescape,language=Verilog] + always @* + if (R == $RstLvl$) + Q <= 0; + else if (S == $SetLvl$) + Q <= 1; +\end{lstlisting} + In most cases gate level logic networks are created from RTL networks using the {\tt techmap} pass. The flip-flop cells from the gate level logic network can be mapped to physical flip-flop cells from a Liberty file using the {\tt dfflibmap} pass. The combinatorial logic cells can be mapped to physical cells from a Liberty file via ABC \citeweblink{ABC} using the {\tt abc} pass. -\begin{fixme} -Add information about {\tt \$assert}, {\tt \$assume}, {\tt \$live}, {\tt \$fair}, {\tt \$cover}, {\tt \$equiv}, -{\tt \$initstate}, {\tt \$anyconst}, {\tt \$anyseq}, {\tt \$allconst}, {\tt \$allseq} cells. -\end{fixme} - -\begin{fixme} -Add information about {\tt \$specify2}, {\tt \$specify3}, and {\tt \$specrule} cells. -\end{fixme} - \begin{fixme} Add information about {\tt \$slice} and {\tt \$concat} cells. \end{fixme} @@ -790,11 +921,3 @@ \section{Gates} \begin{fixme} Add information about {\tt \$alu}, {\tt \$macc}, {\tt \$fa}, and {\tt \$lcu} cells. \end{fixme} - -\begin{fixme} -Add information about {\tt \$ff} and {\tt \$\_FF\_} cells. -\end{fixme} - -\begin{fixme} -Add information about {\tt \$\_DLATCH\_?\_}, and {\tt \$\_DLATCHSR\_???\_} cells. -\end{fixme} From 48b6d3272c3f6ebf1ee1aab3a8abeb5017519b82 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 29 Jun 2020 10:33:39 +0200 Subject: [PATCH 012/287] sim - error when memrd and memwr detected --- passes/sat/sim.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 1ab082b091e..fb496ff87c3 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -163,7 +163,10 @@ struct SimInstance mem_database[cell] = mem; } - + if (cell->type.in(ID($memwr),ID($memrd))) + { + log_error("$memrd and $memwr cells have to be merged to stand-alone $mem cells (execute memory_collect pass)\n"); + } if (cell->type.in(ID($assert), ID($cover), ID($assume))) { formal_database.insert(cell); } From 5aae9360444448dd444b414db46a327c980c2d7a Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 29 Jun 2020 13:18:13 +0200 Subject: [PATCH 013/287] Use ID macro to fix assertion --- passes/tests/test_cell.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc index 942468e295a..72fb630f8bb 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -905,7 +905,7 @@ struct TestCellPass : public Pass { if (!ilang_file.empty()) { if (!selected_cell_types.empty()) log_cmd_error("Do not specify any cell types when using -f.\n"); - selected_cell_types.push_back("ilang"); + selected_cell_types.push_back(ID(ilang)); } if (selected_cell_types.empty()) @@ -917,7 +917,7 @@ struct TestCellPass : public Pass { for (int i = 0; i < num_iter; i++) { RTLIL::Design *design = new RTLIL::Design; - if (cell_type == "ilang") + if (cell_type == ID(ilang)) Frontend::frontend_call(design, NULL, std::string(), "ilang " + ilang_file); else create_gold_module(design, cell_type, cell_types.at(cell_type), constmode, muxdiv); From 27cec16cda7d10e94931b25711358da2b382fdbf Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Fri, 26 Jun 2020 19:52:36 -0700 Subject: [PATCH 014/287] Allow constant function calls in for loops and generate if and case --- frontends/ast/simplify.cc | 6 ++- tests/various/const_func.v | 75 +++++++++++++++++++++++++++++++++++++ tests/various/const_func.ys | 1 + 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 tests/various/const_func.v create mode 100644 tests/various/const_func.ys diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 55e7da0aa88..c819924a00c 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1126,6 +1126,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, bool in_param_here = in_param; if (i == 0 && (type == AST_REPLICATE || type == AST_WIRE)) const_fold_here = true, in_param_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)) @@ -1942,7 +1946,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, continue; buf = child->clone(); - while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } + while (buf->simplify(true, false, false, stage, width_hint, sign_hint, true)) { } if (buf->type != AST_CONSTANT) { // for (auto f : log_files) // dumpAst(f, "verilog-ast> "); diff --git a/tests/various/const_func.v b/tests/various/const_func.v new file mode 100644 index 00000000000..76cdc385dfb --- /dev/null +++ b/tests/various/const_func.v @@ -0,0 +1,75 @@ +module Example(outA, outB, outC, outD); + parameter OUTPUT = "FOO"; + output wire [23:0] outA; + output wire [23:0] outB; + output reg outC, outD; + function automatic [23:0] flip; + input [23:0] inp; + flip = ~inp; + endfunction + + generate + if (flip(OUTPUT) == flip("BAR")) + assign outA = OUTPUT; + else + assign outA = 0; + + case (flip(OUTPUT)) + flip("FOO"): assign outB = OUTPUT; + flip("BAR"): assign outB = 0; + flip("BAZ"): assign outB = "HI"; + endcase + + genvar i; + initial outC = 0; + for (i = 0; i != flip(flip(OUTPUT[15:8])); i = i + 1) + if (i + 1 == flip(flip("O"))) + initial outC = 1; + endgenerate + + integer j; + initial begin + outD = 1; + for (j = 0; j != flip(flip(OUTPUT[15:8])); j = j + 1) + if (j + 1 == flip(flip("O"))) + outD = 0; + end +endmodule + +module top(out); + wire [23:0] a1, a2, a3, a4; + wire [23:0] b1, b2, b3, b4; + wire c1, c2, c3, c4; + wire d1, d2, d3, d4; + Example e1(a1, b1, c1, d1); + Example #("FOO") e2(a2, b2, c2, d2); + Example #("BAR") e3(a3, b3, c3, d3); + Example #("BAZ") e4(a4, b4, c4, d4); + + output wire [24 * 8 - 1 + 4 :0] out; + assign out = { + a1, a2, a3, a4, + b1, b2, b3, b4, + c1, c2, c3, c4, + d1, d2, d3, d4}; + +// `define VERIFY +`ifdef VERIFY + assert property (a1 == 0); + assert property (a2 == 0); + assert property (a3 == "BAR"); + assert property (a4 == 0); + assert property (b1 == "FOO"); + assert property (b2 == "FOO"); + assert property (b3 == 0); + assert property (b4 == "HI"); + assert property (c1 == 1); + assert property (c2 == 1); + assert property (c3 == 0); + assert property (c4 == 0); + assert property (d1 == 0); + assert property (d2 == 0); + assert property (d3 == 1); + assert property (d4 == 1); +`endif +endmodule diff --git a/tests/various/const_func.ys b/tests/various/const_func.ys new file mode 100644 index 00000000000..5e3c0410522 --- /dev/null +++ b/tests/various/const_func.ys @@ -0,0 +1 @@ +read_verilog const_func.v From f544a2cc84f8ec20ad1d86208788bdd8cebcc284 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Tue, 30 Jun 2020 01:53:21 +0000 Subject: [PATCH 015/287] qbfsat: Fix name-based hole specialization. Look for unique connections in the containing module with the $anyconst port Y SigBit on the RHS and use those. If no such connection is found, fall back to using the name of the $anyconst port Y SigBit. --- passes/sat/qbfsat.cc | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/passes/sat/qbfsat.cc b/passes/sat/qbfsat.cc index f4624ab3bb7..fd69bfc0b07 100644 --- a/passes/sat/qbfsat.cc +++ b/passes/sat/qbfsat.cc @@ -147,6 +147,9 @@ void recover_solution(QbfSolutionType &sol) { dict, int>, RTLIL::SigBit> get_hole_loc_idx_sigbit_map(RTLIL::Module *module, const QbfSolutionType &sol) { dict, int>, RTLIL::SigBit> hole_loc_idx_to_sigbit; + pool anyconst_sigbits; + dict anyconst_sigbit_to_wire_sigbit; + for (auto cell : module->cells()) { pool cell_src = cell->get_strpool_attribute(ID::src); auto pos = sol.hole_to_value.find(cell_src); @@ -154,10 +157,30 @@ dict, int>, RTLIL::SigBit> get_hole_loc_idx_sigbit_m RTLIL::SigSpec port_y = cell->getPort(ID::Y); for (int i = GetSize(port_y) - 1; i >= 0; --i) { hole_loc_idx_to_sigbit[std::make_pair(pos->first, i)] = port_y[i]; + anyconst_sigbits.insert(port_y[i]); } } } + for (auto &conn : module->connections()) { + auto lhs = conn.first; + auto rhs = conn.second; + for (auto i = 0; i < GetSize(rhs); ++i) { + if (anyconst_sigbits[rhs[i]]) { + auto pos = anyconst_sigbit_to_wire_sigbit.find(rhs[i]); + if (pos != anyconst_sigbit_to_wire_sigbit.end()) + log_cmd_error("conflicting names for hole $anyconst sigbit %s\n", log_signal(rhs[i])); + anyconst_sigbit_to_wire_sigbit[rhs[i]] = lhs[i]; + } + } + } + + for (auto &it : hole_loc_idx_to_sigbit) { + auto pos = anyconst_sigbit_to_wire_sigbit.find(it.second); + if (pos != anyconst_sigbit_to_wire_sigbit.end()) + it.second = pos->second; + } + return hole_loc_idx_to_sigbit; } @@ -274,8 +297,7 @@ void specialize_from_file(RTLIL::Module *module, const std::string &file) { pool hole_loc_pool(locs.begin(), locs.end()); auto hole_cell_it = anyconst_loc_to_cell.find(hole_loc_pool); if (hole_cell_it == anyconst_loc_to_cell.end()) - YS_DEBUGTRAP; - //log_cmd_error("cannot find matching wire name or $anyconst cell location for hole spec \"%s\"\n", buf.c_str()); + log_cmd_error("cannot find matching wire name or $anyconst cell location for hole spec \"%s\"\n", buf.c_str()); RTLIL::Cell *hole_cell = hole_cell_it->second; hole_sigbit = hole_cell->getPort(ID::Y)[hole_bit]; From 83c595aaacb9617aa00439626f2ea5bf9777c7e9 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Tue, 30 Jun 2020 05:47:03 +0000 Subject: [PATCH 016/287] qbfsat: Add `-O[012]` options to control pre-solving simplification with ABC. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks to @mwk for the gate mapping part of the ABC scripts. Co-Authored-By: Marcelina Koƛcielnicka --- passes/sat/qbfsat.cc | 63 +++++++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/passes/sat/qbfsat.cc b/passes/sat/qbfsat.cc index f4624ab3bb7..6cf25518477 100644 --- a/passes/sat/qbfsat.cc +++ b/passes/sat/qbfsat.cc @@ -51,6 +51,7 @@ struct QbfSolveOptions { bool nooptimize, nobisection; bool sat, unsat, show_smtbmc; enum Solver{Z3, Yices, CVC4} solver; + enum OptimizationLevel{O0, O1, O2} oflag; int timeout; std::string specialize_soln_file; std::string write_soln_soln_file; @@ -59,7 +60,7 @@ struct QbfSolveOptions { QbfSolveOptions() : specialize(false), specialize_from_file(false), write_solution(false), nocleanup(false), dump_final_smt2(false), assume_outputs(false), assume_neg(false), nooptimize(false), nobisection(false), sat(false), unsat(false), show_smtbmc(false), - solver(Yices), timeout(0), argidx(0) {}; + solver(Yices), oflag(O0), timeout(0), argidx(0) {}; }; std::string get_solver_name(const QbfSolveOptions &opt) { @@ -438,8 +439,7 @@ QbfSolutionType qbf_solve(RTLIL::Module *mod, const QbfSolveOptions &opt) { RTLIL::Module *module = mod; RTLIL::Design *design = module->design; std::string module_name = module->name.str(); - RTLIL::Wire *wire_to_optimize = nullptr; - RTLIL::IdString wire_to_optimize_name; + RTLIL::IdString wire_to_optimize_name = ""; bool maximize = false; log_assert(module->design != nullptr); @@ -452,19 +452,30 @@ QbfSolutionType qbf_solve(RTLIL::Module *mod, const QbfSolveOptions &opt) { assume_miter_outputs(module, opt); //Find the wire to be optimized, if any: - for (auto wire : module->wires()) - if (wire->get_bool_attribute("\\maximize") || wire->get_bool_attribute("\\minimize")) - wire_to_optimize = wire; - if (wire_to_optimize != nullptr) { - wire_to_optimize_name = wire_to_optimize->name; - maximize = wire_to_optimize->get_bool_attribute("\\maximize"); + for (auto wire : module->wires()) { + if (wire->get_bool_attribute("\\maximize") || wire->get_bool_attribute("\\minimize")) { + wire_to_optimize_name = wire->name; + maximize = wire->get_bool_attribute("\\maximize"); + if (opt.nooptimize) { + if (maximize) + wire->set_bool_attribute("\\maximize", false); + else + wire->set_bool_attribute("\\minimize", false); + } + } } - if (opt.nobisection || opt.nooptimize || wire_to_optimize == nullptr) { - if (wire_to_optimize != nullptr && opt.nooptimize) { - wire_to_optimize->set_bool_attribute("\\maximize", false); - wire_to_optimize->set_bool_attribute("\\minimize", false); - } + //If -O1 or -O2 was specified, use ABC to simplify the problem: + if (opt.oflag == opt.OptimizationLevel::O1) + Pass::call(module->design, "abc -g AND,NAND,OR,NOR,XOR,XNOR,MUX,NMUX -script +print_stats;strash;print_stats;drwsat;print_stats;fraig;print_stats;refactor,-N,10,-lz;print_stats;&get,-n;&dch,-pem;&nf;&put " + mod->name.str()); + else if (opt.oflag == opt.OptimizationLevel::O2) + Pass::call(module->design, "abc -g AND,NAND,OR,NOR,XOR,XNOR,MUX,NMUX -script +print_stats;strash;print_stats;drwsat;print_stats;dch,-S,1000000,-C,100000,-p;print_stats;fraig;print_stats;refactor,-N,15,-lz;print_stats;dc2,-pbl;print_stats;drwsat;print_stats;&get,-n;&dch,-pem;&nf;&put " + mod->name.str()); + if (opt.oflag != opt.OptimizationLevel::O0) { + Pass::call(module->design, "techmap"); + Pass::call(module->design, "opt"); + } + + if (opt.nobisection || opt.nooptimize || wire_to_optimize_name == "") { ret = call_qbf_solver(module, opt, tempdir_name, false, 0); } else { //Do the iterated bisection method: @@ -473,8 +484,9 @@ QbfSolutionType qbf_solve(RTLIL::Module *mod, const QbfSolveOptions &opt) { unsigned int failure = 0; unsigned int cur_thresh = 0; - log_assert(wire_to_optimize != nullptr); - log("%s wire \"%s\".\n", (maximize? "Maximizing" : "Minimizing"), log_signal(wire_to_optimize)); + log_assert(wire_to_optimize_name != ""); + log_assert(module->wire(wire_to_optimize_name) != nullptr); + log("%s wire \"%s\".\n", (maximize? "Maximizing" : "Minimizing"), wire_to_optimize_name.c_str()); //If maximizing, grow until we get a failure. Then bisect success and failure. while (failure == 0 || difference(success, failure) > 1) { @@ -607,6 +619,22 @@ QbfSolveOptions parse_args(const std::vector &args) { } continue; } + else if (args[opt.argidx].substr(0, 2) == "-O" && args[opt.argidx].size() == 3) { + switch (args[opt.argidx][2]) { + case '0': + opt.oflag = opt.OptimizationLevel::O0; + break; + case '1': + opt.oflag = opt.OptimizationLevel::O1; + break; + case '2': + opt.oflag = opt.OptimizationLevel::O2; + break; + default: + log_cmd_error("unknown argument %s\n", args[opt.argidx].c_str()); + } + continue; + } else if (args[opt.argidx] == "-sat") { opt.sat = true; continue; @@ -721,6 +749,9 @@ struct QbfSatPass : public Pass { log(" -timeout \n"); log(" Set the per-iteration timeout in seconds.\n"); log("\n"); + log(" -O0, -O1, -O2\n"); + log(" Control the use of ABC to simplify the QBF-SAT problem before solving.\n"); + log("\n"); log(" -sat\n"); log(" Generate an error if the solver does not return \"sat\".\n"); log("\n"); From 561890c4e85932b89cb1043a0767dcec6da5993c Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 30 Jun 2020 12:13:13 +0200 Subject: [PATCH 017/287] Update verific API version check --- 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 ccd13e92f7c..9785b8eff9c 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -53,7 +53,7 @@ USING_YOSYS_NAMESPACE # error "Only Symbiotic EDA flavored Verific is supported. Please contact office@symbioticeda.com for commercial support for Yosys+Verific." #endif -#if SYMBIOTIC_VERIFIC_API_VERSION < 1 +#if SYMBIOTIC_VERIFIC_API_VERSION < 202006 # error "Please update your version of Symbiotic EDA flavored Verific." #endif From 817ae04ee0c445efaf83e9847d4956f2dae0d857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Tue, 30 Jun 2020 15:31:12 +0200 Subject: [PATCH 018/287] simcells: Fix reset polarity for $_DLATCH_???_ cells. --- techlibs/common/gen_fine_ffs.py | 2 +- techlibs/common/simcells.v | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/techlibs/common/gen_fine_ffs.py b/techlibs/common/gen_fine_ffs.py index e92d58f40ef..5d331e76746 100644 --- a/techlibs/common/gen_fine_ffs.py +++ b/techlibs/common/gen_fine_ffs.py @@ -300,7 +300,7 @@ input E, R, D; output reg Q; always @* begin - if (R == {E:0|1}) + if (R == {R:0|1}) Q <= {V:0|1}; else if (E == {E:0|1}) Q <= D; diff --git a/techlibs/common/simcells.v b/techlibs/common/simcells.v index 01b5bdfa69c..27ef442327c 100644 --- a/techlibs/common/simcells.v +++ b/techlibs/common/simcells.v @@ -2986,7 +2986,7 @@ module \$_DLATCH_NP0_ (E, R, D, Q); input E, R, D; output reg Q; always @* begin - if (R == 0) + if (R == 1) Q <= 0; else if (E == 0) Q <= D; @@ -3009,7 +3009,7 @@ module \$_DLATCH_NP1_ (E, R, D, Q); input E, R, D; output reg Q; always @* begin - if (R == 0) + if (R == 1) Q <= 1; else if (E == 0) Q <= D; @@ -3032,7 +3032,7 @@ module \$_DLATCH_PN0_ (E, R, D, Q); input E, R, D; output reg Q; always @* begin - if (R == 1) + if (R == 0) Q <= 0; else if (E == 1) Q <= D; @@ -3055,7 +3055,7 @@ module \$_DLATCH_PN1_ (E, R, D, Q); input E, R, D; output reg Q; always @* begin - if (R == 1) + if (R == 0) Q <= 1; else if (E == 1) Q <= D; From 77b15dd8e9262f5db6a8154f7ad75a2540e58c60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Tue, 30 Jun 2020 20:57:35 +0200 Subject: [PATCH 019/287] opt_merge: use the master FF type list --- passes/opt/opt_merge.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index a95aa74c19b..f03faa9cf36 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -298,9 +298,7 @@ struct OptMergeWorker module->connect(RTLIL::SigSig(it.second, other_sig)); assign_map.add(it.second, other_sig); - if (it.first == ID::Q && (cell->type.begins_with("$dff") || cell->type.begins_with("$dlatch") || - cell->type.begins_with("$_DFF") || cell->type.begins_with("$_DLATCH") || cell->type.begins_with("$_SR_") || - cell->type.in(ID($adff), ID($sr), ID($ff), ID($_FF_)))) { + if (it.first == ID::Q && RTLIL::builtin_ff_cell_types().count(cell->type)) { for (auto c : it.second.chunks()) { auto jt = c.wire->attributes.find(ID::init); if (jt == c.wire->attributes.end()) From 7c91f13f51c6c93dbece0eed91977241b7c346df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Tue, 30 Jun 2020 21:07:17 +0200 Subject: [PATCH 020/287] fmcombine: use the master ff cell type list --- passes/sat/fmcombine.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/passes/sat/fmcombine.cc b/passes/sat/fmcombine.cc index 5694a7473dd..cb49edac3c2 100644 --- a/passes/sat/fmcombine.cc +++ b/passes/sat/fmcombine.cc @@ -114,8 +114,7 @@ struct FmcombineWorker Cell *gold = import_prim_cell(cell, "_gold"); Cell *gate = import_prim_cell(cell, "_gate"); if (opts.initeq) { - if (cell->type.in(ID($ff), ID($dff), ID($dffe), - ID($dffsr), ID($adff), ID($dlatch), ID($dlatchsr))) { + if (RTLIL::builtin_ff_cell_types().count(cell->type)) { SigSpec gold_q = gold->getPort(ID::Q); SigSpec gate_q = gate->getPort(ID::Q); SigSpec en = module->Initstate(NEW_ID); From e3564b4502b05f58e6e9d9fc96603dd8a5a0b2d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Tue, 23 Jun 2020 14:36:34 +0200 Subject: [PATCH 021/287] Add dfflegalize pass. --- CHANGELOG | 2 + passes/techmap/Makefile.inc | 1 + passes/techmap/dfflegalize.cc | 1356 +++++++++++++++++++++++++++++++++ 3 files changed, 1359 insertions(+) create mode 100644 passes/techmap/dfflegalize.cc diff --git a/CHANGELOG b/CHANGELOG index 638ce558bfb..12fc8855073 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -67,6 +67,8 @@ Yosys 0.9 .. Yosys 0.9-dev - Added "select -unset" - Use YosysHQ/abc instead of upstream berkeley-abc/abc - Added $divfloor and $modfloor cells + - Added $adffe, $dffsre, $sdff, $sdffe, $sdffce, $adlatch cells + - Added "dfflegalize" pass Yosys 0.8 .. Yosys 0.9 ---------------------- diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index a54b4913d6e..e3b3d8dea11 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -41,6 +41,7 @@ OBJS += passes/techmap/insbuf.o OBJS += passes/techmap/attrmvcp.o OBJS += passes/techmap/attrmap.o OBJS += passes/techmap/zinit.o +OBJS += passes/techmap/dfflegalize.o OBJS += passes/techmap/dff2dffs.o OBJS += passes/techmap/flowmap.o OBJS += passes/techmap/extractinv.o diff --git a/passes/techmap/dfflegalize.cc b/passes/techmap/dfflegalize.cc new file mode 100644 index 00000000000..013f2d9741e --- /dev/null +++ b/passes/techmap/dfflegalize.cc @@ -0,0 +1,1356 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2020 Marcelina Koƛcielnicka + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +enum FfType { + FF_DFF, + FF_DFFE, + FF_ADFF0, + FF_ADFF1, + FF_ADFFE0, + FF_ADFFE1, + FF_DFFSR, + FF_DFFSRE, + FF_SDFF0, + FF_SDFF1, + FF_SDFFE0, + FF_SDFFE1, + FF_SDFFCE0, + FF_SDFFCE1, + FF_SR, + FF_DLATCH, + FF_ADLATCH0, + FF_ADLATCH1, + FF_DLATCHSR, + NUM_FFTYPES, +}; + +enum FfNeg { + NEG_R = 0x1, + NEG_S = 0x2, + NEG_E = 0x4, + NEG_C = 0x8, + NUM_NEG = 0x10, +}; + +enum FfInit { + INIT_X = 0x1, + INIT_0 = 0x2, + INIT_1 = 0x4, +}; + +struct DffLegalizePass : public Pass { + DffLegalizePass() : Pass("dfflegalize", "convert FFs to types supported by the target") { } + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" dfflegalize [options] [selection]\n"); + log("\n"); + log("Converts FFs to types supported by the target.\n"); + log("\n"); + log(" -cell \n"); + log(" specifies a supported group of FF cells. \n"); + log(" is a yosys internal fine cell name, where ? characters can be\n"); + log(" as a wildcard matching any character. specifies\n"); + log(" which initialization values these FF cells can support, and can\n"); + log(" be one of:\n"); + log("\n"); + log(" - x (no init value supported)\n"); + log(" - 0\n"); + log(" - 1\n"); + log(" - r (init value has to match reset value, only for some FF types)\n"); + log(" - 01 (both 0 and 1 supported).\n"); + log("\n"); + log(" -mince \n"); + log(" specifies a minimum number of FFs that should be using any given\n"); + log(" clock enable signal. If a clock enable signal doesn't meet this\n"); + log(" threshold, it is unmapped into soft logic.\n"); + log("\n"); + log(" -minsrst \n"); + log(" specifies a minimum number of FFs that should be using any given\n"); + log(" sync set/reset signal. If a sync set/reset signal doesn't meet this\n"); + log(" threshold, it is unmapped into soft logic.\n"); + log("\n"); + log("The following cells are supported by this pass (ie. will be ingested,\n"); + log("and can be specified as allowed targets):\n"); + log("\n"); + log("- $_DFF_[NP]_\n"); + log("- $_DFFE_[NP][NP]_\n"); + log("- $_DFF_[NP][NP][01]_\n"); + log("- $_DFFE_[NP][NP][01][NP]_\n"); + log("- $_DFFSR_[NP][NP][NP]_\n"); + log("- $_DFFSRE_[NP][NP][NP][NP]_\n"); + log("- $_SDFF_[NP][NP][01]_\n"); + log("- $_SDFFE_[NP][NP][01][NP]_\n"); + log("- $_SDFFCE_[NP][NP][01][NP]_\n"); + log("- $_SR_[NP][NP]_\n"); + log("- $_DLATCH_[NP]_\n"); + log("- $_DLATCH_[NP][NP][01]_\n"); + log("- $_DLATCHSR_[NP][NP][NP]_\n"); + log("\n"); + log("The following transformations are performed by this pass:"); + log(""); + log("- upconversion from a less capable cell to a more capable cell, if the less"); + log(" capable cell is not supported (eg. dff -> dffe, or adff -> dffsr)"); + log(""); + log("- unmapping FFs with clock enable (due to unsupported cell type or -mince)"); + log(""); + log("- unmapping FFs with sync reset (due to unsupported cell type or -minsrst)"); + log(""); + log("- adding inverters on the control pins (due to unsupported polarity)"); + log(""); + log("- adding inverters on the D and Q pins and inverting the init/reset values\n"); + log(" (due to unsupported init or reset value)"); + log(""); + log("- converting sr into adlatch (by tying D to 1 and using E as set input)"); + log(""); + log("- emulating unsupported dffsr cell by adff + adff + sr + mux"); + log(""); + log("- emulating unsupported dlatchsr cell by adlatch + adlatch + sr + mux"); + log(""); + log("- emulating adff when the (reset, init) value combination is unsupported by\n"); + log(" dff + adff + dlatch + mux"); + log(""); + log("- emulating adlatch when the (reset, init) value combination is unsupported by\n"); + log("- dlatch + adlatch + dlatch + mux"); + log(""); + log("If the pass is unable to realize a given cell type (eg. adff when only plain dff"); + log("is available), an error is raised."); + } + + // Table of all supported cell types. + // First index in the array is one of the FF_* values, second + // index is the set of negative-polarity inputs (OR of NEG_* + // values), and the value is the set of supported init values + // (OR of INIT_* values). + int supported_cells_neg[NUM_FFTYPES][NUM_NEG]; + // Aggregated table ignoring signal polarity. + int supported_cells[NUM_FFTYPES]; + // Aggregated for all *dff* cells. + int supported_dff; + // Aggregated for all dffsr* cells. + int supported_dffsr; + // Aggregated for all adff* cells. + int supported_adff0; + int supported_adff1; + // Aggregated for all sdff* cells. + int supported_sdff0; + int supported_sdff1; + // Aggregated for all ways to obtain a SR latch. + int supported_sr; + // Aggregated for all *dlatch* cells. + int supported_dlatch; + + int mince; + int minsrst; + + dict ce_used; + dict srst_used; + + SigMap sigmap; + dict> initbits; + + int flip_initmask(int mask) { + int res = mask & INIT_X; + if (mask & INIT_0) + res |= INIT_1; + if (mask & INIT_1) + res |= INIT_0; + return res; + } + + void handle_ff(Cell *cell) { + std::string type_str = cell->type.str(); + + FfType ff_type; + int ff_neg = 0; + SigSpec sig_d; + SigSpec sig_q; + SigSpec sig_c; + SigSpec sig_e; + SigSpec sig_r; + SigSpec sig_s; + bool has_srst = false; + + if (cell->hasPort(ID::D)) + sig_d = cell->getPort(ID::D); + if (cell->hasPort(ID::Q)) + sig_q = cell->getPort(ID::Q); + if (cell->hasPort(ID::C)) + sig_c = cell->getPort(ID::C); + if (cell->hasPort(ID::E)) + sig_e = cell->getPort(ID::E); + if (cell->hasPort(ID::R)) + sig_r = cell->getPort(ID::R); + if (cell->hasPort(ID::S)) + sig_s = cell->getPort(ID::S); + + if (type_str.substr(0, 5) == "$_SR_") { + ff_type = FF_SR; + if (type_str[5] == 'N') + ff_neg |= NEG_S; + if (type_str[6] == 'N') + ff_neg |= NEG_R; + } else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 8) { + ff_type = FF_DFF; + if (type_str[6] == 'N') + ff_neg |= NEG_C; + } else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 10) { + ff_type = FF_DFFE; + if (type_str[7] == 'N') + ff_neg |= NEG_C; + if (type_str[8] == 'N') + ff_neg |= NEG_E; + } else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 10) { + ff_type = type_str[8] == '1' ? FF_ADFF1 : FF_ADFF0; + if (type_str[6] == 'N') + ff_neg |= NEG_C; + if (type_str[7] == 'N') + ff_neg |= NEG_R; + } else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 12) { + ff_type = type_str[9] == '1' ? FF_ADFFE1 : FF_ADFFE0; + if (type_str[7] == 'N') + ff_neg |= NEG_C; + if (type_str[8] == 'N') + ff_neg |= NEG_R; + if (type_str[10] == 'N') + ff_neg |= NEG_E; + } else if (type_str.substr(0, 8) == "$_DFFSR_" && type_str.size() == 12) { + ff_type = FF_DFFSR; + if (type_str[8] == 'N') + ff_neg |= NEG_C; + if (type_str[9] == 'N') + ff_neg |= NEG_S; + if (type_str[10] == 'N') + ff_neg |= NEG_R; + } else if (type_str.substr(0, 9) == "$_DFFSRE_" && type_str.size() == 14) { + ff_type = FF_DFFSRE; + if (type_str[9] == 'N') + ff_neg |= NEG_C; + if (type_str[10] == 'N') + ff_neg |= NEG_S; + if (type_str[11] == 'N') + ff_neg |= NEG_R; + if (type_str[12] == 'N') + ff_neg |= NEG_E; + } else if (type_str.substr(0, 7) == "$_SDFF_" && type_str.size() == 11) { + ff_type = type_str[9] == '1' ? FF_SDFF1 : FF_SDFF0; + if (type_str[7] == 'N') + ff_neg |= NEG_C; + if (type_str[8] == 'N') + ff_neg |= NEG_R; + has_srst = true; + } else if (type_str.substr(0, 8) == "$_SDFFE_" && type_str.size() == 13) { + ff_type = type_str[10] == '1' ? FF_SDFFE1 : FF_SDFFE0; + if (type_str[8] == 'N') + ff_neg |= NEG_C; + if (type_str[9] == 'N') + ff_neg |= NEG_R; + if (type_str[11] == 'N') + ff_neg |= NEG_E; + has_srst = true; + } else if (type_str.substr(0, 9) == "$_SDFFCE_" && type_str.size() == 14) { + ff_type = type_str[11] == '1' ? FF_SDFFCE1 : FF_SDFFCE0; + if (type_str[9] == 'N') + ff_neg |= NEG_C; + if (type_str[10] == 'N') + ff_neg |= NEG_R; + if (type_str[12] == 'N') + ff_neg |= NEG_E; + has_srst = true; + } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 11) { + ff_type = FF_DLATCH; + if (type_str[9] == 'N') + ff_neg |= NEG_E; + } else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 13) { + ff_type = type_str[11] == '1' ? FF_ADLATCH1 : FF_ADLATCH0; + if (type_str[9] == 'N') + ff_neg |= NEG_E; + if (type_str[10] == 'N') + ff_neg |= NEG_R; + } else if (type_str.substr(0, 11) == "$_DLATCHSR_" && type_str.size() == 15) { + ff_type = FF_DLATCHSR; + if (type_str[11] == 'N') + ff_neg |= NEG_E; + if (type_str[12] == 'N') + ff_neg |= NEG_S; + if (type_str[13] == 'N') + ff_neg |= NEG_R; + } else { + log_warning("Ignoring unknown ff type %s [%s.%s].\n", log_id(cell->type), log_id(cell->module->name), log_id(cell->name)); + return; + } + + State initval = State::Sx; + SigBit initbit; + if (GetSize(sig_q) > 0 && initbits.count(sigmap(sig_q[0]))) { + const auto &d = initbits.at(sigmap(sig_q[0])); + initval = d.first; + initbit = d.second; + } + + FfInit initmask = INIT_X; + if (initval == State::S0) + initmask = INIT_0; + else if (initval == State::S1) + initmask = INIT_1; + const char *reason; + + bool kill_ce = mince && GetSize(sig_c) && GetSize(sig_e) && sig_e[0].wire && ce_used[sig_e[0]] < mince; + bool kill_srst = minsrst && has_srst && sig_r[0].wire && srst_used[sig_r[0]] < minsrst; + + while (!(supported_cells[ff_type] & initmask) || kill_ce || kill_srst) { + // Well, cell is not directly supported. Decide how to deal with it. + + if (ff_type == FF_DFF || ff_type == FF_DFFE) { + if (kill_ce) { + ff_type = FF_DFF; + goto unmap_enable; + } + if (!(supported_dff & initmask)) { + // This init value is not supported at all... + if (supported_dff & flip_initmask(initmask)) { + // The other one is, though. Negate D, Q, and init. +flip_dqi: + if (initval == State::S0) { + initval = State::S1; + initmask = INIT_1; + } else if (initval == State::S1) { + initval = State::S0; + initmask = INIT_0; + } + if (ff_type != FF_SR) + sig_d = cell->module->NotGate(NEW_ID, sig_d[0]); + SigBit new_q = SigSpec(cell->module->addWire(NEW_ID))[0]; + cell->module->addNotGate(NEW_ID, new_q, sig_q[0]); + if (initbit.wire) { + initbit.wire->attributes.at(ID::init)[initbit.offset] = State::Sx; + initbit = new_q; + new_q.wire->attributes[ID::init] = initval; + initbits[new_q] = std::make_pair(initval, new_q); + } + sig_q = new_q; + continue; + } + if (!supported_dff) + reason = "dffs are not supported"; + else + reason = "initialized dffs are not supported"; + goto error; + } + + // Some DFF is supported with this init val. Just pick a type. + if (ff_type == FF_DFF) { + // Try adding a set or reset pin. + for (auto new_type: {FF_ADFF0, FF_ADFF1, FF_SDFF0, FF_SDFF1}) + if (supported_cells[new_type] & initmask) { + ff_type = new_type; + sig_r = State::S0; + goto cell_ok; + } + // Try adding both. + if (supported_cells[FF_DFFSR] & initmask) { + ff_type = FF_DFFSR; + sig_r = State::S0; + sig_s = State::S0; + break; + } + // Nope. Will need to add enable and go the DFFE route. + sig_e = State::S1; + if (supported_cells[FF_DFFE] & initmask) { + ff_type = FF_DFFE; + break; + } + } + // Try adding a set or reset pin. + for (auto new_type: {FF_SDFFE0, FF_SDFFE1, FF_SDFFCE0, FF_SDFFCE1, FF_ADFFE0, FF_ADFFE1}) + if (supported_cells[new_type] & initmask) { + ff_type = new_type; + sig_r = State::S0; + goto cell_ok; + } + // Try adding both. + if (supported_cells[FF_DFFSRE] & initmask) { + ff_type = FF_DFFSRE; + sig_r = State::S0; + sig_s = State::S0; + break; + } + + // Seems that no DFFs with enable are supported. + // The enable input needs to be unmapped. + // This should not be reached if we started from plain DFF. + log_assert(ff_type == FF_DFFE); + ff_type = FF_DFF; +unmap_enable: + if (ff_neg & NEG_E) + sig_d = cell->module->MuxGate(NEW_ID, sig_d[0], sig_q[0], sig_e[0]); + else + sig_d = cell->module->MuxGate(NEW_ID, sig_q[0], sig_d[0], sig_e[0]); + ff_neg &= ~NEG_E; + sig_e = SigSpec(); + kill_ce = false; + // Now try again as plain DFF. + continue; + } else if (ff_type == FF_ADFF0 || ff_type == FF_ADFF1 || ff_type == FF_ADFFE0 || ff_type == FF_ADFFE1) { + bool has_set = ff_type == FF_ADFF1 || ff_type == FF_ADFFE1; + bool has_en = ff_type == FF_ADFFE0 || ff_type == FF_ADFFE1; + if (kill_ce) { + ff_type = has_set ? FF_ADFF1 : FF_ADFF0; + goto unmap_enable; + } + if (!has_en && (supported_cells[has_set ? FF_ADFFE1 : FF_ADFFE0] & initmask)) { + // Just add enable. + sig_e = State::S1; + ff_type = has_set ? FF_ADFFE1 : FF_ADFFE0; + break; + } + if (supported_dffsr & initmask) { + // Throw in a set/reset, retry in DFFSR/DFFSRE branch. + if (has_set) { + sig_s = sig_r; + sig_r = State::S0; + if (ff_neg & NEG_R) { + ff_neg &= ~NEG_R; + ff_neg |= NEG_S; + } + } else { + sig_s = State::S0; + } + if (has_en) + ff_type = FF_DFFSRE; + else + ff_type = FF_DFFSR; + continue; + } + if (has_en && (supported_cells[has_set ? FF_ADFF1 : FF_ADFF0] & initmask)) { + // Unmap enable. + ff_type = has_set ? FF_ADFF1 : FF_ADFF0; + goto unmap_enable; + } + log_assert(!((has_set ? supported_adff1 : supported_adff0) & initmask)); + // Alright, so this particular combination of initval and + // resetval is not natively supported. First, try flipping + // them both to see whether this helps. + int flipmask = flip_initmask(initmask); + if ((has_set ? supported_adff0 : supported_adff1) & flipmask) { + // Checks out, do it. + ff_type = has_en ? (has_set ? FF_ADFFE0 : FF_ADFFE1) : (has_set ? FF_ADFF0 : FF_ADFF1); + goto flip_dqi; + } + + if (!supported_adff0 && !supported_adff1) { + reason = "dffs with async set or reset are not supported"; + goto error; + } + if (!(supported_dff & ~INIT_X)) { + reason = "initialized dffs are not supported"; + goto error; + } + // If we got here, initialized dff is supported, but not this + // particular reset+init combination (nor its negation). + // The only hope left is breaking down to adff + dff + dlatch + mux. + if (!(supported_dlatch & ~INIT_X)) { + reason = "unsupported initial value and async reset value combination"; + goto error; + } + + // If we have to unmap enable anyway, do it before breakdown. + if (has_en && !supported_cells[FF_ADFFE0] && !supported_cells[FF_ADFFE1]) { + ff_type = has_set ? FF_ADFF1 : FF_ADFF0; + goto unmap_enable; + } + + log_warning("Emulating mismatched async reset and init with several FFs and a mux for %s.%s\n", log_id(cell->module->name), log_id(cell->name)); + if (initbit.wire) + initbit.wire->attributes.at(ID::init)[initbit.offset] = State::Sx; + Wire *adff_q = cell->module->addWire(NEW_ID); + Wire *dff_q = cell->module->addWire(NEW_ID); + Wire *sel_q = cell->module->addWire(NEW_ID); + dff_q->attributes[ID::init] = initval; + initbits[SigBit(dff_q, 0)] = std::make_pair(initval, SigBit(dff_q, 0)); + sel_q->attributes[ID::init] = State::S0; + initbits[SigBit(sel_q, 0)] = std::make_pair(State::S0, SigBit(sel_q, 0)); + Cell *cell_dff; + Cell *cell_adff; + Cell *cell_sel; + if (!has_en) { + cell_dff = cell->module->addDffGate(NEW_ID, sig_c, sig_d, dff_q, !(ff_neg & NEG_C)); + cell_adff = cell->module->addAdffGate(NEW_ID, sig_c, sig_r, sig_d, adff_q, has_set, !(ff_neg & NEG_C), !(ff_neg & NEG_R)); + } else { + cell_dff = cell->module->addDffeGate(NEW_ID, sig_c, sig_e, sig_d, dff_q, !(ff_neg & NEG_C), !(ff_neg & NEG_E)); + cell_adff = cell->module->addAdffeGate(NEW_ID, sig_c, sig_e, sig_r, sig_d, adff_q, has_set, !(ff_neg & NEG_C), !(ff_neg & NEG_E), !(ff_neg & NEG_R)); + } + cell_sel = cell->module->addDlatchGate(NEW_ID, sig_r, State::S1, sel_q, !(ff_neg & NEG_R)); + cell->module->addMuxGate(NEW_ID, dff_q, adff_q, sel_q, sig_q); + + // Bye, cell. + cell->module->remove(cell); + handle_ff(cell_dff); + handle_ff(cell_adff); + handle_ff(cell_sel); + return; + } else if (ff_type == FF_DFFSR || ff_type == FF_DFFSRE) { + if (kill_ce) { + ff_type = FF_DFFSR; + goto unmap_enable; + } + // First, see if mapping/unmapping enable will help. + if (supported_cells[FF_DFFSRE] & initmask) { + ff_type = FF_DFFSRE; + sig_e = State::S1; + break; + } + if (supported_cells[FF_DFFSR] & initmask) { + ff_type = FF_DFFSR; + goto unmap_enable; + } + if (supported_dffsr & flip_initmask(initmask)) { +flip_dqisr:; + log_warning("Flipping D/Q/init and inseerting set/reset fixup to handle init value on %s.%s [%s]\n", log_id(cell->module->name), log_id(cell->name), log_id(cell->type)); + SigSpec new_r; + bool neg_r = (ff_neg & NEG_R); + bool neg_s = (ff_neg & NEG_S); + if (!(ff_neg & NEG_S)) { + if (!(ff_neg & NEG_R)) + new_r = cell->module->AndnotGate(NEW_ID, sig_s, sig_r); + else + new_r = cell->module->AndGate(NEW_ID, sig_s, sig_r); + } else { + if (!(ff_neg & NEG_R)) + new_r = cell->module->OrGate(NEW_ID, sig_s, sig_r); + else + new_r = cell->module->OrnotGate(NEW_ID, sig_s, sig_r); + } + ff_neg &= ~(NEG_R | NEG_S); + if (neg_r) + ff_neg |= NEG_S; + if (neg_s) + ff_neg |= NEG_R; + sig_s = sig_r; + sig_r = new_r; + goto flip_dqi; + } + // No native DFFSR. However, if we can conjure + // a SR latch and ADFF, it can still be emulated. + int flipmask = flip_initmask(initmask); + bool init0 = true; + bool init1 = true; + State initsel = State::Sx; + if (((supported_adff0 & initmask) || (supported_adff1 & flipmask)) && ((supported_adff1 & initmask) || (supported_adff0 & flipmask)) && supported_sr) { + // OK + } else if (((supported_adff0 & initmask) || (supported_adff1 & flipmask)) && (supported_sr & INIT_0)) { + init1 = false; + initsel = State::S0; + } else if (((supported_adff1 & initmask) || (supported_adff0 & flipmask)) && (supported_sr & INIT_1)) { + init0 = false; + initsel = State::S1; + } else if (((supported_adff0 & initmask) || (supported_adff1 & flipmask)) && (supported_sr & INIT_1)) { + init1 = false; + initsel = State::S0; + } else if (((supported_adff1 & initmask) || (supported_adff0 & flipmask)) && (supported_sr & INIT_0)) { + init0 = false; + initsel = State::S1; + } else { + if (!supported_dffsr) + reason = "dffs with async set and reset are not supported"; + else + reason = "initialized dffs with async set and reset are not supported"; + goto error; + } + + // If we have to unmap enable anyway, do it before breakdown. + if (ff_type == FF_DFFSRE && !supported_cells[FF_ADFFE0] && !supported_cells[FF_ADFFE1]) { + ff_type = FF_DFFSR; + goto unmap_enable; + } + + log_warning("Emulating async set + reset with several FFs and a mux for %s.%s\n", log_id(cell->module->name), log_id(cell->name)); + if (initbit.wire) + initbit.wire->attributes.at(ID::init)[initbit.offset] = State::Sx; + Wire *adff0_q = cell->module->addWire(NEW_ID); + Wire *adff1_q = cell->module->addWire(NEW_ID); + Wire *sel_q = cell->module->addWire(NEW_ID); + if (init0) { + adff0_q->attributes[ID::init] = initval; + initbits[SigBit(adff0_q, 0)] = std::make_pair(initval, SigBit(adff0_q, 0)); + } + if (init1) { + adff1_q->attributes[ID::init] = initval; + initbits[SigBit(adff1_q, 0)] = std::make_pair(initval, SigBit(adff1_q, 0)); + } + sel_q->attributes[ID::init] = initsel; + initbits[SigBit(sel_q, 0)] = std::make_pair(initsel, SigBit(sel_q, 0)); + Cell *cell_adff0; + Cell *cell_adff1; + Cell *cell_sel; + if (ff_type == FF_DFFSR) { + cell_adff0 = cell->module->addAdffGate(NEW_ID, sig_c, sig_r, sig_d, adff0_q, false, !(ff_neg & NEG_C), !(ff_neg & NEG_R)); + cell_adff1 = cell->module->addAdffGate(NEW_ID, sig_c, sig_s, sig_d, adff1_q, true, !(ff_neg & NEG_C), !(ff_neg & NEG_S)); + } else { + cell_adff0 = cell->module->addAdffeGate(NEW_ID, sig_c, sig_e, sig_r, sig_d, adff0_q, false, !(ff_neg & NEG_C), !(ff_neg & NEG_E), !(ff_neg & NEG_R)); + cell_adff1 = cell->module->addAdffeGate(NEW_ID, sig_c, sig_e, sig_s, sig_d, adff1_q, true, !(ff_neg & NEG_C), !(ff_neg & NEG_E), !(ff_neg & NEG_S)); + } + cell_sel = cell->module->addSrGate(NEW_ID, sig_s, sig_r, sel_q, !(ff_neg & NEG_S), !(ff_neg & NEG_R)); + cell->module->addMuxGate(NEW_ID, adff0_q, adff1_q, sel_q, sig_q); + + // Bye, cell. + cell->module->remove(cell); + handle_ff(cell_adff0); + handle_ff(cell_adff1); + handle_ff(cell_sel); + return; + } else if (ff_type == FF_SR) { + if (supported_cells[FF_ADLATCH0] & initmask || supported_cells[FF_ADLATCH1] & flip_initmask(initmask)) { + // Convert to ADLATCH0. May get converted to ADLATCH1. + ff_type = FF_ADLATCH0; + sig_e = sig_s; + sig_d = State::S1; + if (ff_neg & NEG_S) { + ff_neg &= ~NEG_S; + ff_neg |= NEG_E; + } + continue; + } else if (supported_cells[FF_DLATCHSR] & initmask) { + // Upgrade to DLATCHSR. + ff_type = FF_DLATCHSR; + sig_e = State::S0; + sig_d = State::Sx; + break; + } else if (supported_dffsr & initmask) { + // Upgrade to DFFSR. May get further upgraded to DFFSRE. + ff_type = FF_DFFSR; + sig_c = State::S0; + sig_d = State::Sx; + continue; + } else if (supported_sr & flip_initmask(initmask)) { + goto flip_dqisr; + } else { + if (!supported_sr) + reason = "sr latches are not supported"; + else + reason = "initialized sr latches are not supported"; + goto error; + } + } else if (ff_type == FF_DLATCH) { + if (!(supported_dlatch & initmask)) { + // This init value is not supported at all... + if (supported_dlatch & flip_initmask(initmask)) + goto flip_dqi; + if (!supported_dlatch) + reason = "dlatch are not supported"; + else + reason = "initialized dlatch are not supported"; + goto error; + } + + // Some DLATCH is supported with this init val. Just pick a type. + if (supported_cells[FF_ADLATCH0] & initmask) { + ff_type = FF_ADLATCH0; + sig_r = State::S0; + break; + } + if (supported_cells[FF_ADLATCH1] & initmask) { + ff_type = FF_ADLATCH1; + sig_r = State::S0; + break; + } + if (supported_cells[FF_DLATCHSR] & initmask) { + ff_type = FF_DLATCHSR; + sig_r = State::S0; + sig_s = State::S0; + break; + } + log_assert(0); + } else if (ff_type == FF_ADLATCH0 || ff_type == FF_ADLATCH1) { + if (supported_cells[FF_DLATCHSR] & initmask) { + if (ff_type == FF_ADLATCH1) { + sig_s = sig_r; + sig_r = State::S0; + if (ff_neg & NEG_R) { + ff_neg &= ~NEG_R; + ff_neg |= NEG_S; + } + } else { + sig_s = State::S0; + } + ff_type = FF_DLATCHSR; + break; + } + FfType flip_type = ff_type == FF_ADLATCH0 ? FF_ADLATCH1 : FF_ADLATCH0; + if ((supported_cells[flip_type] | supported_cells[FF_DLATCHSR]) & flip_initmask(initmask)) { + ff_type = flip_type; + goto flip_dqi; + } + + if (!supported_cells[FF_ADLATCH0] && !supported_cells[FF_ADLATCH1] && !supported_cells[FF_DLATCHSR]) { + reason = "dlatch with async set or reset are not supported"; + goto error; + } + if (!(supported_dlatch & ~INIT_X)) { + reason = "initialized dlatch are not supported"; + goto error; + } + + if (!(supported_dlatch & ~INIT_X)) { + reason = "initialized dlatch are not supported"; + goto error; + } + // If we got here, initialized dlatch is supported, but not this + // particular reset+init combination (nor its negation). + // The only hope left is breaking down to adff + dff + dlatch + mux. + + log_warning("Emulating mismatched async reset and init with several latches and a mux for %s.%s\n", log_id(cell->module->name), log_id(cell->name)); + if (initbit.wire) + initbit.wire->attributes.at(ID::init)[initbit.offset] = State::Sx; + Wire *adlatch_q = cell->module->addWire(NEW_ID); + Wire *dlatch_q = cell->module->addWire(NEW_ID); + Wire *sel_q = cell->module->addWire(NEW_ID); + dlatch_q->attributes[ID::init] = initval; + initbits[SigBit(dlatch_q, 0)] = std::make_pair(initval, SigBit(dlatch_q, 0)); + sel_q->attributes[ID::init] = State::S0; + initbits[SigBit(sel_q, 0)] = std::make_pair(State::S0, SigBit(sel_q, 0)); + Cell *cell_dlatch; + Cell *cell_adlatch; + Cell *cell_sel; + cell_dlatch = cell->module->addDlatchGate(NEW_ID, sig_e, sig_d, dlatch_q, !(ff_neg & NEG_E)); + cell_adlatch = cell->module->addAdlatchGate(NEW_ID, sig_e, sig_r, sig_d, adlatch_q, ff_type == FF_ADLATCH1, !(ff_neg & NEG_E), !(ff_neg & NEG_R)); + cell_sel = cell->module->addDlatchGate(NEW_ID, sig_r, State::S1, sel_q, !(ff_neg & NEG_R)); + cell->module->addMuxGate(NEW_ID, dlatch_q, adlatch_q, sel_q, sig_q); + + // Bye, cell. + cell->module->remove(cell); + handle_ff(cell_dlatch); + handle_ff(cell_adlatch); + handle_ff(cell_sel); + return; + } else if (ff_type == FF_DLATCHSR) { + if (supported_cells[FF_DLATCHSR] & flip_initmask(initmask)) { + goto flip_dqisr; + } + // No native DFFSR. However, if we can conjure + // a SR latch and ADFF, it can still be emulated. + int flipmask = flip_initmask(initmask); + bool init0 = true; + bool init1 = true; + State initsel = State::Sx; + if (((supported_cells[FF_ADLATCH0] & initmask) || (supported_cells[FF_ADLATCH1] & flipmask)) && ((supported_cells[FF_ADLATCH1] & initmask) || (supported_cells[FF_ADLATCH0] & flipmask)) && supported_sr) { + // OK + } else if (((supported_cells[FF_ADLATCH0] & initmask) || (supported_cells[FF_ADLATCH1] & flipmask)) && (supported_sr & INIT_0)) { + init1 = false; + initsel = State::S0; + } else if (((supported_cells[FF_ADLATCH1] & initmask) || (supported_cells[FF_ADLATCH0] & flipmask)) && (supported_sr & INIT_1)) { + init0 = false; + initsel = State::S1; + } else if (((supported_cells[FF_ADLATCH0] & initmask) || (supported_cells[FF_ADLATCH1] & flipmask)) && (supported_sr & INIT_1)) { + init1 = false; + initsel = State::S0; + } else if (((supported_cells[FF_ADLATCH1] & initmask) || (supported_cells[FF_ADLATCH0] & flipmask)) && (supported_sr & INIT_0)) { + init0 = false; + initsel = State::S1; + } else { + if (!supported_cells[FF_DLATCHSR]) + reason = "dlatch with async set and reset are not supported"; + else + reason = "initialized dlatch with async set and reset are not supported"; + goto error; + } + + log_warning("Emulating async set + reset with several latches and a mux for %s.%s\n", log_id(cell->module->name), log_id(cell->name)); + if (initbit.wire) + initbit.wire->attributes.at(ID::init)[initbit.offset] = State::Sx; + Wire *adlatch0_q = cell->module->addWire(NEW_ID); + Wire *adlatch1_q = cell->module->addWire(NEW_ID); + Wire *sel_q = cell->module->addWire(NEW_ID); + if (init0) { + adlatch0_q->attributes[ID::init] = initval; + initbits[SigBit(adlatch0_q, 0)] = std::make_pair(initval, SigBit(adlatch0_q, 0)); + } + if (init1) { + adlatch1_q->attributes[ID::init] = initval; + initbits[SigBit(adlatch1_q, 0)] = std::make_pair(initval, SigBit(adlatch1_q, 0)); + } + sel_q->attributes[ID::init] = initsel; + initbits[SigBit(sel_q, 0)] = std::make_pair(initsel, SigBit(sel_q, 0)); + Cell *cell_adlatch0; + Cell *cell_adlatch1; + Cell *cell_sel; + cell_adlatch0 = cell->module->addAdlatchGate(NEW_ID, sig_e, sig_r, sig_d, adlatch0_q, false, !(ff_neg & NEG_E), !(ff_neg & NEG_R)); + cell_adlatch1 = cell->module->addAdlatchGate(NEW_ID, sig_e, sig_s, sig_d, adlatch1_q, true, !(ff_neg & NEG_E), !(ff_neg & NEG_S)); + cell_sel = cell->module->addSrGate(NEW_ID, sig_s, sig_r, sel_q, !(ff_neg & NEG_S), !(ff_neg & NEG_R)); + cell->module->addMuxGate(NEW_ID, adlatch0_q, adlatch1_q, sel_q, sig_q); + + // Bye, cell. + cell->module->remove(cell); + handle_ff(cell_adlatch0); + handle_ff(cell_adlatch1); + handle_ff(cell_sel); + return; + } else if (ff_type == FF_SDFF0 || ff_type == FF_SDFF1 || ff_type == FF_SDFFE0 || ff_type == FF_SDFFE1 || ff_type == FF_SDFFCE0 || ff_type == FF_SDFFCE1) { + bool has_set = ff_type == FF_SDFF1 || ff_type == FF_SDFFE1 || ff_type == FF_SDFFCE1; + bool has_en = ff_type == FF_SDFFE0 || ff_type == FF_SDFFE1; + bool has_ce = ff_type == FF_SDFFCE0 || ff_type == FF_SDFFCE1; + + if (has_en) { + if (kill_ce || kill_srst) { + ff_type = has_set ? FF_SDFF1 : FF_SDFF0; + goto unmap_enable; + } + } else if (has_ce) { + if (kill_ce || kill_srst) + goto unmap_srst; + } else { + log_assert(!kill_ce); + if (kill_srst) + goto unmap_srst; + } + + if (!has_ce) { + if (!has_en && (supported_cells[has_set ? FF_SDFFE1 : FF_SDFFE0] & initmask)) { + // Just add enable. + sig_e = State::S1; + ff_type = has_set ? FF_SDFFE1 : FF_SDFFE0; + break; + } + if (!has_en && (supported_cells[has_set ? FF_SDFFCE1 : FF_SDFFCE0] & initmask)) { + // Just add enable. + sig_e = State::S1; + ff_type = has_set ? FF_SDFFCE1 : FF_SDFFCE0; + break; + } + if (has_en && (supported_cells[has_set ? FF_SDFFCE1 : FF_SDFFCE0] & initmask)) { + // Convert sdffe to sdffce + if (!(ff_neg & NEG_E)) { + if (!(ff_neg & NEG_R)) + sig_e = cell->module->OrGate(NEW_ID, sig_e, sig_r); + else + sig_e = cell->module->OrnotGate(NEW_ID, sig_e, sig_r); + } else { + if (!(ff_neg & NEG_R)) + sig_e = cell->module->AndnotGate(NEW_ID, sig_e, sig_r); + else + sig_e = cell->module->AndGate(NEW_ID, sig_e, sig_r); + } + ff_type = has_set ? FF_SDFFCE1 : FF_SDFFCE0; + break; + } + if (has_en && (supported_cells[has_set ? FF_SDFF1 : FF_SDFF0] & initmask)) { + // Unmap enable. + ff_type = has_set ? FF_SDFF1 : FF_SDFF0; + goto unmap_enable; + } + log_assert(!((has_set ? supported_sdff1 : supported_sdff0) & initmask)); + } else { + if ((has_set ? supported_sdff1 : supported_sdff0) & initmask) { + // Convert sdffce to sdffe, which may be further converted to sdff. + if (!(ff_neg & NEG_R)) { + if (!(ff_neg & NEG_E)) + sig_r = cell->module->AndGate(NEW_ID, sig_r, sig_e); + else + sig_r = cell->module->AndnotGate(NEW_ID, sig_r, sig_e); + } else { + if (!(ff_neg & NEG_E)) + sig_r = cell->module->OrnotGate(NEW_ID, sig_r, sig_e); + else + sig_r = cell->module->OrGate(NEW_ID, sig_r, sig_e); + } + ff_type = has_set ? FF_SDFFE1 : FF_SDFFE0; + continue; + } + } + // Alright, so this particular combination of initval and + // resetval is not natively supported. First, try flipping + // them both to see whether this helps. + if ((has_set ? supported_sdff0 : supported_sdff1) & flip_initmask(initmask)) { + // Checks out, do it. + ff_type = has_ce ? (has_set ? FF_SDFFCE0 : FF_SDFFCE1) : has_en ? (has_set ? FF_SDFFE0 : FF_SDFFE1) : (has_set ? FF_SDFF0 : FF_SDFF1); + goto flip_dqi; + } + + // Nope. No way to get SDFF* of the right kind, so unmap it. + // For SDFFE, the enable has to be unmapped first. + if (has_en) { + ff_type = has_set ? FF_SDFF1 : FF_SDFF0; + goto unmap_enable; + } +unmap_srst: + if (has_ce) + ff_type = FF_DFFE; + else + ff_type = FF_DFF; + if (ff_neg & NEG_R) + sig_d = cell->module->MuxGate(NEW_ID, has_set ? State::S1 : State::S0, sig_d[0], sig_r[0]); + else + sig_d = cell->module->MuxGate(NEW_ID, sig_d[0], has_set ? State::S1 : State::S0, sig_r[0]); + ff_neg &= ~NEG_R; + sig_r = SigSpec(); + kill_srst = false; + continue; + } else { + log_assert(0); + } + } +cell_ok: + + if (!(supported_cells_neg[ff_type][ff_neg] & initmask)) { + // Cell is supported, but not with those polarities. + // Will need to add some inverters. + + // Find the smallest value that xored with the neg mask + // results in a supported one — this results in preferentially + // inverting resets before clocks, etc. + int xneg; + for (xneg = 0; xneg < NUM_NEG; xneg++) + if (supported_cells_neg[ff_type][ff_neg ^ xneg] & initmask) + break; + log_assert(xneg < NUM_NEG); + if (xneg & NEG_R) + sig_r = cell->module->NotGate(NEW_ID, sig_r[0]); + if (xneg & NEG_S) + sig_s = cell->module->NotGate(NEW_ID, sig_s[0]); + if (xneg & NEG_E) + sig_e = cell->module->NotGate(NEW_ID, sig_e[0]); + if (xneg & NEG_C) + sig_c = cell->module->NotGate(NEW_ID, sig_c[0]); + ff_neg ^= xneg; + } + + cell->unsetPort(ID::D); + cell->unsetPort(ID::Q); + cell->unsetPort(ID::C); + cell->unsetPort(ID::E); + cell->unsetPort(ID::S); + cell->unsetPort(ID::R); + switch (ff_type) { + case FF_DFF: + cell->type = IdString(stringf("$_DFF_%c_", + (ff_neg & NEG_C) ? 'N' : 'P' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::C, sig_c); + break; + case FF_DFFE: + cell->type = IdString(stringf("$_DFFE_%c%c_", + (ff_neg & NEG_C) ? 'N' : 'P', + (ff_neg & NEG_E) ? 'N' : 'P' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::C, sig_c); + cell->setPort(ID::E, sig_e); + break; + case FF_ADFF0: + case FF_ADFF1: + cell->type = IdString(stringf("$_DFF_%c%c%c_", + (ff_neg & NEG_C) ? 'N' : 'P', + (ff_neg & NEG_R) ? 'N' : 'P', + (ff_type == FF_ADFF1) ? '1' : '0' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::C, sig_c); + cell->setPort(ID::R, sig_r); + break; + case FF_ADFFE0: + case FF_ADFFE1: + cell->type = IdString(stringf("$_DFFE_%c%c%c%c_", + (ff_neg & NEG_C) ? 'N' : 'P', + (ff_neg & NEG_R) ? 'N' : 'P', + (ff_type == FF_ADFFE1) ? '1' : '0', + (ff_neg & NEG_E) ? 'N' : 'P' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::C, sig_c); + cell->setPort(ID::E, sig_e); + cell->setPort(ID::R, sig_r); + break; + case FF_DFFSR: + cell->type = IdString(stringf("$_DFFSR_%c%c%c_", + (ff_neg & NEG_C) ? 'N' : 'P', + (ff_neg & NEG_S) ? 'N' : 'P', + (ff_neg & NEG_R) ? 'N' : 'P' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::C, sig_c); + cell->setPort(ID::S, sig_s); + cell->setPort(ID::R, sig_r); + break; + case FF_DFFSRE: + cell->type = IdString(stringf("$_DFFSRE_%c%c%c%c_", + (ff_neg & NEG_C) ? 'N' : 'P', + (ff_neg & NEG_S) ? 'N' : 'P', + (ff_neg & NEG_R) ? 'N' : 'P', + (ff_neg & NEG_E) ? 'N' : 'P' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::C, sig_c); + cell->setPort(ID::E, sig_e); + cell->setPort(ID::S, sig_s); + cell->setPort(ID::R, sig_r); + break; + case FF_SDFF0: + case FF_SDFF1: + cell->type = IdString(stringf("$_SDFF_%c%c%c_", + (ff_neg & NEG_C) ? 'N' : 'P', + (ff_neg & NEG_R) ? 'N' : 'P', + (ff_type == FF_SDFF1) ? '1' : '0' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::C, sig_c); + cell->setPort(ID::R, sig_r); + break; + case FF_SDFFE0: + case FF_SDFFE1: + cell->type = IdString(stringf("$_SDFFE_%c%c%c%c_", + (ff_neg & NEG_C) ? 'N' : 'P', + (ff_neg & NEG_R) ? 'N' : 'P', + (ff_type == FF_SDFFE1) ? '1' : '0', + (ff_neg & NEG_E) ? 'N' : 'P' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::C, sig_c); + cell->setPort(ID::E, sig_e); + cell->setPort(ID::R, sig_r); + break; + case FF_SDFFCE0: + case FF_SDFFCE1: + cell->type = IdString(stringf("$_SDFFCE_%c%c%c%c_", + (ff_neg & NEG_C) ? 'N' : 'P', + (ff_neg & NEG_R) ? 'N' : 'P', + (ff_type == FF_SDFFCE1) ? '1' : '0', + (ff_neg & NEG_E) ? 'N' : 'P' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::C, sig_c); + cell->setPort(ID::E, sig_e); + cell->setPort(ID::R, sig_r); + break; + case FF_DLATCH: + cell->type = IdString(stringf("$_DLATCH_%c_", + (ff_neg & NEG_E) ? 'N' : 'P' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::E, sig_e); + break; + case FF_ADLATCH0: + case FF_ADLATCH1: + cell->type = IdString(stringf("$_DLATCH_%c%c%c_", + (ff_neg & NEG_E) ? 'N' : 'P', + (ff_neg & NEG_R) ? 'N' : 'P', + (ff_type == FF_ADLATCH1) ? '1' : '0' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::E, sig_e); + cell->setPort(ID::R, sig_r); + break; + case FF_DLATCHSR: + cell->type = IdString(stringf("$_DLATCHSR_%c%c%c_", + (ff_neg & NEG_E) ? 'N' : 'P', + (ff_neg & NEG_S) ? 'N' : 'P', + (ff_neg & NEG_R) ? 'N' : 'P' + )); + cell->setPort(ID::D, sig_d); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::E, sig_e); + cell->setPort(ID::S, sig_s); + cell->setPort(ID::R, sig_r); + break; + case FF_SR: + cell->type = IdString(stringf("$_SR_%c%c_", + (ff_neg & NEG_S) ? 'N' : 'P', + (ff_neg & NEG_R) ? 'N' : 'P' + )); + cell->setPort(ID::Q, sig_q); + cell->setPort(ID::S, sig_s); + cell->setPort(ID::R, sig_r); + break; + default: + log_assert(0); + } + return; + +error: + log_error("FF %s.%s (type %s) cannot be legalized: %s\n", log_id(cell->module->name), log_id(cell->name), log_id(cell->type), reason); + } + + void execute(std::vector args, RTLIL::Design *design) override + { + + log_header(design, "Executing DFFLEGALIZE pass (convert FFs to types supported by the target).\n"); + + for (int i = 0; i < NUM_FFTYPES; i++) { + for (int j = 0; j < NUM_NEG; j++) + supported_cells_neg[i][j] = 0; + supported_cells[i] = 0; + } + mince = 0; + minsrst = 0; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-cell" && argidx + 2 < args.size()) { + std::string celltype = args[++argidx]; + std::string inittype = args[++argidx]; + enum FfType ff_type[2] = {NUM_FFTYPES, NUM_FFTYPES}; + char pol_c = 0; + char pol_e = 0; + char pol_s = 0; + char pol_r = 0; + char srval = 0; + if (celltype.substr(0, 5) == "$_SR_" && celltype.size() == 8 && celltype[7] == '_') { + ff_type[0] = FF_SR; + pol_s = celltype[5]; + pol_r = celltype[6]; + } else if (celltype.substr(0, 6) == "$_DFF_" && celltype.size() == 8 && celltype[7] == '_') { + ff_type[0] = FF_DFF; + pol_c = celltype[6]; + } else if (celltype.substr(0, 7) == "$_DFFE_" && celltype.size() == 10 && celltype[9] == '_') { + ff_type[0] = FF_DFFE; + pol_c = celltype[7]; + pol_e = celltype[8]; + } else if (celltype.substr(0, 6) == "$_DFF_" && celltype.size() == 10 && celltype[9] == '_') { + ff_type[0] = FF_ADFF0; + ff_type[1] = FF_ADFF1; + pol_c = celltype[6]; + pol_r = celltype[7]; + srval = celltype[8]; + } else if (celltype.substr(0, 7) == "$_DFFE_" && celltype.size() == 12 && celltype[11] == '_') { + ff_type[0] = FF_ADFFE0; + ff_type[1] = FF_ADFFE1; + pol_c = celltype[7]; + pol_r = celltype[8]; + srval = celltype[9]; + pol_e = celltype[10]; + } else if (celltype.substr(0, 8) == "$_DFFSR_" && celltype.size() == 12 && celltype[11] == '_') { + ff_type[0] = FF_DFFSR; + pol_c = celltype[8]; + pol_s = celltype[9]; + pol_r = celltype[10]; + } else if (celltype.substr(0, 9) == "$_DFFSRE_" && celltype.size() == 14 && celltype[13] == '_') { + ff_type[0] = FF_DFFSRE; + pol_c = celltype[9]; + pol_s = celltype[10]; + pol_r = celltype[11]; + pol_e = celltype[12]; + } else if (celltype.substr(0, 7) == "$_SDFF_" && celltype.size() == 11 && celltype[10] == '_') { + ff_type[0] = FF_SDFF0; + ff_type[1] = FF_SDFF1; + pol_c = celltype[7]; + pol_r = celltype[8]; + srval = celltype[9]; + } else if (celltype.substr(0, 8) == "$_SDFFE_" && celltype.size() == 13 && celltype[12] == '_') { + ff_type[0] = FF_SDFFE0; + ff_type[1] = FF_SDFFE1; + pol_c = celltype[8]; + pol_r = celltype[9]; + srval = celltype[10]; + pol_e = celltype[11]; + } else if (celltype.substr(0, 9) == "$_SDFFCE_" && celltype.size() == 14 && celltype[13] == '_') { + ff_type[0] = FF_SDFFCE0; + ff_type[1] = FF_SDFFCE1; + pol_c = celltype[9]; + pol_r = celltype[10]; + srval = celltype[11]; + pol_e = celltype[12]; + } else if (celltype.substr(0, 9) == "$_DLATCH_" && celltype.size() == 11 && celltype[10] == '_') { + ff_type[0] = FF_DLATCH; + pol_e = celltype[9]; + } else if (celltype.substr(0, 9) == "$_DLATCH_" && celltype.size() == 13 && celltype[12] == '_') { + ff_type[0] = FF_ADLATCH0; + ff_type[1] = FF_ADLATCH1; + pol_e = celltype[9]; + pol_r = celltype[10]; + srval = celltype[11]; + } else if (celltype.substr(0, 11) == "$_DLATCHSR_" && celltype.size() == 15 && celltype[14] == '_') { + ff_type[0] = FF_DLATCHSR; + pol_e = celltype[11]; + pol_s = celltype[12]; + pol_r = celltype[13]; + } else { +unrecognized: + log_error("unrecognized cell type %s.\n", celltype.c_str()); + } + int mask = 0; + int match = 0; + for (auto pair : { + std::make_pair(pol_c, NEG_C), + std::make_pair(pol_e, NEG_E), + std::make_pair(pol_s, NEG_S), + std::make_pair(pol_r, NEG_R), + }) { + if (pair.first == 'N') { + mask |= pair.second; + match |= pair.second; + } else if (pair.first == 'P' || pair.first == 0) { + mask |= pair.second; + } else if (pair.first != '?') { + goto unrecognized; + } + } + if (srval == '0') { + ff_type[1] = NUM_FFTYPES; + } else if (srval == '1') { + ff_type[0] = NUM_FFTYPES; + } else if (srval != 0 && srval != '?') { + goto unrecognized; + } + for (int i = 0; i < 2; i++) { + if (ff_type[i] == NUM_FFTYPES) + continue; + int initmask; + if (inittype == "x") { + initmask = INIT_X; + } else if (inittype == "0") { + initmask = INIT_X | INIT_0; + } else if (inittype == "1") { + initmask = INIT_X | INIT_1; + } else if (inittype == "r") { + if (srval == 0) + log_error("init type r not valid for cell type %s.\n", celltype.c_str()); + if (i == 0) + initmask = INIT_X | INIT_0; + else + initmask = INIT_X | INIT_1; + } else if (inittype == "01") { + initmask = INIT_X | INIT_0 | INIT_1; + } else { + log_error("unrecognized init type %s for cell type %s.\n", inittype.c_str(), celltype.c_str()); + } + for (int neg = 0; neg < NUM_NEG; neg++) + if ((neg & mask) == match) + supported_cells_neg[ff_type[i]][neg] |= initmask; + supported_cells[ff_type[i]] |= initmask; + } + continue; + } else if (args[argidx] == "-mince" && argidx + 1 < args.size()) { + mince = atoi(args[++argidx].c_str()); + continue; + } else if (args[argidx] == "-minsrst" && argidx + 1 < args.size()) { + minsrst = atoi(args[++argidx].c_str()); + continue; + } + break; + } + extra_args(args, argidx, design); + supported_dffsr = supported_cells[FF_DFFSR] | supported_cells[FF_DFFSRE]; + supported_adff0 = supported_cells[FF_ADFF0] | supported_cells[FF_ADFFE0] | supported_dffsr; + supported_adff1 = supported_cells[FF_ADFF1] | supported_cells[FF_ADFFE1] | supported_dffsr; + supported_sdff0 = supported_cells[FF_SDFF0] | supported_cells[FF_SDFFE0] | supported_cells[FF_SDFFCE0]; + supported_sdff1 = supported_cells[FF_SDFF1] | supported_cells[FF_SDFFE1] | supported_cells[FF_SDFFCE1]; + supported_dff = supported_cells[FF_DFF] | supported_cells[FF_DFFE] | supported_dffsr | supported_adff0 | supported_adff1 | supported_sdff0 | supported_sdff1; + supported_sr = supported_dffsr | supported_cells[FF_DLATCHSR] | supported_cells[FF_SR] | supported_cells[FF_ADLATCH0] | flip_initmask(supported_cells[FF_ADLATCH1]); + supported_dlatch = supported_cells[FF_DLATCH] | supported_cells[FF_ADLATCH0] | supported_cells[FF_ADLATCH1] | supported_cells[FF_DLATCHSR]; + + for (auto module : design->selected_modules()) + { + sigmap.set(module); + initbits.clear(); + + for (auto wire : module->selected_wires()) + { + if (wire->attributes.count(ID::init) == 0) + continue; + + SigSpec wirebits = sigmap(wire); + Const initval = wire->attributes.at(ID::init); + + for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) + { + SigBit bit = wirebits[i]; + State val = initval[i]; + + if (val != State::S0 && val != State::S1 && bit.wire != nullptr) + continue; + + if (initbits.count(bit)) { + if (initbits.at(bit).first != val) + log_error("Conflicting init values for signal %s (%s = %s != %s).\n", + log_signal(bit), log_signal(SigBit(wire, i)), + log_signal(val), log_signal(initbits.at(bit).first)); + continue; + } + + initbits[bit] = std::make_pair(val,SigBit(wire,i)); + } + } + + if (mince || minsrst) { + ce_used.clear(); + srst_used.clear(); + + for (auto cell : module->cells()) { + if (!RTLIL::builtin_ff_cell_types().count(cell->type)) + continue; + + if (cell->hasPort(ID::C) && cell->hasPort(ID::E)) { + SigSpec sig = cell->getPort(ID::E); + // Do not count const enable signals. + if (GetSize(sig) == 1 && sig[0].wire) + ce_used[sig[0]]++; + } + if (cell->type.str().substr(0, 6) == "$_SDFF") { + SigSpec sig = cell->getPort(ID::R); + // Do not count const srst signals. + if (GetSize(sig) == 1 && sig[0].wire) + srst_used[sig[0]]++; + } + } + } + + // First gather FF cells, then iterate over them later. + // We may need to split an FF into several cells. + std::vector ff_cells; + + for (auto cell : module->selected_cells()) + { + // Early exit for non-FFs. + if (!RTLIL::builtin_ff_cell_types().count(cell->type)) + continue; + + ff_cells.push_back(cell); + } + + for (auto cell: ff_cells) + handle_ff(cell); + } + + sigmap.clear(); + initbits.clear(); + ce_used.clear(); + srst_used.clear(); + } +} DffLegalizePass; + +PRIVATE_NAMESPACE_END From 6b42819a37a02ee4cc0724f54cbbd3ac996ca0a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Tue, 30 Jun 2020 15:30:59 +0200 Subject: [PATCH 022/287] dfflegalize: Add tests. --- tests/techmap/dfflegalize_adff.ys | 103 +++ tests/techmap/dfflegalize_adff_init.ys | 279 ++++++++ tests/techmap/dfflegalize_adlatch.ys | 51 ++ tests/techmap/dfflegalize_adlatch_init.ys | 99 +++ tests/techmap/dfflegalize_dff.ys | 306 ++++++++ tests/techmap/dfflegalize_dff_init.ys | 786 +++++++++++++++++++++ tests/techmap/dfflegalize_dffsr.ys | 88 +++ tests/techmap/dfflegalize_dffsr_init.ys | 379 ++++++++++ tests/techmap/dfflegalize_dlatch.ys | 42 ++ tests/techmap/dfflegalize_dlatch_init.ys | 82 +++ tests/techmap/dfflegalize_dlatchsr.ys | 37 + tests/techmap/dfflegalize_dlatchsr_init.ys | 127 ++++ tests/techmap/dfflegalize_inv.ys | 178 +++++ tests/techmap/dfflegalize_mince.ys | 53 ++ tests/techmap/dfflegalize_minsrst.ys | 43 ++ tests/techmap/dfflegalize_sr.ys | 74 ++ tests/techmap/dfflegalize_sr_init.ys | 230 ++++++ 17 files changed, 2957 insertions(+) create mode 100644 tests/techmap/dfflegalize_adff.ys create mode 100644 tests/techmap/dfflegalize_adff_init.ys create mode 100644 tests/techmap/dfflegalize_adlatch.ys create mode 100644 tests/techmap/dfflegalize_adlatch_init.ys create mode 100644 tests/techmap/dfflegalize_dff.ys create mode 100644 tests/techmap/dfflegalize_dff_init.ys create mode 100644 tests/techmap/dfflegalize_dffsr.ys create mode 100644 tests/techmap/dfflegalize_dffsr_init.ys create mode 100644 tests/techmap/dfflegalize_dlatch.ys create mode 100644 tests/techmap/dfflegalize_dlatch_init.ys create mode 100644 tests/techmap/dfflegalize_dlatchsr.ys create mode 100644 tests/techmap/dfflegalize_dlatchsr_init.ys create mode 100644 tests/techmap/dfflegalize_inv.ys create mode 100644 tests/techmap/dfflegalize_mince.ys create mode 100644 tests/techmap/dfflegalize_minsrst.ys create mode 100644 tests/techmap/dfflegalize_sr.ys create mode 100644 tests/techmap/dfflegalize_sr_init.ys diff --git a/tests/techmap/dfflegalize_adff.ys b/tests/techmap/dfflegalize_adff.ys new file mode 100644 index 00000000000..a563e8c611f --- /dev/null +++ b/tests/techmap/dfflegalize_adff.ys @@ -0,0 +1,103 @@ +read_verilog -icells < Date: Mon, 29 Jun 2020 22:06:43 +0000 Subject: [PATCH 023/287] qbfsat: Clean up and refactor data structures into `qbfsat.h`. --- CODEOWNERS | 1 + passes/sat/qbfsat.cc | 261 +++---------------------------------------- passes/sat/qbfsat.h | 252 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 266 insertions(+), 248 deletions(-) create mode 100644 passes/sat/qbfsat.h diff --git a/CODEOWNERS b/CODEOWNERS index a73779920c1..350a62120b5 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -33,5 +33,6 @@ misc/*.py @btut backends/firrtl @ucbjrl @azidar passes/sat/qbfsat.cc @boqwxp +passes/sat/qbfsat.h @boqwxp passes/cmds/exec.cc @boqwxp passes/cmds/printattrs.cc @boqwxp diff --git a/passes/sat/qbfsat.cc b/passes/sat/qbfsat.cc index 136259558b0..e4dfcaa0c36 100644 --- a/passes/sat/qbfsat.cc +++ b/passes/sat/qbfsat.cc @@ -1,4 +1,4 @@ -/* +/* -*- c++ -*- * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2020 Alberto Gonzalez @@ -18,13 +18,8 @@ */ #include "kernel/yosys.h" -#include "kernel/celltypes.h" #include "kernel/consteval.h" -#include "kernel/log.h" -#include "kernel/rtlil.h" -#include "kernel/register.h" -#include -#include +#include "qbfsat.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -36,156 +31,7 @@ static inline unsigned int difference(unsigned int a, unsigned int b) { return a - b; } -struct QbfSolutionType { - std::vector stdout_lines; - dict, std::string> hole_to_value; - double solver_time; - bool sat; - bool unknown; //true if neither 'sat' nor 'unsat' - - QbfSolutionType() : solver_time(0.0), sat(false), unknown(true) {} -}; - -struct QbfSolveOptions { - bool specialize, specialize_from_file, write_solution, nocleanup, dump_final_smt2, assume_outputs, assume_neg; - bool nooptimize, nobisection; - bool sat, unsat, show_smtbmc; - enum Solver{Z3, Yices, CVC4} solver; - enum OptimizationLevel{O0, O1, O2} oflag; - int timeout; - std::string specialize_soln_file; - std::string write_soln_soln_file; - std::string dump_final_smt2_file; - size_t argidx; - QbfSolveOptions() : specialize(false), specialize_from_file(false), write_solution(false), - nocleanup(false), dump_final_smt2(false), assume_outputs(false), assume_neg(false), - nooptimize(false), nobisection(false), sat(false), unsat(false), show_smtbmc(false), - solver(Yices), oflag(O0), timeout(0), argidx(0) {}; -}; - -std::string get_solver_name(const QbfSolveOptions &opt) { - if (opt.solver == opt.Solver::Z3) - return "z3"; - else if (opt.solver == opt.Solver::Yices) - return "yices"; - else if (opt.solver == opt.Solver::CVC4) - return "cvc4"; - else - log_cmd_error("unknown solver specified.\n"); - return ""; -} - -void recover_solution(QbfSolutionType &sol) { - YS_REGEX_TYPE sat_regex = YS_REGEX_COMPILE("Status: PASSED"); - YS_REGEX_TYPE unsat_regex = YS_REGEX_COMPILE("Solver Error.*model is not available"); - YS_REGEX_TYPE unsat_regex2 = YS_REGEX_COMPILE("Status: FAILED"); - YS_REGEX_TYPE timeout_regex = YS_REGEX_COMPILE("No solution found! \\(timeout\\)"); - YS_REGEX_TYPE timeout_regex2 = YS_REGEX_COMPILE("No solution found! \\(interrupted\\)"); - YS_REGEX_TYPE unknown_regex = YS_REGEX_COMPILE("No solution found! \\(unknown\\)"); - YS_REGEX_TYPE unknown_regex2 = YS_REGEX_COMPILE("Unexpected EOF response from solver"); - YS_REGEX_TYPE memout_regex = YS_REGEX_COMPILE("Solver Error:.*error \"out of memory\""); - YS_REGEX_TYPE hole_value_regex = YS_REGEX_COMPILE_WITH_SUBS("Value for anyconst in [a-zA-Z0-9_]* \\(([^:]*:[^\\)]*)\\): (.*)"); -#ifndef NDEBUG - YS_REGEX_TYPE hole_loc_regex = YS_REGEX_COMPILE("[^:]*:[0-9]+.[0-9]+-[0-9]+.[0-9]+"); - YS_REGEX_TYPE hole_val_regex = YS_REGEX_COMPILE("[0-9]+"); -#endif - YS_REGEX_MATCH_TYPE m; - bool sat_regex_found = false; - bool unsat_regex_found = false; - dict hole_value_recovered; - for (const std::string &x : sol.stdout_lines) { - if(YS_REGEX_NS::regex_search(x, m, hole_value_regex)) { - std::string loc = m[1].str(); - std::string val = m[2].str(); -#ifndef NDEBUG - log_assert(YS_REGEX_NS::regex_search(loc, hole_loc_regex)); - log_assert(YS_REGEX_NS::regex_search(val, hole_val_regex)); -#endif - auto locs = split_tokens(loc, "|"); - pool loc_pool(locs.begin(), locs.end()); - sol.hole_to_value[loc_pool] = val; - } - else if (YS_REGEX_NS::regex_search(x, sat_regex)) { - sat_regex_found = true; - sol.sat = true; - sol.unknown = false; - } - else if (YS_REGEX_NS::regex_search(x, unsat_regex)) { - unsat_regex_found = true; - sol.sat = false; - sol.unknown = false; - } - else if (YS_REGEX_NS::regex_search(x, memout_regex)) { - sol.unknown = true; - log_warning("solver ran out of memory\n"); - } - else if (YS_REGEX_NS::regex_search(x, timeout_regex)) { - sol.unknown = true; - log_warning("solver timed out\n"); - } - else if (YS_REGEX_NS::regex_search(x, timeout_regex2)) { - sol.unknown = true; - log_warning("solver timed out\n"); - } - else if (YS_REGEX_NS::regex_search(x, unknown_regex)) { - sol.unknown = true; - log_warning("solver returned \"unknown\"\n"); - } - else if (YS_REGEX_NS::regex_search(x, unsat_regex2)) { - unsat_regex_found = true; - sol.sat = false; - sol.unknown = false; - } - else if (YS_REGEX_NS::regex_search(x, unknown_regex2)) { - sol.unknown = true; - } - } -#ifndef NDEBUG - log_assert(!sol.unknown && sol.sat? sat_regex_found : true); - log_assert(!sol.unknown && !sol.sat? unsat_regex_found : true); -#endif -} - -dict, int>, RTLIL::SigBit> get_hole_loc_idx_sigbit_map(RTLIL::Module *module, const QbfSolutionType &sol) { - dict, int>, RTLIL::SigBit> hole_loc_idx_to_sigbit; - pool anyconst_sigbits; - dict anyconst_sigbit_to_wire_sigbit; - - for (auto cell : module->cells()) { - pool cell_src = cell->get_strpool_attribute(ID::src); - auto pos = sol.hole_to_value.find(cell_src); - if (pos != sol.hole_to_value.end() && cell->type.in("$anyconst", "$anyseq")) { - RTLIL::SigSpec port_y = cell->getPort(ID::Y); - for (int i = GetSize(port_y) - 1; i >= 0; --i) { - hole_loc_idx_to_sigbit[std::make_pair(pos->first, i)] = port_y[i]; - anyconst_sigbits.insert(port_y[i]); - } - } - } - - for (auto &conn : module->connections()) { - auto lhs = conn.first; - auto rhs = conn.second; - for (auto i = 0; i < GetSize(rhs); ++i) { - if (anyconst_sigbits[rhs[i]]) { - auto pos = anyconst_sigbit_to_wire_sigbit.find(rhs[i]); - if (pos != anyconst_sigbit_to_wire_sigbit.end()) - log_cmd_error("conflicting names for hole $anyconst sigbit %s\n", log_signal(rhs[i])); - anyconst_sigbit_to_wire_sigbit[rhs[i]] = lhs[i]; - } - } - } - - for (auto &it : hole_loc_idx_to_sigbit) { - auto pos = anyconst_sigbit_to_wire_sigbit.find(it.second); - if (pos != anyconst_sigbit_to_wire_sigbit.end()) - it.second = pos->second; - } - - return hole_loc_idx_to_sigbit; -} - -pool validate_design_and_get_inputs(RTLIL::Module *module, const QbfSolveOptions &opt) { +pool validate_design_and_get_inputs(RTLIL::Module *module, bool assume_outputs) { bool found_input = false; bool found_hole = false; bool found_1bit_output = false; @@ -213,48 +59,12 @@ pool validate_design_and_get_inputs(RTLIL::Module *module, const Qb log_cmd_error("Did not find any existentially-quantified variables. Use 'sat' instead.\n"); if (!found_1bit_output && !found_assert_assume) log_cmd_error("Did not find any single-bit outputs or $assert/$assume cells. Is this a miter circuit?\n"); - if (!found_assert_assume && !opt.assume_outputs) + if (!found_assert_assume && !assume_outputs) log_cmd_error("Did not find any $assert/$assume cells. Single-bit outputs were found, but `-assume-outputs` was not specified.\n"); return input_wires; } -void write_solution(RTLIL::Module *module, const QbfSolutionType &sol, const std::string &file) { - std::ofstream fout(file.c_str()); - if (!fout) - log_cmd_error("could not open solution file for writing.\n"); - - //There is a question here: How exactly shall we identify holes? - //There are at least two reasonable options: - //1. By the source location of the $anyconst cells - //2. By the name(s) of the wire(s) connected to each SigBit of the $anyconst cell->getPort(ID::Y) SigSpec. - // - //Option 1 has the benefit of being very precise. There is very limited potential for confusion, as long - //as the source attribute has been set. However, if the source attribute is not set, this won't work. - //More importantly, we want to have the ability to port hole assignments to other modules with compatible - //hole names and widths. Obviously in those cases source locations of the $anyconst cells will not match. - // - //Option 2 has the benefits previously described, but wire names can be changed automatically by - //optimization or techmapping passes, especially when (ex/im)porting from BLIF for optimization with ABC. - // - //The approach taken here is to allow both options. We write the assignment information for each bit of - //the solution on a separate line. Each line is of one of two forms: - // - //location bit name = value - //location bit name [offset] = value - // - //where '[', ']', and '=' are literal symbols, "location" is the $anyconst cell source location attribute, - //"bit" is the index of the $anyconst cell, "name" is the `wire->name` field of the SigBit corresponding - //to the current bit of the $anyconst cell->getPort(ID::Y), "offset" is the `offset` field of that same - //SigBit, and "value", which is either '0' or '1', represents the assignment for that bit. - dict, int>, RTLIL::SigBit> hole_loc_idx_to_sigbit = get_hole_loc_idx_sigbit_map(module, sol); - for (auto &x : sol.hole_to_value) { - std::string src_as_str = std::accumulate(x.first.begin(), x.first.end(), std::string(), [](const std::string &a, const std::string &b){return a + "|" + b;}); - for (auto i = 0; i < GetSize(x.second); ++i) - fout << src_as_str.c_str() << " " << i << " " << log_signal(hole_loc_idx_to_sigbit[std::make_pair(x.first, i)]) << " = " << x.second[GetSize(x.second) - 1 - i] << std::endl; - } -} - void specialize_from_file(RTLIL::Module *module, const std::string &file) { YS_REGEX_TYPE hole_bit_assn_regex = YS_REGEX_COMPILE_WITH_SUBS("^(.+) ([0-9]+) ([^ ]+) \\[([0-9]+)] = ([01])$"); YS_REGEX_TYPE hole_assn_regex = YS_REGEX_COMPILE_WITH_SUBS("^(.+) ([0-9]+) ([^ ]+) = ([01])$"); //if no index specified @@ -318,7 +128,7 @@ void specialize_from_file(RTLIL::Module *module, const std::string &file) { } void specialize(RTLIL::Module *module, const QbfSolutionType &sol, bool quiet = false) { - dict, int>, RTLIL::SigBit> hole_loc_idx_to_sigbit = get_hole_loc_idx_sigbit_map(module, sol); + auto hole_loc_idx_to_sigbit = sol.get_hole_loc_idx_sigbit_map(module); pool anyconsts_to_remove; for (auto cell : module->cells()) if (cell->type == "$anyconst") @@ -348,24 +158,6 @@ void specialize(RTLIL::Module *module, const QbfSolutionType &sol, bool quiet = } } -void dump_model(RTLIL::Module *module, const QbfSolutionType &sol) { - log("Satisfiable model:\n"); - dict, int>, RTLIL::SigBit> hole_loc_idx_to_sigbit = get_hole_loc_idx_sigbit_map(module, sol); - for (auto &it : sol.hole_to_value) { - pool hole_loc = it.first; - std::string hole_value = it.second; - - for (unsigned int i = 0; i < hole_value.size(); ++i) { - int bit_idx = GetSize(hole_value) - 1 - i; - auto it = hole_loc_idx_to_sigbit.find(std::make_pair(hole_loc, i)); - log_assert(it != hole_loc_idx_to_sigbit.end()); - - RTLIL::SigBit hole_sigbit = it->second; - log("\t%s = 1'b%c\n", log_signal(hole_sigbit), hole_value[bit_idx]); - } - } -} - void allconstify_inputs(RTLIL::Module *module, const pool &input_wires) { for (auto &n : input_wires) { RTLIL::Wire *input = module->wire(n); @@ -383,7 +175,7 @@ void allconstify_inputs(RTLIL::Module *module, const pool &input_wi module->fixup_ports(); } -void assume_miter_outputs(RTLIL::Module *module, const QbfSolveOptions &opt) { +void assume_miter_outputs(RTLIL::Module *module, bool assume_neg) { std::vector wires_to_assume; for (auto w : module->wires()) if (w->port_output && w->width == 1) @@ -398,7 +190,7 @@ void assume_miter_outputs(RTLIL::Module *module, const QbfSolveOptions &opt) { log("\n"); } - if (opt.assume_neg) { + if (assume_neg) { for (unsigned int i = 0; i < wires_to_assume.size(); ++i) { RTLIL::SigSpec n_wire = module->LogicNot(wires_to_assume[i]->name.str() + "__n__qbfsat", wires_to_assume[i], false, wires_to_assume[i]->get_src_attribute()); wires_to_assume[i] = n_wire.as_wire(); @@ -430,7 +222,7 @@ QbfSolutionType call_qbf_solver(RTLIL::Module *mod, const QbfSolveOptions &opt, const std::string yosys_smtbmc_exe = proc_self_dirname() + "yosys-smtbmc"; const std::string smt2_command = "write_smt2 -stbv -wires " + tempdir_name + "/problem" + (iter_num != 0? stringf("%d", iter_num) : "") + ".smt2"; const std::string smtbmc_warning = "z3: WARNING:"; - const std::string smtbmc_cmd = yosys_smtbmc_exe + " -s " + (get_solver_name(opt)) + (opt.timeout != 0? stringf(" --timeout %d", opt.timeout) : "") + " -t 1 -g --binary " + (opt.dump_final_smt2? "--dump-smt2 " + opt.dump_final_smt2_file + " " : "") + tempdir_name + "/problem" + (iter_num != 0? stringf("%d", iter_num) : "") + ".smt2 2>&1"; + const std::string smtbmc_cmd = yosys_smtbmc_exe + " -s " + (opt.get_solver_name()) + (opt.timeout != 0? stringf(" --timeout %d", opt.timeout) : "") + " -t 1 -g --binary " + (opt.dump_final_smt2? "--dump-smt2 " + opt.dump_final_smt2_file + " " : "") + tempdir_name + "/problem" + (iter_num != 0? stringf("%d", iter_num) : "") + ".smt2 2>&1"; Pass::call(mod->design, smt2_command); @@ -451,7 +243,7 @@ QbfSolutionType call_qbf_solver(RTLIL::Module *mod, const QbfSolveOptions &opt, ret.solver_time = (end - begin) / 1e9f; if (!quiet) log("Solver finished in %.3f seconds.\n", ret.solver_time); - recover_solution(ret); + ret.recover_solution(); return ret; } @@ -468,10 +260,10 @@ QbfSolutionType qbf_solve(RTLIL::Module *mod, const QbfSolveOptions &opt) { Pass::call(design, "design -push-copy"); //Replace input wires with wires assigned $allconst cells: - pool input_wires = validate_design_and_get_inputs(module, opt); + pool input_wires = validate_design_and_get_inputs(module, opt.assume_outputs); allconstify_inputs(module, input_wires); if (opt.assume_outputs) - assume_miter_outputs(module, opt); + assume_miter_outputs(module, opt.assume_neg); //Find the wire to be optimized, if any: for (auto wire : module->wires()) { @@ -699,33 +491,6 @@ QbfSolveOptions parse_args(const std::vector &args) { return opt; } -void print_proof_failed() -{ - log("\n"); - log(" ______ ___ ___ _ _ _ _ \n"); - log(" (_____ \\ / __) / __) (_) | | | |\n"); - log(" _____) )___ ___ ___ _| |__ _| |__ _____ _| | _____ __| | |\n"); - log(" | ____/ ___) _ \\ / _ (_ __) (_ __|____ | | || ___ |/ _ |_|\n"); - log(" | | | | | |_| | |_| || | | | / ___ | | || ____( (_| |_ \n"); - log(" |_| |_| \\___/ \\___/ |_| |_| \\_____|_|\\_)_____)\\____|_|\n"); - log("\n"); -} - -void print_qed() -{ - log("\n"); - log(" /$$$$$$ /$$$$$$$$ /$$$$$$$ \n"); - log(" /$$__ $$ | $$_____/ | $$__ $$ \n"); - log(" | $$ \\ $$ | $$ | $$ \\ $$ \n"); - log(" | $$ | $$ | $$$$$ | $$ | $$ \n"); - log(" | $$ | $$ | $$__/ | $$ | $$ \n"); - log(" | $$/$$ $$ | $$ | $$ | $$ \n"); - log(" | $$$$$$/ /$$| $$$$$$$$ /$$| $$$$$$$//$$\n"); - log(" \\____ $$$|__/|________/|__/|_______/|__/\n"); - log(" \\__/ \n"); - log("\n"); -} - struct QbfSatPass : public Pass { QbfSatPass() : Pass("qbfsat", "solve a 2QBF-SAT problem in the circuit") { } void help() override @@ -827,12 +592,12 @@ struct QbfSatPass : public Pass { else if (ret.sat) { print_qed(); if (opt.write_solution) { - write_solution(module, ret, opt.write_soln_soln_file); + ret.write_solution(module, opt.write_soln_soln_file); } if (opt.specialize) { specialize(module, ret); } else { - dump_model(module, ret); + ret.dump_model(module); } if (opt.unsat) log_cmd_error("expected problem to be UNSAT\n"); diff --git a/passes/sat/qbfsat.h b/passes/sat/qbfsat.h new file mode 100644 index 00000000000..401f9c7a6ba --- /dev/null +++ b/passes/sat/qbfsat.h @@ -0,0 +1,252 @@ +/* -*- c++ -*- + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2020 Alberto Gonzalez + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef QBFSAT_H +#define QBFSAT_H + +#include "kernel/yosys.h" +#include + +YOSYS_NAMESPACE_BEGIN + +struct QbfSolveOptions { + bool specialize = false, specialize_from_file = false, write_solution = false, nocleanup = false; + bool dump_final_smt2 = false, assume_outputs = false, assume_neg = false, nooptimize = false; + bool nobisection = false, sat = false, unsat = false, show_smtbmc = false; + enum Solver{Z3, Yices, CVC4} solver = Yices; + enum OptimizationLevel{O0, O1, O2} oflag = O0; + int timeout = 0; + std::string specialize_soln_file = ""; + std::string write_soln_soln_file = ""; + std::string dump_final_smt2_file = ""; + size_t argidx = 0; + + std::string get_solver_name() const { + if (solver == Solver::Z3) + return "z3"; + else if (solver == Solver::Yices) + return "yices"; + else if (solver == Solver::CVC4) + return "cvc4"; + + log_cmd_error("unknown solver specified.\n"); + return ""; + } +}; + +struct QbfSolutionType { + std::vector stdout_lines = {}; + dict, std::string> hole_to_value = {}; + double solver_time = 0; + bool sat = false; + bool unknown = true; //true if neither 'sat' nor 'unsat' + + dict, int>, RTLIL::SigBit> get_hole_loc_idx_sigbit_map(RTLIL::Module *module) const { + dict, int>, RTLIL::SigBit> hole_loc_idx_to_sigbit; + pool anyconst_sigbits; + dict anyconst_sigbit_to_wire_sigbit; + + for (auto cell : module->cells()) { + pool cell_src = cell->get_strpool_attribute(ID::src); + auto pos = hole_to_value.find(cell_src); + if (pos != hole_to_value.end() && cell->type.in("$anyconst", "$anyseq")) { + RTLIL::SigSpec port_y = cell->getPort(ID::Y); + for (int i = GetSize(port_y) - 1; i >= 0; --i) { + hole_loc_idx_to_sigbit[std::make_pair(pos->first, i)] = port_y[i]; + anyconst_sigbits.insert(port_y[i]); + } + } + } + + for (auto &conn : module->connections()) { + auto lhs = conn.first; + auto rhs = conn.second; + for (auto i = 0; i < GetSize(rhs); ++i) { + if (anyconst_sigbits[rhs[i]]) { + auto pos = anyconst_sigbit_to_wire_sigbit.find(rhs[i]); + if (pos != anyconst_sigbit_to_wire_sigbit.end()) + log_cmd_error("conflicting names for hole $anyconst sigbit %s\n", log_signal(rhs[i])); + anyconst_sigbit_to_wire_sigbit[rhs[i]] = lhs[i]; + } + } + } + + for (auto &it : hole_loc_idx_to_sigbit) { + auto pos = anyconst_sigbit_to_wire_sigbit.find(it.second); + if (pos != anyconst_sigbit_to_wire_sigbit.end()) + it.second = pos->second; + } + + return hole_loc_idx_to_sigbit; + } + + void dump_model(RTLIL::Module *module) const { + log("Satisfiable model:\n"); + auto hole_loc_idx_to_sigbit = get_hole_loc_idx_sigbit_map(module); + for (auto &it : hole_to_value) { + pool hole_loc = it.first; + std::string hole_value = it.second; + + for (unsigned int i = 0; i < hole_value.size(); ++i) { + int bit_idx = GetSize(hole_value) - 1 - i; + auto it = hole_loc_idx_to_sigbit.find(std::make_pair(hole_loc, i)); + log_assert(it != hole_loc_idx_to_sigbit.end()); + + RTLIL::SigBit hole_sigbit = it->second; + log("\t%s = 1'b%c\n", log_signal(hole_sigbit), hole_value[bit_idx]); + } + } + } + + void write_solution(RTLIL::Module *module, const std::string &file) const { + std::ofstream fout(file.c_str()); + if (!fout) + log_cmd_error("could not open solution file for writing.\n"); + + //There is a question here: How exactly shall we identify holes? + //There are at least two reasonable options: + //1. By the source location of the $anyconst cells + //2. By the name(s) of the wire(s) connected to each SigBit of the $anyconst cell->getPort(ID::Y) SigSpec. + // + //Option 1 has the benefit of being very precise. There is very limited potential for confusion, as long + //as the source attribute has been set. However, if the source attribute is not set, this won't work. + //More importantly, we want to have the ability to port hole assignments to other modules with compatible + //hole names and widths. Obviously in those cases source locations of the $anyconst cells will not match. + // + //Option 2 has the benefits previously described, but wire names can be changed automatically by + //optimization or techmapping passes, especially when (ex/im)porting from BLIF for optimization with ABC. + // + //The approach taken here is to allow both options. We write the assignment information for each bit of + //the solution on a separate line. Each line is of one of two forms: + // + //location bit name = value + //location bit name [offset] = value + // + //where '[', ']', and '=' are literal symbols, "location" is the $anyconst cell source location attribute, + //"bit" is the index of the $anyconst cell, "name" is the `wire->name` field of the SigBit corresponding + //to the current bit of the $anyconst cell->getPort(ID::Y), "offset" is the `offset` field of that same + //SigBit, and "value", which is either '0' or '1', represents the assignment for that bit. + auto hole_loc_idx_to_sigbit = get_hole_loc_idx_sigbit_map(module); + for (auto &x : hole_to_value) { + std::string src_as_str = std::accumulate(x.first.begin(), x.first.end(), std::string(), [](const std::string &a, const std::string &b){return a + "|" + b;}); + for (auto i = 0; i < GetSize(x.second); ++i) + fout << src_as_str.c_str() << " " << i << " " << log_signal(hole_loc_idx_to_sigbit[std::make_pair(x.first, i)]) << " = " << x.second[GetSize(x.second) - 1 - i] << std::endl; + } + } + + void recover_solution() { + YS_REGEX_TYPE sat_regex = YS_REGEX_COMPILE("Status: PASSED"); + YS_REGEX_TYPE unsat_regex = YS_REGEX_COMPILE("Solver Error.*model is not available"); + YS_REGEX_TYPE unsat_regex2 = YS_REGEX_COMPILE("Status: FAILED"); + YS_REGEX_TYPE timeout_regex = YS_REGEX_COMPILE("No solution found! \\(timeout\\)"); + YS_REGEX_TYPE timeout_regex2 = YS_REGEX_COMPILE("No solution found! \\(interrupted\\)"); + YS_REGEX_TYPE unknown_regex = YS_REGEX_COMPILE("No solution found! \\(unknown\\)"); + YS_REGEX_TYPE unknown_regex2 = YS_REGEX_COMPILE("Unexpected EOF response from solver"); + YS_REGEX_TYPE memout_regex = YS_REGEX_COMPILE("Solver Error:.*error \"out of memory\""); + YS_REGEX_TYPE hole_value_regex = YS_REGEX_COMPILE_WITH_SUBS("Value for anyconst in [a-zA-Z0-9_]* \\(([^:]*:[^\\)]*)\\): (.*)"); +#ifndef NDEBUG + YS_REGEX_TYPE hole_loc_regex = YS_REGEX_COMPILE("[^:]*:[0-9]+.[0-9]+-[0-9]+.[0-9]+"); + YS_REGEX_TYPE hole_val_regex = YS_REGEX_COMPILE("[0-9]+"); +#endif + YS_REGEX_MATCH_TYPE m; + bool sat_regex_found = false; + bool unsat_regex_found = false; + dict hole_value_recovered; + for (const std::string &x : stdout_lines) { + if(YS_REGEX_NS::regex_search(x, m, hole_value_regex)) { + std::string loc = m[1].str(); + std::string val = m[2].str(); +#ifndef NDEBUG + log_assert(YS_REGEX_NS::regex_search(loc, hole_loc_regex)); + log_assert(YS_REGEX_NS::regex_search(val, hole_val_regex)); +#endif + auto locs = split_tokens(loc, "|"); + pool loc_pool(locs.begin(), locs.end()); + hole_to_value[loc_pool] = val; + } + else if (YS_REGEX_NS::regex_search(x, sat_regex)) { + sat_regex_found = true; + sat = true; + unknown = false; + } + else if (YS_REGEX_NS::regex_search(x, unsat_regex)) { + unsat_regex_found = true; + sat = false; + unknown = false; + } + else if (YS_REGEX_NS::regex_search(x, memout_regex)) { + unknown = true; + log_warning("solver ran out of memory\n"); + } + else if (YS_REGEX_NS::regex_search(x, timeout_regex)) { + unknown = true; + log_warning("solver timed out\n"); + } + else if (YS_REGEX_NS::regex_search(x, timeout_regex2)) { + unknown = true; + log_warning("solver timed out\n"); + } + else if (YS_REGEX_NS::regex_search(x, unknown_regex)) { + unknown = true; + log_warning("solver returned \"unknown\"\n"); + } + else if (YS_REGEX_NS::regex_search(x, unsat_regex2)) { + unsat_regex_found = true; + sat = false; + unknown = false; + } + else if (YS_REGEX_NS::regex_search(x, unknown_regex2)) { + unknown = true; + } + } + log_assert(!unknown && sat? sat_regex_found : true); + log_assert(!unknown && !sat? unsat_regex_found : true); + } +}; + +void print_proof_failed() +{ + log("\n"); + log(" ______ ___ ___ _ _ _ _ \n"); + log(" (_____ \\ / __) / __) (_) | | | |\n"); + log(" _____) )___ ___ ___ _| |__ _| |__ _____ _| | _____ __| | |\n"); + log(" | ____/ ___) _ \\ / _ (_ __) (_ __|____ | | || ___ |/ _ |_|\n"); + log(" | | | | | |_| | |_| || | | | / ___ | | || ____( (_| |_ \n"); + log(" |_| |_| \\___/ \\___/ |_| |_| \\_____|_|\\_)_____)\\____|_|\n"); + log("\n"); +} + +void print_qed() +{ + log("\n"); + log(" /$$$$$$ /$$$$$$$$ /$$$$$$$ \n"); + log(" /$$__ $$ | $$_____/ | $$__ $$ \n"); + log(" | $$ \\ $$ | $$ | $$ \\ $$ \n"); + log(" | $$ | $$ | $$$$$ | $$ | $$ \n"); + log(" | $$ | $$ | $$__/ | $$ | $$ \n"); + log(" | $$/$$ $$ | $$ | $$ | $$ \n"); + log(" | $$$$$$/ /$$| $$$$$$$$ /$$| $$$$$$$//$$\n"); + log(" \\____ $$$|__/|________/|__/|_______/|__/\n"); + log(" \\__/ \n"); + log("\n"); +} + +YOSYS_NAMESPACE_END + +#endif From 95e801681146eef6fce177e84701cddf1b822e23 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Mon, 29 Jun 2020 23:01:56 +0000 Subject: [PATCH 024/287] qbfsat: Clean up external executable command lines and update temporary directory name. --- passes/sat/qbfsat.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/passes/sat/qbfsat.cc b/passes/sat/qbfsat.cc index e4dfcaa0c36..8a526ecbe29 100644 --- a/passes/sat/qbfsat.cc +++ b/passes/sat/qbfsat.cc @@ -220,9 +220,13 @@ QbfSolutionType call_qbf_solver(RTLIL::Module *mod, const QbfSolveOptions &opt, //Execute and capture stdout from `yosys-smtbmc -s z3 -t 1 -g --binary [--dump-smt2 ]` QbfSolutionType ret; const std::string yosys_smtbmc_exe = proc_self_dirname() + "yosys-smtbmc"; - const std::string smt2_command = "write_smt2 -stbv -wires " + tempdir_name + "/problem" + (iter_num != 0? stringf("%d", iter_num) : "") + ".smt2"; + const std::string smt2_command = stringf("write_smt2 -stbv -wires %s/problem%d.smt2", tempdir_name.c_str(), iter_num); const std::string smtbmc_warning = "z3: WARNING:"; - const std::string smtbmc_cmd = yosys_smtbmc_exe + " -s " + (opt.get_solver_name()) + (opt.timeout != 0? stringf(" --timeout %d", opt.timeout) : "") + " -t 1 -g --binary " + (opt.dump_final_smt2? "--dump-smt2 " + opt.dump_final_smt2_file + " " : "") + tempdir_name + "/problem" + (iter_num != 0? stringf("%d", iter_num) : "") + ".smt2 2>&1"; + const std::string smtbmc_cmd = stringf("%s -s %s %s -t 1 -g --binary %s %s/problem%d.smt2 2>&1", + yosys_smtbmc_exe.c_str(), opt.get_solver_name().c_str(), + (opt.timeout != 0? stringf("--timeout %d", opt.timeout) : "").c_str(), + (opt.dump_final_smt2? "--dump-smt2 " + opt.dump_final_smt2_file : "").c_str(), + tempdir_name.c_str(), iter_num); Pass::call(mod->design, smt2_command); @@ -249,7 +253,7 @@ QbfSolutionType call_qbf_solver(RTLIL::Module *mod, const QbfSolveOptions &opt, QbfSolutionType qbf_solve(RTLIL::Module *mod, const QbfSolveOptions &opt) { QbfSolutionType ret, best_soln; - const std::string tempdir_name = make_temp_dir("/tmp/yosys-z3-XXXXXX"); + const std::string tempdir_name = make_temp_dir("/tmp/yosys-qbfsat-XXXXXX"); RTLIL::Module *module = mod; RTLIL::Design *design = module->design; std::string module_name = module->name.str(); From 3345d39e6f159c2ae76ddff71d7db2b14a3e535c Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Tue, 30 Jun 2020 06:57:45 +0000 Subject: [PATCH 025/287] qbfsat: Specify default values for some options in the help message. --- passes/sat/qbfsat.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/passes/sat/qbfsat.cc b/passes/sat/qbfsat.cc index 8a526ecbe29..010025ffe60 100644 --- a/passes/sat/qbfsat.cc +++ b/passes/sat/qbfsat.cc @@ -536,9 +536,11 @@ struct QbfSatPass : public Pass { log("\n"); log(" -solver \n"); log(" Use a particular solver. Choose one of: \"z3\", \"yices\", and \"cvc4\".\n"); + log(" (default: yices)\n"); log("\n"); log(" -timeout \n"); log(" Set the per-iteration timeout in seconds.\n"); + log(" (default: no timeout)\n"); log("\n"); log(" -O0, -O1, -O2\n"); log(" Control the use of ABC to simplify the QBF-SAT problem before solving.\n"); From 56f98b9e3d9489503b11e3a406bc3a81c6feb62c Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Tue, 30 Jun 2020 07:00:14 +0000 Subject: [PATCH 026/287] qbfsat: Remove useless comment and #ifndef guards. --- passes/sat/qbfsat.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/passes/sat/qbfsat.cc b/passes/sat/qbfsat.cc index 010025ffe60..46f7f50707a 100644 --- a/passes/sat/qbfsat.cc +++ b/passes/sat/qbfsat.cc @@ -69,7 +69,6 @@ void specialize_from_file(RTLIL::Module *module, const std::string &file) { YS_REGEX_TYPE hole_bit_assn_regex = YS_REGEX_COMPILE_WITH_SUBS("^(.+) ([0-9]+) ([^ ]+) \\[([0-9]+)] = ([01])$"); YS_REGEX_TYPE hole_assn_regex = YS_REGEX_COMPILE_WITH_SUBS("^(.+) ([0-9]+) ([^ ]+) = ([01])$"); //if no index specified YS_REGEX_MATCH_TYPE bit_m, m; - //(hole_loc, hole_bit, hole_name, hole_offset) -> (value, found) dict, RTLIL::Cell*> anyconst_loc_to_cell; dict hole_assignments; @@ -161,9 +160,7 @@ void specialize(RTLIL::Module *module, const QbfSolutionType &sol, bool quiet = void allconstify_inputs(RTLIL::Module *module, const pool &input_wires) { for (auto &n : input_wires) { RTLIL::Wire *input = module->wire(n); -#ifndef NDEBUG log_assert(input != nullptr); -#endif RTLIL::Cell *allconst = module->addCell("$allconst$" + n, "$allconst"); allconst->setParam(ID(WIDTH), input->width); @@ -210,9 +207,7 @@ void assume_miter_outputs(RTLIL::Module *module, bool assume_neg) { wires_to_assume.swap(buf); } -#ifndef NDEBUG log_assert(wires_to_assume.size() == 1); -#endif module->addAssume("$assume_qbfsat_miter_outputs", wires_to_assume[0], RTLIL::S1); } From a9b61080a409d3ad2c8ff4a9bbef9ba1c9c1d194 Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Fri, 3 Jul 2020 11:12:03 +0100 Subject: [PATCH 027/287] Add newlines to help text for dfflegalize I think these were probably missed by accident. Spotted because GCC spits out lots of messages like this: passes/techmap/dfflegalize.cc:114:7: warning: zero-length gnu_printf format string [-Wformat-zero-length] 114 | log(""); | ^~ (because we tell GCC that the first argument to log() looks like a printf control string in log.h, and a zero length such string triggers a warning). --- passes/techmap/dfflegalize.cc | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/passes/techmap/dfflegalize.cc b/passes/techmap/dfflegalize.cc index 013f2d9741e..7f2cdc6acce 100644 --- a/passes/techmap/dfflegalize.cc +++ b/passes/techmap/dfflegalize.cc @@ -111,31 +111,31 @@ struct DffLegalizePass : public Pass { log("- $_DLATCHSR_[NP][NP][NP]_\n"); log("\n"); log("The following transformations are performed by this pass:"); - log(""); + log("\n"); log("- upconversion from a less capable cell to a more capable cell, if the less"); log(" capable cell is not supported (eg. dff -> dffe, or adff -> dffsr)"); - log(""); + log("\n"); log("- unmapping FFs with clock enable (due to unsupported cell type or -mince)"); - log(""); + log("\n"); log("- unmapping FFs with sync reset (due to unsupported cell type or -minsrst)"); - log(""); + log("\n"); log("- adding inverters on the control pins (due to unsupported polarity)"); - log(""); + log("\n"); log("- adding inverters on the D and Q pins and inverting the init/reset values\n"); log(" (due to unsupported init or reset value)"); - log(""); + log("\n"); log("- converting sr into adlatch (by tying D to 1 and using E as set input)"); - log(""); + log("\n"); log("- emulating unsupported dffsr cell by adff + adff + sr + mux"); - log(""); + log("\n"); log("- emulating unsupported dlatchsr cell by adlatch + adlatch + sr + mux"); - log(""); + log("\n"); log("- emulating adff when the (reset, init) value combination is unsupported by\n"); log(" dff + adff + dlatch + mux"); - log(""); + log("\n"); log("- emulating adlatch when the (reset, init) value combination is unsupported by\n"); log("- dlatch + adlatch + dlatch + mux"); - log(""); + log("\n"); log("If the pass is unable to realize a given cell type (eg. adff when only plain dff"); log("is available), an error is raised."); } From 83cde2d02ba06bbd4014858983ac324bf44cb6c6 Mon Sep 17 00:00:00 2001 From: Dan Ravensloft Date: Sat, 23 May 2020 12:52:13 +0100 Subject: [PATCH 028/287] intel_alm: ABC9 sequential optimisations --- techlibs/intel_alm/Makefile.inc | 3 ++ techlibs/intel_alm/common/abc9_map.v | 18 +++++++++ techlibs/intel_alm/common/abc9_model.v | 55 ++++++++++++++++++++++++++ techlibs/intel_alm/common/abc9_unmap.v | 11 ++++++ techlibs/intel_alm/common/dff_sim.v | 42 +++++++++++++++----- techlibs/intel_alm/common/mem_sim.v | 10 +++++ techlibs/intel_alm/synth_intel_alm.cc | 29 +++++++++----- 7 files changed, 149 insertions(+), 19 deletions(-) create mode 100644 techlibs/intel_alm/common/abc9_map.v create mode 100644 techlibs/intel_alm/common/abc9_model.v create mode 100644 techlibs/intel_alm/common/abc9_unmap.v diff --git a/techlibs/intel_alm/Makefile.inc b/techlibs/intel_alm/Makefile.inc index ed6c4510b95..477be63535d 100644 --- a/techlibs/intel_alm/Makefile.inc +++ b/techlibs/intel_alm/Makefile.inc @@ -2,6 +2,9 @@ OBJS += techlibs/intel_alm/synth_intel_alm.o # Techmap +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/abc9_map.v)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/abc9_unmap.v)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/abc9_model.v)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/alm_map.v)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/alm_sim.v)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/arith_alm_map.v)) diff --git a/techlibs/intel_alm/common/abc9_map.v b/techlibs/intel_alm/common/abc9_map.v new file mode 100644 index 00000000000..32ad79bdcc7 --- /dev/null +++ b/techlibs/intel_alm/common/abc9_map.v @@ -0,0 +1,18 @@ +// This file exists to map purely-synchronous flops to ABC9 flops, while +// mapping flops with asynchronous-clear as boxes, this is because ABC9 +// doesn't support asynchronous-clear flops in sequential synthesis. + +module MISTRAL_FF( + input DATAIN, CLK, ACLR, ENA, SCLR, SLOAD, SDATA, + output reg Q +); + +parameter _TECHMAP_CONSTMSK_ACLR_ = 1'b0; + +// If the async-clear is constant, we assume it's disabled. +if (_TECHMAP_CONSTMSK_ACLR_ != 1'b0) + MISTRAL_FF_SYNCONLY _TECHMAP_REPLACE_ (.DATAIN(DATAIN), .CLK(CLK), .ENA(ENA), .SCLR(SCLR), .SLOAD(SLOAD), .SDATA(SDATA), .Q(Q)); +else + wire _TECHMAP_FAIL_ = 1; + +endmodule diff --git a/techlibs/intel_alm/common/abc9_model.v b/techlibs/intel_alm/common/abc9_model.v new file mode 100644 index 00000000000..dd46147a5c7 --- /dev/null +++ b/techlibs/intel_alm/common/abc9_model.v @@ -0,0 +1,55 @@ +`ifdef cyclonev +`define SYNCPATH 262 +`define SYNCSETUP 522 +`define COMBPATH 0 +`endif +`ifdef cyclone10gx +`define SYNCPATH 219 +`define SYNCSETUP 268 +`define COMBPATH 0 +`endif + +// fallback for when a family isn't detected (e.g. when techmapping for equivalence) +`ifndef SYNCPATH +`define SYNCPATH 0 +`define SYNCSETUP 0 +`define COMBPATH 0 +`endif + +// This is a purely-synchronous flop, that ABC9 can use for sequential synthesis. +(* abc9_flop, lib_whitebox *) +module MISTRAL_FF_SYNCONLY( + input DATAIN, CLK, ENA, SCLR, SLOAD, SDATA, + output reg Q +); + +specify + if (ENA) (posedge CLK => (Q : DATAIN)) = `SYNCPATH; + if (ENA) (posedge CLK => (Q : SCLR)) = `SYNCPATH; + if (ENA) (posedge CLK => (Q : SLOAD)) = `SYNCPATH; + if (ENA) (posedge CLK => (Q : SDATA)) = `SYNCPATH; + + $setup(DATAIN, posedge CLK, `SYNCSETUP); + $setup(ENA, posedge CLK, `SYNCSETUP); + $setup(SCLR, posedge CLK, `SYNCSETUP); + $setup(SLOAD, posedge CLK, `SYNCSETUP); + $setup(SDATA, posedge CLK, `SYNCSETUP); +endspecify + +initial begin + // Altera flops initialise to zero. + Q = 0; +end + +always @(posedge CLK) begin + // Clock-enable + if (ENA) begin + // Synchronous clear + if (SCLR) Q <= 0; + // Synchronous load + else if (SLOAD) Q <= SDATA; + else Q <= DATAIN; + end +end + +endmodule diff --git a/techlibs/intel_alm/common/abc9_unmap.v b/techlibs/intel_alm/common/abc9_unmap.v new file mode 100644 index 00000000000..0eda69560cf --- /dev/null +++ b/techlibs/intel_alm/common/abc9_unmap.v @@ -0,0 +1,11 @@ +// After performing sequential synthesis, map the synchronous flops back to +// standard MISTRAL_FF flops. + +module MISTRAL_FF_SYNCONLY( + input DATAIN, CLK, ENA, SCLR, SLOAD, SDATA, + output reg Q +); + +MISTRAL_FF _TECHMAP_REPLACE_ (.DATAIN(DATAIN), .CLK(CLK), .ACLR(1'b1), .ENA(ENA), .SCLR(SCLR), .SLOAD(SLOAD), .SDATA(SDATA), .Q(Q)); + +endmodule diff --git a/techlibs/intel_alm/common/dff_sim.v b/techlibs/intel_alm/common/dff_sim.v index 32444dd46e8..94aa37fb56b 100644 --- a/techlibs/intel_alm/common/dff_sim.v +++ b/techlibs/intel_alm/common/dff_sim.v @@ -53,23 +53,45 @@ // Q: data output // // Note: the DFFEAS primitive is mostly emulated; it does not reflect what the hardware implements. + +`ifdef cyclonev +`define SYNCPATH 262 +`define SYNCSETUP 522 +`define COMBPATH 0 +`endif +`ifdef cyclone10gx +`define SYNCPATH 219 +`define SYNCSETUP 268 +`define COMBPATH 0 +`endif + +// fallback for when a family isn't detected (e.g. when techmapping for equivalence) +`ifndef SYNCPATH +`define SYNCPATH 0 +`define SYNCSETUP 0 +`define COMBPATH 0 +`endif + +(* abc9_box, lib_whitebox *) module MISTRAL_FF( input DATAIN, CLK, ACLR, ENA, SCLR, SLOAD, SDATA, output reg Q ); -`ifdef cyclonev -specify - (posedge CLK => (Q : DATAIN)) = 262; - $setup(DATAIN, posedge CLK, 522); -endspecify -`endif -`ifdef cyclone10gx specify - (posedge CLK => (Q : DATAIN)) = 219; - $setup(DATAIN, posedge CLK, 268); + if (ENA) (posedge CLK => (Q : DATAIN)) = `SYNCPATH; + if (ENA) (posedge CLK => (Q : SCLR)) = `SYNCPATH; + if (ENA) (posedge CLK => (Q : SLOAD)) = `SYNCPATH; + if (ENA) (posedge CLK => (Q : SDATA)) = `SYNCPATH; + + $setup(DATAIN, posedge CLK, `SYNCSETUP); + $setup(ENA, posedge CLK, `SYNCSETUP); + $setup(SCLR, posedge CLK, `SYNCSETUP); + $setup(SLOAD, posedge CLK, `SYNCSETUP); + $setup(SDATA, posedge CLK, `SYNCSETUP); + + (ACLR => Q) = `COMBPATH; endspecify -`endif initial begin // Altera flops initialise to zero. diff --git a/techlibs/intel_alm/common/mem_sim.v b/techlibs/intel_alm/common/mem_sim.v index ae79b19a42e..f6f9ecb02b0 100644 --- a/techlibs/intel_alm/common/mem_sim.v +++ b/techlibs/intel_alm/common/mem_sim.v @@ -48,10 +48,20 @@ // the following model because it's very difficult to trigger this in practice // as clock cycles will be much longer than any potential blip of 'x, so the // model can be treated as always returning a defined result. + +(* abc9_box, lib_whitebox *) module MISTRAL_MLAB(input [4:0] A1ADDR, input A1DATA, A1EN, CLK1, input [4:0] B1ADDR, output B1DATA); reg [31:0] mem = 32'b0; +// TODO +specify + $setup(A1ADDR, posedge CLK1, 0); + $setup(A1DATA, posedge CLK1, 0); + + (B1ADDR *> B1DATA) = 0; +endspecify + always @(posedge CLK1) if (A1EN) mem[A1ADDR] <= A1DATA; diff --git a/techlibs/intel_alm/synth_intel_alm.cc b/techlibs/intel_alm/synth_intel_alm.cc index fabfc9003e3..982857dd587 100644 --- a/techlibs/intel_alm/synth_intel_alm.cc +++ b/techlibs/intel_alm/synth_intel_alm.cc @@ -38,20 +38,26 @@ struct SynthIntelALMPass : public ScriptPass { log("This command runs synthesis for ALM-based Intel FPGAs.\n"); log("\n"); log(" -top \n"); - log(" use the specified module as top module (default='top')\n"); + log(" use the specified module as top module\n"); log("\n"); log(" -family \n"); log(" target one of:\n"); log(" \"cyclonev\" - Cyclone V (default)\n"); log(" \"cyclone10gx\" - Cyclone 10GX\n"); log("\n"); - log(" -quartus\n"); - log(" output a netlist using Quartus cells instead of MISTRAL_* cells\n"); - log("\n"); log(" -vqm \n"); log(" write the design to the specified Verilog Quartus Mapping File. Writing of an\n"); log(" output file is omitted if this parameter is not specified. Implies -quartus.\n"); log("\n"); + log(" -noflatten\n"); + log(" do not flatten design before synthesis; useful for per-module area statistics\n"); + log("\n"); + log(" -quartus\n"); + log(" output a netlist using Quartus cells instead of MISTRAL_* cells\n"); + log("\n"); + log(" -dff\n"); + log(" pass DFFs to ABC to perform sequential logic optimisations (EXPERIMENTAL)\n"); + log("\n"); log(" -run :\n"); log(" only run the commands between the labels (see below). an empty\n"); log(" from label is synonymous to 'begin', and empty to label is\n"); @@ -63,16 +69,13 @@ struct SynthIntelALMPass : public ScriptPass { log(" -nobram\n"); log(" do not use block RAM cells in output netlist\n"); log("\n"); - log(" -noflatten\n"); - log(" do not flatten design before synthesis\n"); - log("\n"); log("The following commands are executed by this synthesis command:\n"); help_script(); log("\n"); } string top_opt, family_opt, bram_type, vout_file; - bool flatten, quartus, nolutram, nobram; + bool flatten, quartus, nolutram, nobram, dff; void clear_flags() override { @@ -84,6 +87,7 @@ struct SynthIntelALMPass : public ScriptPass { quartus = false; nolutram = false; nobram = false; + dff = false; } void execute(std::vector args, RTLIL::Design *design) override @@ -130,6 +134,10 @@ struct SynthIntelALMPass : public ScriptPass { flatten = false; continue; } + if (args[argidx] == "-dff") { + dff = true; + continue; + } break; } extra_args(args, argidx, design); @@ -165,6 +173,7 @@ struct SynthIntelALMPass : public ScriptPass { run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/alm_sim.v", family_opt.c_str())); run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/dff_sim.v", family_opt.c_str())); run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/mem_sim.v", family_opt.c_str())); + run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/abc9_model.v", family_opt.c_str())); // Misc and common cells run("read_verilog -lib +/intel/common/altpll_bb.v"); @@ -209,7 +218,9 @@ struct SynthIntelALMPass : public ScriptPass { } if (check_label("map_luts")) { - run("abc9 -maxlut 6 -W 200"); + run("techmap -map +/intel_alm/common/abc9_map.v"); + run(stringf("abc9 %s -maxlut 6 -W 200", help_mode ? "[-dff]" : dff ? "-dff" : "")); + run("techmap -map +/intel_alm/common/abc9_unmap.v"); run("techmap -map +/intel_alm/common/alm_map.v"); run("opt -fast"); run("autoname"); From 3db3e1e1491b426766f1da87e1da840f3fa46278 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 25 May 2020 15:15:20 -0700 Subject: [PATCH 029/287] intel_alm: add $__ prefix to MISTRAL_FF_SYNCONLY --- techlibs/intel_alm/common/abc9_map.v | 2 +- techlibs/intel_alm/common/abc9_model.v | 2 +- techlibs/intel_alm/common/abc9_unmap.v | 2 +- techlibs/intel_alm/synth_intel_alm.cc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/techlibs/intel_alm/common/abc9_map.v b/techlibs/intel_alm/common/abc9_map.v index 32ad79bdcc7..9d11bb24093 100644 --- a/techlibs/intel_alm/common/abc9_map.v +++ b/techlibs/intel_alm/common/abc9_map.v @@ -11,7 +11,7 @@ parameter _TECHMAP_CONSTMSK_ACLR_ = 1'b0; // If the async-clear is constant, we assume it's disabled. if (_TECHMAP_CONSTMSK_ACLR_ != 1'b0) - MISTRAL_FF_SYNCONLY _TECHMAP_REPLACE_ (.DATAIN(DATAIN), .CLK(CLK), .ENA(ENA), .SCLR(SCLR), .SLOAD(SLOAD), .SDATA(SDATA), .Q(Q)); + $__MISTRAL_FF_SYNCONLY _TECHMAP_REPLACE_ (.DATAIN(DATAIN), .CLK(CLK), .ENA(ENA), .SCLR(SCLR), .SLOAD(SLOAD), .SDATA(SDATA), .Q(Q)); else wire _TECHMAP_FAIL_ = 1; diff --git a/techlibs/intel_alm/common/abc9_model.v b/techlibs/intel_alm/common/abc9_model.v index dd46147a5c7..8ad52e13ac0 100644 --- a/techlibs/intel_alm/common/abc9_model.v +++ b/techlibs/intel_alm/common/abc9_model.v @@ -18,7 +18,7 @@ // This is a purely-synchronous flop, that ABC9 can use for sequential synthesis. (* abc9_flop, lib_whitebox *) -module MISTRAL_FF_SYNCONLY( +module $__MISTRAL_FF_SYNCONLY ( input DATAIN, CLK, ENA, SCLR, SLOAD, SDATA, output reg Q ); diff --git a/techlibs/intel_alm/common/abc9_unmap.v b/techlibs/intel_alm/common/abc9_unmap.v index 0eda69560cf..4b28866a3a6 100644 --- a/techlibs/intel_alm/common/abc9_unmap.v +++ b/techlibs/intel_alm/common/abc9_unmap.v @@ -1,7 +1,7 @@ // After performing sequential synthesis, map the synchronous flops back to // standard MISTRAL_FF flops. -module MISTRAL_FF_SYNCONLY( +module $__MISTRAL_FF_SYNCONLY ( input DATAIN, CLK, ENA, SCLR, SLOAD, SDATA, output reg Q ); diff --git a/techlibs/intel_alm/synth_intel_alm.cc b/techlibs/intel_alm/synth_intel_alm.cc index 982857dd587..4bc943cb266 100644 --- a/techlibs/intel_alm/synth_intel_alm.cc +++ b/techlibs/intel_alm/synth_intel_alm.cc @@ -173,7 +173,7 @@ struct SynthIntelALMPass : public ScriptPass { run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/alm_sim.v", family_opt.c_str())); run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/dff_sim.v", family_opt.c_str())); run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/mem_sim.v", family_opt.c_str())); - run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/abc9_model.v", family_opt.c_str())); + run(stringf("read_verilog -specify -lib -D %s -icells +/intel_alm/common/abc9_model.v", family_opt.c_str())); // Misc and common cells run("read_verilog -lib +/intel/common/altpll_bb.v"); From 0ba79feb6f0b77120f113dec268908bf25306581 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 26 May 2020 08:37:26 -0700 Subject: [PATCH 030/287] abc9: techmap from user design to allow abc9_flop modules to be composed from other primitives --- passes/techmap/abc9.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 127f8934e3d..7c8eba17778 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -294,7 +294,7 @@ struct Abc9Pass : public ScriptPass run("design -load $abc9_map"); run("proc"); run("wbflip"); - run("techmap"); + run("techmap -wb -map %$abc9 -map +/techmap.v"); run("opt"); if (dff_mode || help_mode) { if (!help_mode) From 2bdced0d68f3f3a1ea43741c49435d482698a8ca Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 26 May 2020 08:38:11 -0700 Subject: [PATCH 031/287] intel_alm: compose $__MISTRAL_FF_SYNCONLY from MISTRAL_FF --- techlibs/intel_alm/common/abc9_model.v | 47 +------------------------- techlibs/intel_alm/common/dff_sim.v | 2 +- 2 files changed, 2 insertions(+), 47 deletions(-) diff --git a/techlibs/intel_alm/common/abc9_model.v b/techlibs/intel_alm/common/abc9_model.v index 8ad52e13ac0..8f06d38353b 100644 --- a/techlibs/intel_alm/common/abc9_model.v +++ b/techlibs/intel_alm/common/abc9_model.v @@ -1,21 +1,3 @@ -`ifdef cyclonev -`define SYNCPATH 262 -`define SYNCSETUP 522 -`define COMBPATH 0 -`endif -`ifdef cyclone10gx -`define SYNCPATH 219 -`define SYNCSETUP 268 -`define COMBPATH 0 -`endif - -// fallback for when a family isn't detected (e.g. when techmapping for equivalence) -`ifndef SYNCPATH -`define SYNCPATH 0 -`define SYNCSETUP 0 -`define COMBPATH 0 -`endif - // This is a purely-synchronous flop, that ABC9 can use for sequential synthesis. (* abc9_flop, lib_whitebox *) module $__MISTRAL_FF_SYNCONLY ( @@ -23,33 +5,6 @@ module $__MISTRAL_FF_SYNCONLY ( output reg Q ); -specify - if (ENA) (posedge CLK => (Q : DATAIN)) = `SYNCPATH; - if (ENA) (posedge CLK => (Q : SCLR)) = `SYNCPATH; - if (ENA) (posedge CLK => (Q : SLOAD)) = `SYNCPATH; - if (ENA) (posedge CLK => (Q : SDATA)) = `SYNCPATH; - - $setup(DATAIN, posedge CLK, `SYNCSETUP); - $setup(ENA, posedge CLK, `SYNCSETUP); - $setup(SCLR, posedge CLK, `SYNCSETUP); - $setup(SLOAD, posedge CLK, `SYNCSETUP); - $setup(SDATA, posedge CLK, `SYNCSETUP); -endspecify - -initial begin - // Altera flops initialise to zero. - Q = 0; -end - -always @(posedge CLK) begin - // Clock-enable - if (ENA) begin - // Synchronous clear - if (SCLR) Q <= 0; - // Synchronous load - else if (SLOAD) Q <= SDATA; - else Q <= DATAIN; - end -end +MISTRAL_FF ff (.DATAIN(DATAIN), .CLK(CLK), .ENA(ENA), .ACLR(1'b1), .SCLR(SCLR), .SLOAD(SLOAD), .SDATA(SDATA), .Q(Q)); endmodule diff --git a/techlibs/intel_alm/common/dff_sim.v b/techlibs/intel_alm/common/dff_sim.v index 94aa37fb56b..38e3d661837 100644 --- a/techlibs/intel_alm/common/dff_sim.v +++ b/techlibs/intel_alm/common/dff_sim.v @@ -90,7 +90,7 @@ specify $setup(SLOAD, posedge CLK, `SYNCSETUP); $setup(SDATA, posedge CLK, `SYNCSETUP); - (ACLR => Q) = `COMBPATH; + if (!ACLR) (ACLR => Q) = `COMBPATH; endspecify initial begin From 27a9d1b6e68a2d8c6db03524fff8fa832a7b6583 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 27 May 2020 09:37:57 -0700 Subject: [PATCH 032/287] abc9: only techmap (* abc9_flop *) modules --- passes/techmap/abc9.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 7c8eba17778..e99c56d8d73 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -294,7 +294,7 @@ struct Abc9Pass : public ScriptPass run("design -load $abc9_map"); run("proc"); run("wbflip"); - run("techmap -wb -map %$abc9 -map +/techmap.v"); + run("techmap -wb -map %$abc9 -map +/techmap.v A:abc9_flop"); run("opt"); if (dff_mode || help_mode) { if (!help_mode) From 52fbaeca07a5d8d0a3776d56665dc3bdaadf96b4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 27 May 2020 12:49:16 -0700 Subject: [PATCH 033/287] tests: update fsm.ys resource count Suspect it is to do with map/set ordering in techmap; should be fixed by #1862? --- tests/arch/intel_alm/fsm.ys | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/arch/intel_alm/fsm.ys b/tests/arch/intel_alm/fsm.ys index 67965569b33..20321c62f1f 100644 --- a/tests/arch/intel_alm/fsm.ys +++ b/tests/arch/intel_alm/fsm.ys @@ -13,7 +13,7 @@ cd fsm # Constrain all select calls below inside the top module select -assert-count 6 t:MISTRAL_FF select -assert-max 2 t:MISTRAL_ALUT2 # Clang returns 2, GCC returns 1 -select -assert-count 1 t:MISTRAL_ALUT3 -select -assert-count 5 t:MISTRAL_ALUT5 -select -assert-count 2 t:MISTRAL_ALUT6 -select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D +select -assert-max 1 t:MISTRAL_ALUT4 # Clang returns 0, GCC returns 1 +select -assert-max 5 t:MISTRAL_ALUT5 # Clang returns 5, GCC returns 4 +select -assert-max 2 t:MISTRAL_ALUT6 # Clang returns 1, GCC returns 2 +select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT2 t:MISTRAL_ALUT4 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D From c6765443fdb57938418fb2b80bf56cda0e7d229b Mon Sep 17 00:00:00 2001 From: Dan Ravensloft Date: Thu, 28 May 2020 11:33:19 +0100 Subject: [PATCH 034/287] Improve MISTRAL_FF specify rules Co-authored-by: Eddie Hung --- techlibs/intel_alm/common/dff_sim.v | 9 ++++----- tests/arch/intel_alm/fsm.ys | 3 ++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/techlibs/intel_alm/common/dff_sim.v b/techlibs/intel_alm/common/dff_sim.v index 38e3d661837..9ff8f9f6715 100644 --- a/techlibs/intel_alm/common/dff_sim.v +++ b/techlibs/intel_alm/common/dff_sim.v @@ -79,10 +79,9 @@ module MISTRAL_FF( ); specify - if (ENA) (posedge CLK => (Q : DATAIN)) = `SYNCPATH; - if (ENA) (posedge CLK => (Q : SCLR)) = `SYNCPATH; - if (ENA) (posedge CLK => (Q : SLOAD)) = `SYNCPATH; - if (ENA) (posedge CLK => (Q : SDATA)) = `SYNCPATH; + if (ENA && ACLR !== 1'b0 && !SCLR && !SLOAD) (posedge CLK => (Q : DATAIN)) = `SYNCPATH; + if (ENA && SCLR) (posedge CLK => (Q : 1'b0)) = `SYNCPATH; + if (ENA && !SCLR && SLOAD) (posedge CLK => (Q : SDATA)) = `SYNCPATH; $setup(DATAIN, posedge CLK, `SYNCSETUP); $setup(ENA, posedge CLK, `SYNCSETUP); @@ -90,7 +89,7 @@ specify $setup(SLOAD, posedge CLK, `SYNCSETUP); $setup(SDATA, posedge CLK, `SYNCSETUP); - if (!ACLR) (ACLR => Q) = `COMBPATH; + if (ACLR === 1'b0) (ACLR => Q) = `COMBPATH; endspecify initial begin diff --git a/tests/arch/intel_alm/fsm.ys b/tests/arch/intel_alm/fsm.ys index 20321c62f1f..02e4a9789bb 100644 --- a/tests/arch/intel_alm/fsm.ys +++ b/tests/arch/intel_alm/fsm.ys @@ -13,7 +13,8 @@ cd fsm # Constrain all select calls below inside the top module select -assert-count 6 t:MISTRAL_FF select -assert-max 2 t:MISTRAL_ALUT2 # Clang returns 2, GCC returns 1 +select -assert-count 1 t:MISTRAL_ALUT3 select -assert-max 1 t:MISTRAL_ALUT4 # Clang returns 0, GCC returns 1 select -assert-max 5 t:MISTRAL_ALUT5 # Clang returns 5, GCC returns 4 select -assert-max 2 t:MISTRAL_ALUT6 # Clang returns 1, GCC returns 2 -select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT2 t:MISTRAL_ALUT4 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D +select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_ALUT4 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D From 6b0ac04698d62c33bcf9309d9f69d09b7b614c1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Sat, 4 Jul 2020 20:49:28 +0200 Subject: [PATCH 035/287] efinix: Nuke efinix_gbuf in favor of clkbufmap. --- techlibs/efinix/Makefile.inc | 2 +- techlibs/efinix/cells_sim.v | 6 +- techlibs/efinix/efinix_gbuf.cc | 119 -------------------------------- techlibs/efinix/gbuf_map.v | 3 + techlibs/efinix/synth_efinix.cc | 3 +- 5 files changed, 11 insertions(+), 122 deletions(-) delete mode 100644 techlibs/efinix/efinix_gbuf.cc create mode 100644 techlibs/efinix/gbuf_map.v diff --git a/techlibs/efinix/Makefile.inc b/techlibs/efinix/Makefile.inc index 69665982c88..2a3a953e349 100644 --- a/techlibs/efinix/Makefile.inc +++ b/techlibs/efinix/Makefile.inc @@ -1,10 +1,10 @@ OBJS += techlibs/efinix/synth_efinix.o -OBJS += techlibs/efinix/efinix_gbuf.o OBJS += techlibs/efinix/efinix_fixcarry.o $(eval $(call add_share_file,share/efinix,techlibs/efinix/cells_map.v)) $(eval $(call add_share_file,share/efinix,techlibs/efinix/arith_map.v)) $(eval $(call add_share_file,share/efinix,techlibs/efinix/cells_sim.v)) $(eval $(call add_share_file,share/efinix,techlibs/efinix/brams_map.v)) +$(eval $(call add_share_file,share/efinix,techlibs/efinix/gbuf_map.v)) $(eval $(call add_share_file,share/efinix,techlibs/efinix/brams.txt)) diff --git a/techlibs/efinix/cells_sim.v b/techlibs/efinix/cells_sim.v index a74d1c571b5..22c7bc776da 100644 --- a/techlibs/efinix/cells_sim.v +++ b/techlibs/efinix/cells_sim.v @@ -36,6 +36,7 @@ module EFX_FF( output reg Q, input D, input CE, + (* clkbuf_sink *) input CLK, input SR ); @@ -100,6 +101,7 @@ endmodule module EFX_GBUFCE( input CE, input I, + (* clkbuf_driver *) output O ); parameter CE_POLARITY = 1'b1; @@ -115,11 +117,13 @@ module EFX_RAM_5K( input [WRITE_WIDTH-1:0] WDATA, input [WRITE_ADDR_WIDTH-1:0] WADDR, input WE, + (* clkbuf_sink *) input WCLK, input WCLKE, output [READ_WIDTH-1:0] RDATA, input [READ_ADDR_WIDTH-1:0] RADDR, input RE, + (* clkbuf_sink *) input RCLK ); parameter READ_WIDTH = 20; @@ -172,4 +176,4 @@ module EFX_RAM_5K( (WRITE_WIDTH == 10) ? 9 : // 512x10 (WRITE_WIDTH == 5) ? 10 : -1; // 1024x5 -endmodule \ No newline at end of file +endmodule diff --git a/techlibs/efinix/efinix_gbuf.cc b/techlibs/efinix/efinix_gbuf.cc deleted file mode 100644 index ae191359a70..00000000000 --- a/techlibs/efinix/efinix_gbuf.cc +++ /dev/null @@ -1,119 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2019 Miodrag Milanovic - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" -#include "kernel/sigtools.h" - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -static void handle_gbufs(Module *module) -{ - SigMap sigmap(module); - - pool clk_bits; - dict rewrite_bits; - vector> pad_bits; - - for (auto cell : module->cells()) - { - if (cell->type == ID(EFX_FF)) { - for (auto bit : sigmap(cell->getPort(ID::CLK))) - clk_bits.insert(bit); - } - if (cell->type == ID(EFX_RAM_5K)) { - for (auto bit : sigmap(cell->getPort(ID(RCLK)))) - clk_bits.insert(bit); - for (auto bit : sigmap(cell->getPort(ID(WCLK)))) - clk_bits.insert(bit); - } - } - - for (auto wire : vector(module->wires())) - { - if (!wire->port_input) - continue; - - for (int index = 0; index < GetSize(wire); index++) - { - SigBit bit(wire, index); - SigBit canonical_bit = sigmap(bit); - - if (!clk_bits.count(canonical_bit)) - continue; - - Cell *c = module->addCell(NEW_ID, ID(EFX_GBUFCE)); - SigBit new_bit = module->addWire(NEW_ID); - c->setParam(ID(CE_POLARITY), State::S1); - c->setPort(ID::O, new_bit); - c->setPort(ID(CE), State::S1); - pad_bits.push_back(make_pair(c, bit)); - rewrite_bits[canonical_bit] = new_bit; - - log("Added %s cell %s for port bit %s.\n", log_id(c->type), log_id(c), log_signal(bit)); - } - } - - auto rewrite_function = [&](SigSpec &s) { - for (auto &bit : s) { - SigBit canonical_bit = sigmap(bit); - if (rewrite_bits.count(canonical_bit)) - bit = rewrite_bits.at(canonical_bit); - } - }; - - module->rewrite_sigspecs(rewrite_function); - - for (auto &it : pad_bits) - it.first->setPort(ID::I, it.second); -} - -struct EfinixGbufPass : public Pass { - EfinixGbufPass() : Pass("efinix_gbuf", "Efinix: insert global clock buffers") { } - void help() override - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" efinix_gbuf [options] [selection]\n"); - log("\n"); - log("Add Efinix global clock buffers to top module as needed.\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) override - { - log_header(design, "Executing efinix_gbuf pass (insert global clock buffers).\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - break; - } - extra_args(args, argidx, design); - - Module *module = design->top_module(); - - if (module == nullptr) - log_cmd_error("No top module found.\n"); - - handle_gbufs(module); - } -} EfinixGbufPass; - -PRIVATE_NAMESPACE_END diff --git a/techlibs/efinix/gbuf_map.v b/techlibs/efinix/gbuf_map.v new file mode 100644 index 00000000000..43e0c9ac3f6 --- /dev/null +++ b/techlibs/efinix/gbuf_map.v @@ -0,0 +1,3 @@ +module \$__EFX_GBUF (input I, output O); + EFX_GBUFCE #(.CE_POLARITY(1'b1)) _TECHMAP_REPLACE_ (.I(I), .O(O), .CE(1'b1)); +endmodule diff --git a/techlibs/efinix/synth_efinix.cc b/techlibs/efinix/synth_efinix.cc index 6ca44eed140..cc926235f68 100644 --- a/techlibs/efinix/synth_efinix.cc +++ b/techlibs/efinix/synth_efinix.cc @@ -202,7 +202,8 @@ struct SynthEfinixPass : public ScriptPass if (check_label("map_gbuf")) { - run("efinix_gbuf"); + run("clkbufmap -buf $__EFX_GBUF O:I"); + run("techmap -map +/efinix/gbuf_map.v"); run("efinix_fixcarry"); run("clean"); } From 7d5828a70635e3934300c15b5b6a89430a0f0355 Mon Sep 17 00:00:00 2001 From: Dan Ravensloft Date: Sat, 4 Jul 2020 19:59:39 +0100 Subject: [PATCH 036/287] Add option to use ccache when building --- Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Makefile b/Makefile index 3d3e60359b1..b9c3d14eb1e 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,7 @@ ENABLE_GCOV := 0 ENABLE_GPROF := 0 ENABLE_DEBUG := 0 ENABLE_NDEBUG := 0 +ENABLE_CCACHE := 0 LINK_CURSES := 0 LINK_TERMCAP := 0 LINK_ABC := 0 @@ -528,6 +529,10 @@ ifeq ($(ENABLE_COVER),1) CXXFLAGS += -DYOSYS_ENABLE_COVER endif +ifeq ($(ENABLE_CCACHE),1) +CXX := ccache $(CXX) +endif + define add_share_file EXTRA_TARGETS += $(subst //,/,$(1)/$(notdir $(2))) $(subst //,/,$(1)/$(notdir $(2))): $(2) From 3ca2de0f772b3f08f2169f6b93518c8a94ffb23a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Wed, 1 Jul 2020 03:31:34 +0200 Subject: [PATCH 037/287] synth_intel_alm: Use dfflegalize. --- techlibs/intel_alm/common/dff_map.v | 123 ++------------------------ techlibs/intel_alm/synth_intel_alm.cc | 7 +- tests/arch/intel_alm/fsm.ys | 2 +- 3 files changed, 10 insertions(+), 122 deletions(-) diff --git a/techlibs/intel_alm/common/dff_map.v b/techlibs/intel_alm/common/dff_map.v index 962be670c65..1a4b5d65a0f 100644 --- a/techlibs/intel_alm/common/dff_map.v +++ b/techlibs/intel_alm/common/dff_map.v @@ -1,124 +1,13 @@ `default_nettype none -// D flip-flops -module \$_DFF_P_ (input D, C, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b0; -if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin +// D flip-flop with async reset and enable +module \$_DFFE_PN0P_ (input D, C, R, E, output Q); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Cannot implement a flip-flop that initialises to one"); + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(R), .ENA(E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); endmodule -module \$_DFF_N_ (input D, C, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b0; -if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin +// D flip-flop with sync reset and enable (enable has priority) +module \$_SDFFCE_PP0P_ (input D, C, R, E, output Q); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(1'b1), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Cannot implement a flip-flop that initialises to one"); -endmodule - -// D flip-flops with reset -module \$_DFF_PP0_ (input D, C, R, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b0; -if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Cannot implement a flip-flop with reset that initialises to one"); -endmodule - -module \$_DFF_PN0_ (input D, C, R, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b0; -if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Cannot implement a flip-flop with reset that initialises to one"); -endmodule - -module \$_DFF_NP0_ (input D, C, R, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b0; -if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Cannot implement a flip-flop with reset that initialises to one"); -endmodule - -module \$_DFF_NN0_ (input D, C, R, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b0; -if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Cannot implement a flip-flop with reset that initialises to one"); -endmodule - -// D flip-flops with set -module \$_DFF_PP1_ (input D, C, R, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b1; -if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - wire Q_tmp; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp)); - assign Q = ~Q_tmp; -end else $error("Cannot implement a flip-flop with set that initialises to zero"); -endmodule - -module \$_DFF_PN1_ (input D, C, R, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b1; -if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - wire Q_tmp; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp)); -end else $error("Cannot implement a flip-flop with set that initialises to zero"); -endmodule - -module \$_DFF_NP1_ (input D, C, R, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b1; -if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - wire Q_tmp; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(~C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp)); - assign Q = ~Q_tmp; -end else $error("Cannot implement a flip-flop with set that initialises to zero"); -endmodule - -module \$_DFF_NN1_ (input D, C, R, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b1; -if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - wire Q_tmp; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(~C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp)); - assign Q = ~Q_tmp; -end else $error("Cannot implement a flip-flop with set that initialises to zero"); -endmodule - -// D flip-flops with clock enable -module \$_DFFE_PP_ (input D, C, E, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b0; -if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Cannot implement a flip-flop with enable that initialises to one"); -endmodule - -module \$_DFFE_PN_ (input D, C, E, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b0; -if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(~E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Cannot implement a flip-flop with enable that initialises to one"); -endmodule - -module \$_DFFE_NP_ (input D, C, E, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b0; -if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(1'b1), .ENA(E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Cannot implement a flip-flop with enable that initialises to one"); -endmodule - -module \$_DFFE_NN_ (input D, C, E, output Q); -parameter _TECHMAP_WIREINIT_Q_ = 1'b0; -if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin - wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; - MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(1'b1), .ENA(~E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Cannot implement a flip-flop with enable that initialises to one"); + MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(E), .SCLR(R), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); endmodule diff --git a/techlibs/intel_alm/synth_intel_alm.cc b/techlibs/intel_alm/synth_intel_alm.cc index 4bc943cb266..4170274622c 100644 --- a/techlibs/intel_alm/synth_intel_alm.cc +++ b/techlibs/intel_alm/synth_intel_alm.cc @@ -208,11 +208,10 @@ struct SynthIntelALMPass : public ScriptPass { } if (check_label("map_ffs")) { + run("techmap"); run("dff2dffe"); - // As mentioned in common/dff_sim.v, Intel flops power up to zero, - // so use `zinit` to add inverters where needed. - run("zinit"); - run("techmap -map +/techmap.v -map +/intel_alm/common/dff_map.v"); + run("dfflegalize -cell $_DFFE_PN0P_ 0 -cell $_SDFFCE_PP0P_ 0"); + run("techmap -map +/intel_alm/common/dff_map.v"); run("opt -full -undriven -mux_undef"); run("clean -purge"); } diff --git a/tests/arch/intel_alm/fsm.ys b/tests/arch/intel_alm/fsm.ys index 02e4a9789bb..60cd23373ba 100644 --- a/tests/arch/intel_alm/fsm.ys +++ b/tests/arch/intel_alm/fsm.ys @@ -15,6 +15,6 @@ select -assert-count 6 t:MISTRAL_FF select -assert-max 2 t:MISTRAL_ALUT2 # Clang returns 2, GCC returns 1 select -assert-count 1 t:MISTRAL_ALUT3 select -assert-max 1 t:MISTRAL_ALUT4 # Clang returns 0, GCC returns 1 -select -assert-max 5 t:MISTRAL_ALUT5 # Clang returns 5, GCC returns 4 +select -assert-max 6 t:MISTRAL_ALUT5 # Clang returns 5, GCC returns 4 select -assert-max 2 t:MISTRAL_ALUT6 # Clang returns 1, GCC returns 2 select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_ALUT4 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D From 01772dec8c13fb331df439319f4619b6292d6409 Mon Sep 17 00:00:00 2001 From: Dan Ravensloft Date: Sat, 4 Jul 2020 19:39:40 +0100 Subject: [PATCH 038/287] gowin: replace determine_init with setundef --- techlibs/gowin/Makefile.inc | 1 - techlibs/gowin/determine_init.cc | 72 -------------------------------- techlibs/gowin/synth_gowin.cc | 2 +- 3 files changed, 1 insertion(+), 74 deletions(-) delete mode 100644 techlibs/gowin/determine_init.cc diff --git a/techlibs/gowin/Makefile.inc b/techlibs/gowin/Makefile.inc index 0756e3bcf35..e6a6be970ad 100644 --- a/techlibs/gowin/Makefile.inc +++ b/techlibs/gowin/Makefile.inc @@ -1,6 +1,5 @@ OBJS += techlibs/gowin/synth_gowin.o -OBJS += techlibs/gowin/determine_init.o GENFILES += techlibs/gowin/bram_init_16.vh diff --git a/techlibs/gowin/determine_init.cc b/techlibs/gowin/determine_init.cc deleted file mode 100644 index 15ff115debb..00000000000 --- a/techlibs/gowin/determine_init.cc +++ /dev/null @@ -1,72 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2018 Icenowy Zheng - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" -#include "kernel/sigtools.h" - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct DetermineInitPass : public Pass { - DetermineInitPass() : Pass("determine_init", "Determine the init value of cells") { } - void help() override - { - log("\n"); - log(" determine_init [selection]\n"); - log("\n"); - log("Determine the init value of cells that doesn't allow unknown init value.\n"); - log("\n"); - } - - Const determine_init(Const init) - { - for (int i = 0; i < GetSize(init); i++) { - if (init[i] != State::S0 && init[i] != State::S1) - init[i] = State::S0; - } - - return init; - } - - void execute(std::vector args, RTLIL::Design *design) override - { - log_header(design, "Executing DETERMINE_INIT pass (determine init value for cells).\n"); - - extra_args(args, args.size(), design); - - int cnt = 0; - for (auto module : design->selected_modules()) - { - for (auto cell : module->selected_cells()) - { - if (cell->type == ID(RAM16S4)) - { - cell->setParam(ID(INIT_0), determine_init(cell->getParam(ID(INIT_0)))); - cell->setParam(ID(INIT_1), determine_init(cell->getParam(ID(INIT_1)))); - cell->setParam(ID(INIT_2), determine_init(cell->getParam(ID(INIT_2)))); - cell->setParam(ID(INIT_3), determine_init(cell->getParam(ID(INIT_3)))); - cnt++; - } - } - } - log_header(design, "Updated %d cells with determined init value.\n", cnt); - } -} DetermineInitPass; - -PRIVATE_NAMESPACE_END diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 32d9cc0a5d9..1e82e1ed6ed 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -198,7 +198,7 @@ struct SynthGowinPass : public ScriptPass { run("memory_bram -rules +/gowin/lutrams.txt"); run("techmap -map +/gowin/lutrams_map.v"); - run("determine_init"); + run("setundef -params -zero t:RAM16S4"); } if (check_label("map_ffram")) From 9beed4d771359f1757682cedf5a1175db3408959 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Sun, 5 Jul 2020 03:03:48 +0200 Subject: [PATCH 039/287] gowin: Fix INIT values in sim library. --- techlibs/gowin/cells_sim.v | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/techlibs/gowin/cells_sim.v b/techlibs/gowin/cells_sim.v index a67855dab9a..da51759751c 100644 --- a/techlibs/gowin/cells_sim.v +++ b/techlibs/gowin/cells_sim.v @@ -77,7 +77,7 @@ endmodule // DFFE (positive clock edge; clock enable) module DFFS (output reg Q, input D, CLK, SET); - parameter [0:0] INIT = 1'b0; + parameter [0:0] INIT = 1'b1; initial Q = INIT; always @(posedge CLK) begin if (SET) @@ -89,7 +89,7 @@ endmodule // DFFS (positive clock edge; synchronous set) module DFFSE (output reg Q, input D, CLK, CE, SET); - parameter [0:0] INIT = 1'b0; + parameter [0:0] INIT = 1'b1; initial Q = INIT; always @(posedge CLK) begin if (SET) @@ -125,7 +125,7 @@ endmodule // DFFRE (positive clock edge; synchronous reset takes precedence over module DFFP (output reg Q, input D, CLK, PRESET); - parameter [0:0] INIT = 1'b0; + parameter [0:0] INIT = 1'b1; initial Q = INIT; always @(posedge CLK or posedge PRESET) begin if(PRESET) @@ -137,7 +137,7 @@ endmodule // DFFP (positive clock edge; asynchronous preset) module DFFPE (output reg Q, input D, CLK, CE, PRESET); - parameter [0:0] INIT = 1'b0; + parameter [0:0] INIT = 1'b1; initial Q = INIT; always @(posedge CLK or posedge PRESET) begin if(PRESET) @@ -190,7 +190,7 @@ endmodule // DFFNE (negative clock edge; clock enable) module DFFNS (output reg Q, input D, CLK, SET); - parameter [0:0] INIT = 1'b0; + parameter [0:0] INIT = 1'b1; initial Q = INIT; always @(negedge CLK) begin if (SET) @@ -202,7 +202,7 @@ endmodule // DFFNS (negative clock edge; synchronous set) module DFFNSE (output reg Q, input D, CLK, CE, SET); - parameter [0:0] INIT = 1'b0; + parameter [0:0] INIT = 1'b1; initial Q = INIT; always @(negedge CLK) begin if (SET) @@ -238,7 +238,7 @@ endmodule // DFFNRE (negative clock edge; synchronous reset takes precedence ove module DFFNP (output reg Q, input D, CLK, PRESET); - parameter [0:0] INIT = 1'b0; + parameter [0:0] INIT = 1'b1; initial Q = INIT; always @(negedge CLK or posedge PRESET) begin if(PRESET) @@ -250,7 +250,7 @@ endmodule // DFFNP (negative clock edge; asynchronous preset) module DFFNPE (output reg Q, input D, CLK, CE, PRESET); - parameter [0:0] INIT = 1'b0; + parameter [0:0] INIT = 1'b1; initial Q = INIT; always @(negedge CLK or posedge PRESET) begin if(PRESET) From 1fc8c3a0d1b2e78c7c12123674732d516a0f5a9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Fri, 3 Jul 2020 00:21:24 +0200 Subject: [PATCH 040/287] ice40: Use dfflegalize. --- techlibs/ice40/Makefile.inc | 1 - techlibs/ice40/ff_map.v | 43 ++++---- techlibs/ice40/ice40_ffinit.cc | 179 --------------------------------- techlibs/ice40/synth_ice40.cc | 9 +- 4 files changed, 24 insertions(+), 208 deletions(-) delete mode 100644 techlibs/ice40/ice40_ffinit.cc diff --git a/techlibs/ice40/Makefile.inc b/techlibs/ice40/Makefile.inc index 1a8caf9a9cc..4f4faf6d5a0 100644 --- a/techlibs/ice40/Makefile.inc +++ b/techlibs/ice40/Makefile.inc @@ -2,7 +2,6 @@ OBJS += techlibs/ice40/synth_ice40.o OBJS += techlibs/ice40/ice40_braminit.o OBJS += techlibs/ice40/ice40_ffssr.o -OBJS += techlibs/ice40/ice40_ffinit.o OBJS += techlibs/ice40/ice40_opt.o GENFILES += techlibs/ice40/brams_init1.vh diff --git a/techlibs/ice40/ff_map.v b/techlibs/ice40/ff_map.v index 990cd74f18a..8174323a2d3 100644 --- a/techlibs/ice40/ff_map.v +++ b/techlibs/ice40/ff_map.v @@ -1,28 +1,25 @@ -module \$_DFF_N_ (input D, C, output Q); SB_DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule -module \$_DFF_P_ (input D, C, output Q); SB_DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule +module \$_DFF_N_ (input D, C, output Q); SB_DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule +module \$_DFF_P_ (input D, C, output Q); SB_DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule -module \$_DFFE_NN_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule -module \$_DFFE_PN_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule +module \$_DFFE_NP_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule +module \$_DFFE_PP_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule -module \$_DFFE_NP_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule -module \$_DFFE_PP_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule +module \$_DFF_NP0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule +module \$_DFF_NP1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule +module \$_DFF_PP0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule +module \$_DFF_PP1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule -module \$_DFF_NN0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule -module \$_DFF_NN1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule -module \$_DFF_PN0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule -module \$_DFF_PN1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule +module \$_DFFE_NP0P_ (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule +module \$_DFFE_NP1P_ (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule +module \$_DFFE_PP0P_ (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule +module \$_DFFE_PP1P_ (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule -module \$_DFF_NP0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule -module \$_DFF_NP1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule -module \$_DFF_PP0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule -module \$_DFF_PP1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule +module \$_SDFF_NP0_ (input D, C, R, output Q); SB_DFFNSR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule +module \$_SDFF_NP1_ (input D, C, R, output Q); SB_DFFNSS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule +module \$_SDFF_PP0_ (input D, C, R, output Q); SB_DFFSR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule +module \$_SDFF_PP1_ (input D, C, R, output Q); SB_DFFSS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule -module \$_DFFE_NN0P_ (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule -module \$_DFFE_NN1P_ (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule -module \$_DFFE_PN0P_ (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule -module \$_DFFE_PN1P_ (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule - -module \$_DFFE_NP0P_ (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule -module \$_DFFE_NP1P_ (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule -module \$_DFFE_PP0P_ (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule -module \$_DFFE_PP1P_ (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule +module \$_SDFFCE_NP0P_ (input D, C, E, R, output Q); SB_DFFNESR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule +module \$_SDFFCE_NP1P_ (input D, C, E, R, output Q); SB_DFFNESS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule +module \$_SDFFCE_PP0P_ (input D, C, E, R, output Q); SB_DFFESR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule +module \$_SDFFCE_PP1P_ (input D, C, E, R, output Q); SB_DFFESS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule diff --git a/techlibs/ice40/ice40_ffinit.cc b/techlibs/ice40/ice40_ffinit.cc deleted file mode 100644 index 2eef3fa93b5..00000000000 --- a/techlibs/ice40/ice40_ffinit.cc +++ /dev/null @@ -1,179 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" -#include "kernel/sigtools.h" - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct Ice40FfinitPass : public Pass { - Ice40FfinitPass() : Pass("ice40_ffinit", "iCE40: handle FF init values") { } - void help() override - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" ice40_ffinit [options] [selection]\n"); - log("\n"); - log("Remove zero init values for FF output signals. Add inverters to implement\n"); - log("nonzero init values.\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) override - { - log_header(design, "Executing ICE40_FFINIT pass (implement FF init values).\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - // if (args[argidx] == "-singleton") { - // singleton_mode = true; - // continue; - // } - break; - } - extra_args(args, argidx, design); - - for (auto module : design->selected_modules()) - { - log("Handling FF init values in %s.\n", log_id(module)); - - SigMap sigmap(module); - pool init_wires; - dict initbits; - dict initbit_to_wire; - pool handled_initbits; - - for (auto wire : module->selected_wires()) - { - if (wire->attributes.count(ID::init) == 0) - continue; - - SigSpec wirebits = sigmap(wire); - Const initval = wire->attributes.at(ID::init); - init_wires.insert(wire); - - for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) - { - SigBit bit = wirebits[i]; - State val = initval[i]; - - if (val != State::S0 && val != State::S1) - continue; - - if (initbits.count(bit)) { - if (initbits.at(bit) != val) { - log_warning("Conflicting init values for signal %s (%s = %s, %s = %s).\n", - log_signal(bit), log_signal(SigBit(wire, i)), log_signal(val), - log_signal(initbit_to_wire[bit]), log_signal(initbits.at(bit))); - initbits.at(bit) = State::Sx; - } - continue; - } - - initbits[bit] = val; - initbit_to_wire[bit] = SigBit(wire, i); - } - } - - pool sb_dff_types = { - ID(SB_DFF), ID(SB_DFFE), ID(SB_DFFSR), ID(SB_DFFR), ID(SB_DFFSS), ID(SB_DFFS), ID(SB_DFFESR), - ID(SB_DFFER), ID(SB_DFFESS), ID(SB_DFFES), ID(SB_DFFN), ID(SB_DFFNE), ID(SB_DFFNSR), ID(SB_DFFNR), - ID(SB_DFFNSS), ID(SB_DFFNS), ID(SB_DFFNESR), ID(SB_DFFNER), ID(SB_DFFNESS), ID(SB_DFFNES) - }; - - for (auto cell : module->selected_cells()) - { - if (!sb_dff_types.count(cell->type)) - continue; - - SigSpec sig_d = cell->getPort(ID::D); - SigSpec sig_q = cell->getPort(ID::Q); - - if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1) - continue; - - SigBit bit_d = sigmap(sig_d[0]); - SigBit bit_q = sigmap(sig_q[0]); - - if (!initbits.count(bit_q)) - continue; - - State val = initbits.at(bit_q); - - if (val == State::Sx) - continue; - - handled_initbits.insert(bit_q); - - log("FF init value for cell %s (%s): %s = %c\n", log_id(cell), log_id(cell->type), - log_signal(bit_q), val != State::S0 ? '1' : '0'); - - if (val == State::S0) - continue; - - string type_str = cell->type.str(); - - if (type_str.back() == 'S') { - type_str.back() = 'R'; - cell->type = type_str; - cell->setPort(ID::R, cell->getPort(ID::S)); - cell->unsetPort(ID::S); - } else - if (type_str.back() == 'R') { - type_str.back() = 'S'; - cell->type = type_str; - cell->setPort(ID::S, cell->getPort(ID::R)); - cell->unsetPort(ID::R); - } - - Wire *new_bit_d = module->addWire(NEW_ID); - Wire *new_bit_q = module->addWire(NEW_ID); - - module->addNotGate(NEW_ID, bit_d, new_bit_d); - module->addNotGate(NEW_ID, new_bit_q, bit_q); - - cell->setPort(ID::D, new_bit_d); - cell->setPort(ID::Q, new_bit_q); - } - - for (auto wire : init_wires) - { - if (wire->attributes.count(ID::init) == 0) - continue; - - SigSpec wirebits = sigmap(wire); - Const &initval = wire->attributes.at(ID::init); - bool remove_attribute = true; - - for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) { - if (handled_initbits.count(wirebits[i])) - initval[i] = State::Sx; - else if (initval[i] != State::Sx) - remove_attribute = false; - } - - if (remove_attribute) - wire->attributes.erase(ID::init); - } - } - } -} Ice40FfinitPass; - -PRIVATE_NAMESPACE_END diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 6464368ebe3..4ddb6ca70ae 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -358,15 +358,14 @@ struct SynthIce40Pass : public ScriptPass run("dff2dffe -direct-match $_DFF_*"); if (min_ce_use >= 0) { run("opt_merge"); - run(stringf("dff2dffe -unmap-mince %d", min_ce_use)); - run("simplemap t:$dff"); } - if ((abc9 && dff) || help_mode) - run("zinit -all w:* t:$_DFF_?_ t:$_DFFE_??_ t:$_SDFF*", "(only if -abc9 and -dff"); + if (nodffe) + run(stringf("dfflegalize -cell $_DFF_?_ 0 -cell $_DFF_?P?_ 0 -cell $_SDFF_?P?_ 0 -cell $_DLATCH_?_ x")); + else + run(stringf("dfflegalize -cell $_DFF_?_ 0 -cell $_DFFE_?P_ 0 -cell $_DFF_?P?_ 0 -cell $_DFFE_?P?P_ 0 -cell $_SDFF_?P?_ 0 -cell $_SDFFCE_?P?P_ 0 -cell $_DLATCH_?_ x -mince %d", min_ce_use)); run("techmap -map +/ice40/ff_map.v"); run("opt_expr -mux_undef"); run("simplemap"); - run("ice40_ffinit"); run("ice40_ffssr"); run("ice40_opt -full"); } From b004f0901873962ba4a6fd3e12c7bc0cc1e04032 Mon Sep 17 00:00:00 2001 From: Dan Ravensloft Date: Sat, 25 Apr 2020 17:25:59 +0100 Subject: [PATCH 041/287] intel_alm: DSP inference --- techlibs/intel_alm/Makefile.inc | 2 + techlibs/intel_alm/common/dsp_map.v | 49 +++++++++++++++++ techlibs/intel_alm/common/dsp_sim.v | 35 +++++++++++++ techlibs/intel_alm/common/megafunction_bb.v | 28 ++++++++++ techlibs/intel_alm/common/quartus_rename.v | 23 ++++++++ techlibs/intel_alm/synth_intel_alm.cc | 58 +++++++++++++++++---- tests/arch/intel_alm/mul.ys | 23 ++++++++ 7 files changed, 209 insertions(+), 9 deletions(-) create mode 100644 techlibs/intel_alm/common/dsp_map.v create mode 100644 techlibs/intel_alm/common/dsp_sim.v create mode 100644 tests/arch/intel_alm/mul.ys diff --git a/techlibs/intel_alm/Makefile.inc b/techlibs/intel_alm/Makefile.inc index 477be63535d..552f00c658e 100644 --- a/techlibs/intel_alm/Makefile.inc +++ b/techlibs/intel_alm/Makefile.inc @@ -10,6 +10,8 @@ $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/al $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/arith_alm_map.v)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/dff_map.v)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/dff_sim.v)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/dsp_sim.v)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/dsp_map.v)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/mem_sim.v)) # RAM diff --git a/techlibs/intel_alm/common/dsp_map.v b/techlibs/intel_alm/common/dsp_map.v new file mode 100644 index 00000000000..d1bc25e6585 --- /dev/null +++ b/techlibs/intel_alm/common/dsp_map.v @@ -0,0 +1,49 @@ +module __MUL27X27(A, B, Y); + +parameter A_SIGNED = 1; +parameter B_SIGNED = 1; +parameter A_WIDTH = 27; +parameter B_WIDTH = 27; +parameter Y_WIDTH = 54; + +input [A_WIDTH-1:0] A; +input [B_WIDTH-1:0] B; +output [Y_WIDTH-1:0] Y; + +MISTRAL_MUL27X27 _TECHMAP_REPLACE_ (.A(A), .B(B), .Y(Y)); + +endmodule + + +module __MUL18X18(A, B, Y); + +parameter A_SIGNED = 1; +parameter B_SIGNED = 1; +parameter A_WIDTH = 18; +parameter B_WIDTH = 18; +parameter Y_WIDTH = 36; + +input [A_WIDTH-1:0] A; +input [B_WIDTH-1:0] B; +output [Y_WIDTH-1:0] Y; + +MISTRAL_MUL18X18 _TECHMAP_REPLACE_ (.A(A), .B(B), .Y(Y)); + +endmodule + + +module __MUL9X9(A, B, Y); + +parameter A_SIGNED = 1; +parameter B_SIGNED = 1; +parameter A_WIDTH = 9; +parameter B_WIDTH = 9; +parameter Y_WIDTH = 18; + +input [A_WIDTH-1:0] A; +input [B_WIDTH-1:0] B; +output [Y_WIDTH-1:0] Y; + +MISTRAL_MUL9X9 _TECHMAP_REPLACE_ (.A(A), .B(B), .Y(Y)); + +endmodule diff --git a/techlibs/intel_alm/common/dsp_sim.v b/techlibs/intel_alm/common/dsp_sim.v new file mode 100644 index 00000000000..5dc4c02deff --- /dev/null +++ b/techlibs/intel_alm/common/dsp_sim.v @@ -0,0 +1,35 @@ +(* abc9_box *) +module MISTRAL_MUL27x27(input [26:0] A, input [26:0] B, output [53:0] Y); + +specify + (A *> Y) = 4057; + (B *> Y) = 4057; +endspecify + +assign Y = $signed(A) * $signed(B); + +endmodule + +(* abc9_box *) +module MISTRAL_MUL18X18(input [17:0] A, input [17:0] B, output [35:0] Y); + +specify + (A *> Y) = 4057; + (B *> Y) = 4057; +endspecify + +assign Y = $signed(A) * $signed(B); + +endmodule + +(* abc9_box *) +module MISTRAL_MUL9X9(input [8:0] A, input [8:0] B, output [17:0] Y); + +specify + (A *> Y) = 4057; + (B *> Y) = 4057; +endspecify + +assign Y = $signed(A) * $signed(B); + +endmodule diff --git a/techlibs/intel_alm/common/megafunction_bb.v b/techlibs/intel_alm/common/megafunction_bb.v index c749fa70bd7..b5a3d889261 100644 --- a/techlibs/intel_alm/common/megafunction_bb.v +++ b/techlibs/intel_alm/common/megafunction_bb.v @@ -129,3 +129,31 @@ output [data_width-1:0] portbdataout; input ena0, clk0, clk1; endmodule + +(* blackbox *) +module cyclonev_mac(ax, ay, resulta); + +parameter ax_width = 9; +parameter ay_scan_in_width = 9; +parameter result_a_width = 18; +parameter operation_mode = "M9x9"; + +input [ax_width-1:0] ax; +input [ay_scan_in_width-1:0] ay; +output [result_a_width-1:0] resulta; + +endmodule + +(* blackbox *) +module cyclone10gx_mac(ax, ay, resulta); + +parameter ax_width = 18; +parameter ay_scan_in_width = 18; +parameter result_a_width = 36; +parameter operation_mode = "M18X18_FULL"; + +input [ax_width-1:0] ax; +input [ay_scan_in_width-1:0] ay; +output [result_a_width-1:0] resulta; + +endmodule \ No newline at end of file diff --git a/techlibs/intel_alm/common/quartus_rename.v b/techlibs/intel_alm/common/quartus_rename.v index c40a4e02d1e..46ef2aa0dc7 100644 --- a/techlibs/intel_alm/common/quartus_rename.v +++ b/techlibs/intel_alm/common/quartus_rename.v @@ -1,9 +1,11 @@ `ifdef cyclonev `define LCELL cyclonev_lcell_comb +`define MAC cyclonev_mac `define MLAB cyclonev_mlab_cell `endif `ifdef cyclone10gx `define LCELL cyclone10gx_lcell_comb +`define MAC cyclone10gx_mac `define MLAB cyclone10gx_mlab_cell `endif @@ -119,3 +121,24 @@ module MISTRAL_MLAB(input [4:0] A1ADDR, input A1DATA, A1EN, CLK1, input [4:0] B1 ); endmodule + + +module MISTRAL_MUL27X27(input [26:0] A, B, output [53:0] Y); + +`MAC #(.ax_width(27), .ay_scan_in_width(27), .result_a_width(54), .operation_mode("M27x27")) _TECHMAP_REPLACE_ (.ax(A), .ay(B), .resulta(Y)); + +endmodule + + +module MISTRAL_MUL18X18(input [17:0] A, B, output [35:0] Y); + +`MAC #(.ax_width(18), .ay_scan_in_width(18), .result_a_width(36), .operation_mode("M18x18_FULL")) _TECHMAP_REPLACE_ (.ax(B), .ay(A), .resulta(Y)); + +endmodule + + +module MISTRAL_MUL9X9(input [8:0] A, B, output [17:0] Y); + +`MAC #(.ax_width(9), .ay_scan_in_width(9), .result_a_width(18), .operation_mode("M9x9")) _TECHMAP_REPLACE_ (.ax(A), .ay(B), .resulta(Y)); + +endmodule diff --git a/techlibs/intel_alm/synth_intel_alm.cc b/techlibs/intel_alm/synth_intel_alm.cc index 4170274622c..b751e8413fc 100644 --- a/techlibs/intel_alm/synth_intel_alm.cc +++ b/techlibs/intel_alm/synth_intel_alm.cc @@ -69,13 +69,16 @@ struct SynthIntelALMPass : public ScriptPass { log(" -nobram\n"); log(" do not use block RAM cells in output netlist\n"); log("\n"); + log(" -nodsp\n"); + log(" do not map multipliers to MISTRAL_MUL cells\n"); + log("\n"); log("The following commands are executed by this synthesis command:\n"); help_script(); log("\n"); } string top_opt, family_opt, bram_type, vout_file; - bool flatten, quartus, nolutram, nobram, dff; + bool flatten, quartus, nolutram, nobram, dff, nodsp; void clear_flags() override { @@ -88,6 +91,7 @@ struct SynthIntelALMPass : public ScriptPass { nolutram = false; nobram = false; dff = false; + nodsp = false; } void execute(std::vector args, RTLIL::Design *design) override @@ -130,6 +134,10 @@ struct SynthIntelALMPass : public ScriptPass { nobram = true; continue; } + if (args[argidx] == "-nodsp") { + nodsp = true; + continue; + } if (args[argidx] == "-noflatten") { flatten = false; continue; @@ -169,9 +177,11 @@ struct SynthIntelALMPass : public ScriptPass { } if (check_label("begin")) { - run(stringf("read_verilog -sv -lib +/intel/%s/cells_sim.v", family_opt.c_str())); + if (family_opt == "cyclonev") + run(stringf("read_verilog -sv -lib +/intel/%s/cells_sim.v", family_opt.c_str())); run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/alm_sim.v", family_opt.c_str())); run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/dff_sim.v", family_opt.c_str())); + run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/dsp_sim.v", family_opt.c_str())); run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/mem_sim.v", family_opt.c_str())); run(stringf("read_verilog -specify -lib -D %s -icells +/intel_alm/common/abc9_model.v", family_opt.c_str())); @@ -181,16 +191,46 @@ struct SynthIntelALMPass : public ScriptPass { run(stringf("hierarchy -check %s", help_mode ? "-top " : top_opt.c_str())); } - if (flatten && check_label("flatten", "(unless -noflatten)")) { + if (check_label("coarse")) { run("proc"); - run("flatten"); + if (flatten || help_mode) + run("flatten", "(skip if -noflatten)"); run("tribuf -logic"); run("deminout"); - } - - if (check_label("coarse")) { - run("synth -run coarse -lut 6"); - run("techmap -map +/intel_alm/common/arith_alm_map.v"); + run("opt_expr"); + run("opt_clean"); + run("check"); + run("opt"); + run("wreduce"); + run("peepopt"); + run("opt_clean"); + run("share"); + run("techmap -map +/cmp2lut.v -D LUT_WIDTH=6"); + run("opt_expr"); + run("opt_clean"); + if (help_mode) { + run("techmap -map +/mul2dsp.v [...]", "(unless -nodsp)"); + } else if (!nodsp) { + // Cyclone V supports 9x9 multiplication, Cyclone 10 GX does not. + run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=27 -D DSP_B_MAXWIDTH=27 -D DSP_A_MINWIDTH=19 -D DSP_B_MINWIDTH=19 -D DSP_SIGNEDONLY -D DSP_NAME=__MUL27X27"); + run("chtype -set $mul t:$__soft_mul"); + if (family_opt == "cyclonev") { + run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=10 -D DSP_B_MINWIDTH=10 -D DSP_SIGNEDONLY -D DSP_NAME=__MUL18X18"); + run("chtype -set $mul t:$__soft_mul"); + run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=9 -D DSP_B_MAXWIDTH=9 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_SIGNEDONLY -D DSP_NAME=__MUL9X9"); + run("chtype -set $mul t:$__soft_mul"); + } else if (family_opt == "cyclone10gx") { + run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_SIGNEDONLY -D DSP_NAME=__MUL18X18"); + run("chtype -set $mul t:$__soft_mul"); + } + } + run("alumacc"); + run("techmap -map +/intel_alm/common/arith_alm_map.v -map +/intel_alm/common/dsp_map.v"); + run("opt"); + run("fsm"); + run("opt -fast"); + run("memory -nomap"); + run("opt_clean"); } if (!nobram && check_label("map_bram", "(skip if -nobram)")) { diff --git a/tests/arch/intel_alm/mul.ys b/tests/arch/intel_alm/mul.ys new file mode 100644 index 00000000000..92f00156ab2 --- /dev/null +++ b/tests/arch/intel_alm/mul.ys @@ -0,0 +1,23 @@ +read_verilog ../common/mul.v +hierarchy -top top +proc +equiv_opt -assert -map +/intel_alm/common/dsp_sim.v synth_intel_alm -family cyclonev # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module + +stat + +select -assert-count 1 t:MISTRAL_MUL9X9 +select -assert-none t:MISTRAL_MUL9X9 %% t:* %D + +design -reset +read_verilog ../common/mul.v +hierarchy -top top +proc +equiv_opt -assert -map +/intel_alm/common/dsp_sim.v synth_intel_alm -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module + +# Cyclone 10 GX does not have 9x9 multipliers, so we use 18x18. +select -assert-count 1 t:MISTRAL_MUL18X18 +select -assert-none t:MISTRAL_MUL18X18 %% t:* %D From 7afcb72c98620adaace7cc9622c4d577668f9426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Sun, 5 Jul 2020 00:55:38 +0200 Subject: [PATCH 042/287] opt_expr: Fix crash on $mul optimization with more zeros removed than Y has. Fixes #2221. --- passes/opt/opt_expr.cc | 8 ++++++++ tests/opt/bug2221.ys | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 tests/opt/bug2221.ys diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 1051a59f278..649ad83a69f 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -1596,6 +1596,14 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons log_debug("Removing low %d A and %d B bits from cell `%s' in module `%s'.\n", a_zeros, b_zeros, cell->name.c_str(), module->name.c_str()); + if (y_zeros >= GetSize(sig_y)) { + module->connect(sig_y, RTLIL::SigSpec(0, GetSize(sig_y))); + module->remove(cell); + + did_something = true; + goto next_cell; + } + if (a_zeros) { cell->setPort(ID::A, sig_a.extract_end(a_zeros)); cell->parameters[ID::A_WIDTH] = GetSize(sig_a) - a_zeros; diff --git a/tests/opt/bug2221.ys b/tests/opt/bug2221.ys new file mode 100644 index 00000000000..8ac380243d1 --- /dev/null +++ b/tests/opt/bug2221.ys @@ -0,0 +1,16 @@ +read_verilog < Date: Sun, 5 Jul 2020 04:57:24 +0200 Subject: [PATCH 043/287] dfflegalize: Prefer mapping dff to sdff before adff This ensures that, when both sync and async FFs are available and abc9 is involved, the sync FFs will be used, and will thus remain available for sequential synthesis. --- passes/techmap/dfflegalize.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/dfflegalize.cc b/passes/techmap/dfflegalize.cc index 7f2cdc6acce..b2fe90702da 100644 --- a/passes/techmap/dfflegalize.cc +++ b/passes/techmap/dfflegalize.cc @@ -364,7 +364,7 @@ struct DffLegalizePass : public Pass { // Some DFF is supported with this init val. Just pick a type. if (ff_type == FF_DFF) { // Try adding a set or reset pin. - for (auto new_type: {FF_ADFF0, FF_ADFF1, FF_SDFF0, FF_SDFF1}) + for (auto new_type: {FF_SDFF0, FF_SDFF1, FF_ADFF0, FF_ADFF1}) if (supported_cells[new_type] & initmask) { ff_type = new_type; sig_r = State::S0; From 372521ca56c2ca27bb562098aa65b4e457959e77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Fri, 3 Jul 2020 00:23:03 +0200 Subject: [PATCH 044/287] ecp5: Use dfflegalize. --- techlibs/ecp5/Makefile.inc | 3 +- techlibs/ecp5/cells_map.v | 143 +++++++++++++++---------- techlibs/ecp5/ecp5_ffinit.cc | 197 ----------------------------------- techlibs/ecp5/synth_ecp5.cc | 7 +- 4 files changed, 96 insertions(+), 254 deletions(-) delete mode 100644 techlibs/ecp5/ecp5_ffinit.cc diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc index 9d564c78cc3..4c1bc23b544 100644 --- a/techlibs/ecp5/Makefile.inc +++ b/techlibs/ecp5/Makefile.inc @@ -1,6 +1,5 @@ -OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_ffinit.o \ - techlibs/ecp5/ecp5_gsr.o +OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_gsr.o GENFILES += techlibs/ecp5/bram_init_1_2_4.vh GENFILES += techlibs/ecp5/bram_init_9_18_36.vh diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v index 80f497cc39d..dc83d96dc00 100644 --- a/techlibs/ecp5/cells_map.v +++ b/techlibs/ecp5/cells_map.v @@ -1,64 +1,99 @@ -module \$_DFF_N_ (input D, C, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule -module \$_DFF_P_ (input D, C, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule - -module \$_DFFE_NN_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule -module \$_DFFE_PN_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule - -module \$_DFFE_NP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule -module \$_DFFE_PP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule - -module \$_DFF_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule -module \$_DFF_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule -module \$_DFF_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule -module \$_DFF_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule - -module \$_DFF_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule -module \$_DFF_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule -module \$_DFF_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule -module \$_DFF_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule - -module \$_SDFF_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule -module \$_SDFF_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule -module \$_SDFF_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule -module \$_SDFF_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule - -module \$_SDFF_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule -module \$_SDFF_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule -module \$_SDFF_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule -module \$_SDFF_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule - -module \$_DFFE_NN0P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule -module \$_DFFE_NN1P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule -module \$_DFFE_PN0P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule -module \$_DFFE_PN1P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule - -module \$_DFFE_NP0P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule -module \$_DFFE_NP1P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule -module \$_DFFE_PP0P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule -module \$_DFFE_PP1P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule - -module \$_SDFFE_NN0P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule -module \$_SDFFE_NN1P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule -module \$_SDFFE_PN0P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule -module \$_SDFFE_PN1P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule - -module \$_SDFFE_NP0P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule -module \$_SDFFE_NP1P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule -module \$_SDFFE_PP0P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule -module \$_SDFFE_PP1P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule +module \$_DFF_N_ (input D, C, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) + TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); + else + TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); + endgenerate + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; +endmodule + +module \$_DFF_P_ (input D, C, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) + TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); + else + TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); + endgenerate + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; +endmodule + +module \$_DFFE_NN_ (input D, C, E, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) + TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); + else + TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); + endgenerate + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; +endmodule + +module \$_DFFE_PN_ (input D, C, E, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) + TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); + else + TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); + endgenerate + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; +endmodule + +module \$_DFFE_NP_ (input D, C, E, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) + TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); + else + TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); + endgenerate + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; +endmodule + +module \$_DFFE_PP_ (input D, C, E, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) + TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); + else + TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); + endgenerate + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; +endmodule + +module \$_DFF_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DFF_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DFF_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DFF_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule + +module \$_SDFF_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_SDFF_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_SDFF_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_SDFF_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule + +module \$_DFFE_NP0P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DFFE_NP1P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DFFE_PP0P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DFFE_PP1P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule + +module \$_DFFE_NP0N_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DFFE_NP1N_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DFFE_PP0N_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DFFE_PP1N_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule + +module \$_SDFFE_NP0P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_SDFFE_NP1P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_SDFFE_PP0P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_SDFFE_PP1P_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule + +module \$_SDFFE_NP0N_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_SDFFE_NP1N_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_SDFFE_PP0N_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_SDFFE_PP1N_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule `ifdef ASYNC_PRLD module \$_DLATCH_N_ (input E, input D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.LSR(!E), .DI(1'b0), .M(D), .Q(Q)); endmodule module \$_DLATCH_P_ (input E, input D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.LSR(E), .DI(1'b0), .M(D), .Q(Q)); endmodule -module \$_DFFSR_NNN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || !R), .DI(D), .M(R), .Q(Q)); endmodule -module \$_DFFSR_NNP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || R), .DI(D), .M(!R), .Q(Q)); endmodule -module \$_DFFSR_NPN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || !R), .DI(D), .M(R), .Q(Q)); endmodule module \$_DFFSR_NPP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || R), .DI(D), .M(!R), .Q(Q)); endmodule -module \$_DFFSR_PNN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || !R), .DI(D), .M(R), .Q(Q)); endmodule -module \$_DFFSR_PNP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || R), .DI(D), .M(!R), .Q(Q)); endmodule -module \$_DFFSR_PPN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || !R), .DI(D), .M(R), .Q(Q)); endmodule module \$_DFFSR_PPP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || R), .DI(D), .M(!R), .Q(Q)); endmodule `endif diff --git a/techlibs/ecp5/ecp5_ffinit.cc b/techlibs/ecp5/ecp5_ffinit.cc deleted file mode 100644 index 0ecc8638848..00000000000 --- a/techlibs/ecp5/ecp5_ffinit.cc +++ /dev/null @@ -1,197 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * Copyright (C) 2018-19 David Shah - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" -#include "kernel/sigtools.h" - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct Ecp5FfinitPass : public Pass { - Ecp5FfinitPass() : Pass("ecp5_ffinit", "ECP5: handle FF init values") { } - void help() override - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" ecp5_ffinit [options] [selection]\n"); - log("\n"); - log("Remove init values for FF output signals when equal to reset value.\n"); - log("If reset is not used, set the reset value to the init value, otherwise\n"); - log("unmap out the reset (if not an async reset).\n"); - } - void execute(std::vector args, RTLIL::Design *design) override - { - log_header(design, "Executing ECP5_FFINIT pass (implement FF init values).\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - // if (args[argidx] == "-singleton") { - // singleton_mode = true; - // continue; - // } - break; - } - extra_args(args, argidx, design); - - for (auto module : design->selected_modules()) - { - log("Handling FF init values in %s.\n", log_id(module)); - - SigMap sigmap(module); - pool init_wires; - dict initbits; - dict initbit_to_wire; - pool handled_initbits; - - for (auto wire : module->selected_wires()) - { - if (wire->attributes.count(ID::init) == 0) - continue; - - SigSpec wirebits = sigmap(wire); - Const initval = wire->attributes.at(ID::init); - init_wires.insert(wire); - - for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) - { - SigBit bit = wirebits[i]; - State val = initval[i]; - - if (val != State::S0 && val != State::S1) - continue; - - if (initbits.count(bit)) { - if (initbits.at(bit) != val) { - log_warning("Conflicting init values for signal %s (%s = %s, %s = %s).\n", - log_signal(bit), log_signal(SigBit(wire, i)), log_signal(val), - log_signal(initbit_to_wire[bit]), log_signal(initbits.at(bit))); - initbits.at(bit) = State::Sx; - } - continue; - } - - initbits[bit] = val; - initbit_to_wire[bit] = SigBit(wire, i); - } - } - for (auto cell : module->selected_cells()) - { - if (cell->type != ID(TRELLIS_FF)) - continue; - SigSpec sig_d = cell->getPort(ID(DI)); - SigSpec sig_q = cell->getPort(ID::Q); - SigSpec sig_lsr = cell->getPort(ID(LSR)); - - if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1) - continue; - - SigBit bit_d = sigmap(sig_d[0]); - SigBit bit_q = sigmap(sig_q[0]); - - std::string regset = cell->getParam(ID(REGSET)).decode_string(); - State resetState; - if (regset == "SET") - resetState = State::S1; - else if (regset == "RESET") - resetState = State::S0; - else - log_error("FF cell %s has illegal REGSET value %s.\n", - log_id(cell), regset.c_str()); - - if (!initbits.count(bit_q)) - continue; - - State val = initbits.at(bit_q); - - if (val == State::Sx) - continue; - - log("FF init value for cell %s (%s): %s = %c\n", log_id(cell), log_id(cell->type), - log_signal(bit_q), val != State::S0 ? '1' : '0'); - // Initval is the same as the reset state. Matches hardware, nowt more to do - if (val == resetState) { - handled_initbits.insert(bit_q); - continue; - } - - if (GetSize(sig_lsr) >= 1 && sig_lsr[0] != State::S0) { - std::string srmode = cell->getParam(ID(SRMODE)).decode_string(); - if (srmode == "ASYNC") { - log("Async reset value %c for FF cell %s inconsistent with init value %c.\n", - resetState != State::S0 ? '1' : '0', log_id(cell), val != State::S0 ? '1' : '0'); - } else { - SigBit bit_lsr = sigmap(sig_lsr[0]); - Wire *new_bit_d = module->addWire(NEW_ID); - if (resetState == State::S0) { - module->addAndnotGate(NEW_ID, bit_d, bit_lsr, new_bit_d); - } else { - module->addOrGate(NEW_ID, bit_d, bit_lsr, new_bit_d); - } - - cell->setPort(ID(DI), new_bit_d); - cell->setPort(ID(LSR), State::S0); - - if(cell->hasPort(ID(CE))) { - std::string cemux = cell->getParam(ID(CEMUX)).decode_string(); - SigSpec sig_ce = cell->getPort(ID(CE)); - if (GetSize(sig_ce) >= 1) { - SigBit bit_ce = sigmap(sig_ce[0]); - Wire *new_bit_ce = module->addWire(NEW_ID); - if (cemux == "INV") - module->addAndnotGate(NEW_ID, bit_ce, bit_lsr, new_bit_ce); - else - module->addOrGate(NEW_ID, bit_ce, bit_lsr, new_bit_ce); - cell->setPort(ID(CE), new_bit_ce); - } - } - cell->setParam(ID(REGSET), val != State::S0 ? Const("SET") : Const("RESET")); - handled_initbits.insert(bit_q); - } - } else { - cell->setParam(ID(REGSET), val != State::S0 ? Const("SET") : Const("RESET")); - handled_initbits.insert(bit_q); - } - } - - for (auto wire : init_wires) - { - if (wire->attributes.count(ID::init) == 0) - continue; - - SigSpec wirebits = sigmap(wire); - Const &initval = wire->attributes.at(ID::init); - bool remove_attribute = true; - - for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) { - if (handled_initbits.count(wirebits[i])) - initval[i] = State::Sx; - else if (initval[i] != State::Sx) - remove_attribute = false; - } - - if (remove_attribute) - wire->attributes.erase(ID::init); - } - } - } -} Ecp5FfinitPass; - -PRIVATE_NAMESPACE_END diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index 0874b954a8a..46d051e4427 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -315,12 +315,17 @@ struct SynthEcp5Pass : public ScriptPass run("opt_clean"); if (!nodffe) run("dff2dffe -direct-match $_DFF_* -direct-match $_SDFF_*"); + if (help_mode) + run("dfflegalize -cell $_DFF_?_ 01 -cell $_DFFE_??_ 01 -cell $_DFF_?P?_ r -cell $_DFFE_?P??_ r -cell $_SDFF_?P?_ r -cell $_SDFFE_?P??_ r -cell $_DLATCH_?_ x [-cell $_DFFSR_?PP_ x]", "($_DFFSR_*_ only if -asyncprld)"); + else if (asyncprld) + run("dfflegalize -cell $_DFF_?_ 01 -cell $_DFFE_??_ 01 -cell $_DFF_?P?_ r -cell $_DFFE_?P??_ r -cell $_SDFF_?P?_ r -cell $_SDFFE_?P??_ r -cell $_DLATCH_?_ x -cell $_DFFSR_?PP_ x"); + else + run("dfflegalize -cell $_DFF_?_ 01 -cell $_DFFE_??_ 01 -cell $_DFF_?P?_ r -cell $_DFFE_?P??_ r -cell $_SDFF_?P?_ r -cell $_SDFFE_?P??_ r -cell $_DLATCH_?_ x"); if ((abc9 && dff) || help_mode) run("zinit -all w:* t:$_DFF_?_ t:$_DFFE_??_ t:$_SDFF*", "(only if -abc9 and -dff"); run(stringf("techmap -D NO_LUT %s -map +/ecp5/cells_map.v", help_mode ? "[-D ASYNC_PRLD]" : (asyncprld ? "-D ASYNC_PRLD" : ""))); run("opt_expr -undriven -mux_undef"); run("simplemap"); - run("ecp5_ffinit"); run("ecp5_gsr"); run("attrmvcp -copy -attr syn_useioff"); run("opt_clean"); From 0d4c2f0a65de2fccd767a56b9698be3d913fdd9f Mon Sep 17 00:00:00 2001 From: Dan Ravensloft Date: Sun, 5 Jul 2020 18:53:14 +0100 Subject: [PATCH 045/287] intel_alm: add Cyclone 10 GX tests --- tests/arch/intel_alm/add_sub.ys | 10 ++++++ tests/arch/intel_alm/adffs.ys | 48 +++++++++++++++++++++++++++++ tests/arch/intel_alm/counter.ys | 14 +++++++++ tests/arch/intel_alm/dffs.ys | 22 +++++++++++++ tests/arch/intel_alm/fsm.ys | 22 +++++++++++++ tests/arch/intel_alm/logic.ys | 14 +++++++++ tests/arch/intel_alm/lutram.ys | 23 +++++++++++++- tests/arch/intel_alm/mux.ys | 46 ++++++++++++++++++++++++++- tests/arch/intel_alm/quartus_ice.ys | 14 +++++++++ tests/arch/intel_alm/shifter.ys | 11 +++++++ tests/arch/intel_alm/tribuf.ys | 14 +++++++++ 11 files changed, 236 insertions(+), 2 deletions(-) diff --git a/tests/arch/intel_alm/add_sub.ys b/tests/arch/intel_alm/add_sub.ys index 4cb2c2e0dd0..0f552a27cb1 100644 --- a/tests/arch/intel_alm/add_sub.ys +++ b/tests/arch/intel_alm/add_sub.ys @@ -6,3 +6,13 @@ cd top # Constrain all select calls below inside the top module stat select -assert-count 8 t:MISTRAL_ALUT_ARITH select -assert-none t:MISTRAL_ALUT_ARITH %% t:* %D + +design -reset +read_verilog ../common/add_sub.v +hierarchy -top top +equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module +stat +select -assert-count 8 t:MISTRAL_ALUT_ARITH +select -assert-none t:MISTRAL_ALUT_ARITH %% t:* %D diff --git a/tests/arch/intel_alm/adffs.ys b/tests/arch/intel_alm/adffs.ys index 5d8d3a22067..04fa2ad249e 100644 --- a/tests/arch/intel_alm/adffs.ys +++ b/tests/arch/intel_alm/adffs.ys @@ -12,6 +12,18 @@ select -assert-count 1 t:MISTRAL_NOT select -assert-none t:MISTRAL_FF t:MISTRAL_NOT %% t:* %D +design -load read +hierarchy -top adff +proc +equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd adff # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF +select -assert-count 1 t:MISTRAL_NOT + +select -assert-none t:MISTRAL_FF t:MISTRAL_NOT %% t:* %D + + design -load read hierarchy -top adffn proc @@ -23,6 +35,17 @@ select -assert-count 1 t:MISTRAL_FF select -assert-none t:MISTRAL_FF %% t:* %D +design -load read +hierarchy -top adffn +proc +equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd adffn # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF + +select -assert-none t:MISTRAL_FF %% t:* %D + + design -load read hierarchy -top dffs proc @@ -35,6 +58,18 @@ select -assert-count 1 t:MISTRAL_ALUT2 select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT2 %% t:* %D +design -load read +hierarchy -top dffs +proc +equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd dffs # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF +select -assert-count 1 t:MISTRAL_ALUT2 + +select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT2 %% t:* %D + + design -load read hierarchy -top ndffnr proc @@ -46,3 +81,16 @@ select -assert-count 1 t:MISTRAL_NOT select -assert-count 1 t:MISTRAL_ALUT2 select -assert-none t:MISTRAL_FF t:MISTRAL_NOT t:MISTRAL_ALUT2 %% t:* %D + + +design -load read +hierarchy -top ndffnr +proc +equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd ndffnr # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_FF +select -assert-count 1 t:MISTRAL_NOT +select -assert-count 1 t:MISTRAL_ALUT2 + +select -assert-none t:MISTRAL_FF t:MISTRAL_NOT t:MISTRAL_ALUT2 %% t:* %D diff --git a/tests/arch/intel_alm/counter.ys b/tests/arch/intel_alm/counter.ys index 945c318d8c1..50103fefc93 100644 --- a/tests/arch/intel_alm/counter.ys +++ b/tests/arch/intel_alm/counter.ys @@ -9,5 +9,19 @@ cd top # Constrain all select calls below inside the top module select -assert-count 2 t:MISTRAL_NOT select -assert-count 8 t:MISTRAL_ALUT_ARITH select -assert-count 8 t:MISTRAL_FF +select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT_ARITH t:MISTRAL_FF %% t:* %D + + +design -reset +read_verilog ../common/counter.v +hierarchy -top top +proc +flatten +equiv_opt -async2sync -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module +select -assert-count 2 t:MISTRAL_NOT +select -assert-count 8 t:MISTRAL_ALUT_ARITH +select -assert-count 8 t:MISTRAL_FF select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT_ARITH t:MISTRAL_FF %% t:* %D diff --git a/tests/arch/intel_alm/dffs.ys b/tests/arch/intel_alm/dffs.ys index 149b3121afe..9ae6c637a83 100644 --- a/tests/arch/intel_alm/dffs.ys +++ b/tests/arch/intel_alm/dffs.ys @@ -10,6 +10,17 @@ select -assert-count 1 t:MISTRAL_FF select -assert-none t:MISTRAL_FF %% t:* %D +design -load read +hierarchy -top dff +proc +equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclone10gx # 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-count 1 t:MISTRAL_FF + +select -assert-none t:MISTRAL_FF %% t:* %D + + design -load read hierarchy -top dffe proc @@ -19,3 +30,14 @@ cd dffe # Constrain all select calls below inside the top module select -assert-count 1 t:MISTRAL_FF select -assert-none t:MISTRAL_FF %% t:* %D + + +design -load read +hierarchy -top dffe +proc +equiv_opt -async2sync -assert -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclone10gx # 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 +select -assert-count 1 t:MISTRAL_FF + +select -assert-none t:MISTRAL_FF %% t:* %D diff --git a/tests/arch/intel_alm/fsm.ys b/tests/arch/intel_alm/fsm.ys index 60cd23373ba..6491b2e087c 100644 --- a/tests/arch/intel_alm/fsm.ys +++ b/tests/arch/intel_alm/fsm.ys @@ -18,3 +18,25 @@ select -assert-max 1 t:MISTRAL_ALUT4 # Clang returns 0, GCC returns 1 select -assert-max 6 t:MISTRAL_ALUT5 # Clang returns 5, GCC returns 4 select -assert-max 2 t:MISTRAL_ALUT6 # Clang returns 1, GCC returns 2 select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_ALUT4 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D + +design -reset +read_verilog ../common/fsm.v +hierarchy -top fsm +proc +flatten + +equiv_opt -run :prove -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v synth_intel_alm -family cyclone10gx +async2sync +miter -equiv -make_assert -flatten gold gate miter +sat -verify -prove-asserts -show-public -set-at 1 in_reset 1 -seq 20 -prove-skip 1 miter + +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd fsm # Constrain all select calls below inside the top module + +select -assert-count 6 t:MISTRAL_FF +select -assert-max 2 t:MISTRAL_ALUT2 # Clang returns 2, GCC returns 1 +select -assert-max 2 t:MISTRAL_ALUT3 # Clang returns 2, GCC returns 1 +select -assert-max 1 t:MISTRAL_ALUT4 # Clang returns 0, GCC returns 1 +select -assert-max 6 t:MISTRAL_ALUT5 # Clang returns 5, GCC returns 4 +select -assert-max 2 t:MISTRAL_ALUT6 # Clang returns 1, GCC returns 2 +select -assert-none t:MISTRAL_FF t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_ALUT4 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D diff --git a/tests/arch/intel_alm/logic.ys b/tests/arch/intel_alm/logic.ys index fad45db74ff..e8b26a524fb 100644 --- a/tests/arch/intel_alm/logic.ys +++ b/tests/arch/intel_alm/logic.ys @@ -9,3 +9,17 @@ select -assert-count 1 t:MISTRAL_NOT select -assert-count 6 t:MISTRAL_ALUT2 select -assert-count 2 t:MISTRAL_ALUT4 select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT4 %% t:* %D + + +design -reset +read_verilog ../common/logic.v +hierarchy -top top +proc +equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module + +select -assert-count 1 t:MISTRAL_NOT +select -assert-count 6 t:MISTRAL_ALUT2 +select -assert-count 2 t:MISTRAL_ALUT4 +select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT4 %% t:* %D \ No newline at end of file diff --git a/tests/arch/intel_alm/lutram.ys b/tests/arch/intel_alm/lutram.ys index 6f997b67b06..66f8a15362a 100644 --- a/tests/arch/intel_alm/lutram.ys +++ b/tests/arch/intel_alm/lutram.ys @@ -7,7 +7,7 @@ memory opt -full miter -equiv -flatten -make_assert -make_outputs gold gate miter -sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter +sat -verify -prove-asserts -seq 3 -set-init-zero -show-inputs -show-outputs miter design -load postopt cd lutram_1w1r @@ -18,3 +18,24 @@ select -assert-count 8 t:MISTRAL_ALUT3 select -assert-count 17 t:MISTRAL_FF select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_FF t:MISTRAL_MLAB %% t:* %D + +design -reset +read_verilog ../common/lutram.v +hierarchy -top lutram_1w1r +proc +memory -nomap +equiv_opt -run :prove -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v -map +/intel_alm/common/mem_sim.v synth_intel_alm -family cyclonev -nobram +memory +opt -full + +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -seq 3 -set-init-zero -show-inputs -show-outputs miter + +design -load postopt +cd lutram_1w1r +select -assert-count 16 t:MISTRAL_MLAB +select -assert-count 1 t:MISTRAL_NOT +select -assert-count 2 t:MISTRAL_ALUT2 +select -assert-count 8 t:MISTRAL_ALUT3 +select -assert-count 17 t:MISTRAL_FF +select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_FF t:MISTRAL_MLAB %% t:* %D diff --git a/tests/arch/intel_alm/mux.ys b/tests/arch/intel_alm/mux.ys index 308e452682e..d109257bd9b 100644 --- a/tests/arch/intel_alm/mux.ys +++ b/tests/arch/intel_alm/mux.ys @@ -1,15 +1,26 @@ read_verilog ../common/mux.v design -save read + hierarchy -top mux2 proc equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclonev # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd mux2 # Constrain all select calls below inside the top module select -assert-count 1 t:MISTRAL_ALUT3 +select -assert-none t:MISTRAL_ALUT3 %% t:* %D + +design -load read +hierarchy -top mux2 +proc +equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd mux2 # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_ALUT3 select -assert-none t:MISTRAL_ALUT3 %% t:* %D + design -load read hierarchy -top mux4 proc @@ -17,9 +28,19 @@ equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cycl design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd mux4 # Constrain all select calls below inside the top module select -assert-count 1 t:MISTRAL_ALUT6 +select -assert-none t:MISTRAL_ALUT6 %% t:* %D + +design -load read +hierarchy -top mux4 +proc +equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd mux4 # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_ALUT6 select -assert-none t:MISTRAL_ALUT6 %% t:* %D + design -load read hierarchy -top mux8 proc @@ -29,9 +50,20 @@ cd mux8 # Constrain all select calls below inside the top module select -assert-count 1 t:MISTRAL_ALUT3 select -assert-count 1 t:MISTRAL_ALUT5 select -assert-count 2 t:MISTRAL_ALUT6 - select -assert-none t:MISTRAL_ALUT3 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D + +design -load read +hierarchy -top mux8 +proc +equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd mux8 # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_ALUT3 +select -assert-count 2 t:MISTRAL_ALUT6 +select -assert-none t:MISTRAL_ALUT3 t:MISTRAL_ALUT6 %% t:* %D + + design -load read hierarchy -top mux16 proc @@ -41,5 +73,17 @@ cd mux16 # Constrain all select calls below inside the top module select -assert-count 1 t:MISTRAL_ALUT3 select -assert-count 2 t:MISTRAL_ALUT5 select -assert-count 4 t:MISTRAL_ALUT6 +select -assert-none t:MISTRAL_ALUT3 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D + + +design -load read +hierarchy -top mux16 +proc +equiv_opt -assert -map +/intel_alm/common/alm_sim.v synth_intel_alm -family cyclone10gx # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd mux16 # Constrain all select calls below inside the top module +select -assert-count 1 t:MISTRAL_ALUT3 +select -assert-count 2 t:MISTRAL_ALUT5 +select -assert-count 4 t:MISTRAL_ALUT6 select -assert-none t:MISTRAL_ALUT3 t:MISTRAL_ALUT5 t:MISTRAL_ALUT6 %% t:* %D diff --git a/tests/arch/intel_alm/quartus_ice.ys b/tests/arch/intel_alm/quartus_ice.ys index 4b9b54d10af..a88226e13ba 100644 --- a/tests/arch/intel_alm/quartus_ice.ys +++ b/tests/arch/intel_alm/quartus_ice.ys @@ -10,3 +10,17 @@ EOT synth_intel_alm -family cyclonev -quartus select -assert-none w:*[* w:*]* + +design -reset +read_verilog < Date: Wed, 1 Apr 2020 01:07:30 +0100 Subject: [PATCH 046/287] synth_gowin: ABC9 support This adds ABC9 support for synth_gowin; drastically improving synthesis quality. --- techlibs/gowin/cells_sim.v | 343 ++++++++++++++++++++++++++++++++-- techlibs/gowin/synth_gowin.cc | 31 +-- tests/arch/gowin/init.ys | 6 +- 3 files changed, 345 insertions(+), 35 deletions(-) diff --git a/techlibs/gowin/cells_sim.v b/techlibs/gowin/cells_sim.v index da51759751c..47ece84dfd3 100644 --- a/techlibs/gowin/cells_sim.v +++ b/techlibs/gowin/cells_sim.v @@ -1,33 +1,112 @@ +(* abc9_lut=1 *) module LUT1(output F, input I0); parameter [1:0] INIT = 0; + specify + (I0 => F) = (555, 902); + endspecify assign F = I0 ? INIT[1] : INIT[0]; endmodule +(* abc9_lut=1 *) module LUT2(output F, input I0, I1); parameter [3:0] INIT = 0; + specify + (I0 => F) = (867, 1184); + (I1 => F) = (555, 902); + endspecify wire [ 1: 0] s1 = I1 ? INIT[ 3: 2] : INIT[ 1: 0]; assign F = I0 ? s1[1] : s1[0]; endmodule +(* abc9_lut=1 *) module LUT3(output F, input I0, I1, I2); parameter [7:0] INIT = 0; + specify + (I0 => F) = (1054, 1486); + (I1 => F) = (867, 1184); + (I2 => F) = (555, 902); + endspecify wire [ 3: 0] s2 = I2 ? INIT[ 7: 4] : INIT[ 3: 0]; wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0]; assign F = I0 ? s1[1] : s1[0]; endmodule +(* abc9_lut=1 *) module LUT4(output F, input I0, I1, I2, I3); parameter [15:0] INIT = 0; + specify + (I0 => F) = (1054, 1486); + (I1 => F) = (1053, 1583); + (I2 => F) = (867, 1184); + (I3 => F) = (555, 902); + endspecify wire [ 7: 0] s3 = I3 ? INIT[15: 8] : INIT[ 7: 0]; wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0]; wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0]; assign F = I0 ? s1[1] : s1[0]; endmodule +(* abc9_lut=2 *) +module __APICULA_LUT5(output F, input I0, I1, I2, I3, M0); + specify + (I0 => F) = (1187, 1638); + (I1 => F) = (1184, 1638); + (I2 => F) = (995, 1371); + (I3 => F) = (808, 1116); + (M0 => F) = (486, 680); + endspecify +endmodule + +(* abc9_lut=4 *) +module __APICULA_LUT6(output F, input I0, I1, I2, I3, M0, M1); + specify + (I0 => F) = (1187 + 136, 1638 + 255); + (I1 => F) = (1184 + 136, 1638 + 255); + (I2 => F) = (995 + 136, 1371 + 255); + (I3 => F) = (808 + 136, 1116 + 255); + (M0 => F) = (486 + 136, 680 + 255); + (M1 => F) = (478, 723); + endspecify +endmodule + +(* abc9_lut=8 *) +module __APICULA_LUT7(output F, input I0, I1, I2, I3, M0, M1, M2); + specify + (I0 => F) = (1187 + 136 + 136, 1638 + 255 + 255); + (I1 => F) = (1184 + 136 + 136, 1638 + 255 + 255); + (I2 => F) = (995 + 136 + 136, 1371 + 255 + 255); + (I3 => F) = (808 + 136 + 136, 1116 + 255 + 255); + (M0 => F) = (486 + 136 + 136, 680 + 255 + 255); + (M1 => F) = (478 + 136, 723 + 255); + (M2 => F) = (478, 723); + endspecify +endmodule + +(* abc9_lut=16 *) +module __APICULA_LUT8(output F, input I0, I1, I2, I3, M0, M1, M2, M3); + specify + (I0 => F) = (1187 + 136 + 136 + 136, 1638 + 255 + 255 + 255); + (I1 => F) = (1184 + 136 + 136 + 136, 1638 + 255 + 255 + 255); + (I2 => F) = (995 + 136 + 136 + 136, 1371 + 255 + 255 + 255); + (I3 => F) = (808 + 136 + 136 + 136, 1116 + 255 + 255 + 255); + (M0 => F) = (486 + 136 + 136 + 136, 680 + 255 + 255 + 255); + (M1 => F) = (478 + 136 + 136, 723 + 255 + 255); + (M2 => F) = (478 + 136, 723 + 255); + (M3 => F) = (478, 723); + endspecify + endmodule + module MUX2 (O, I0, I1, S0); input I0,I1; input S0; output O; + + specify + (I0 => O) = (141, 160); + (I1 => O) = (141, 160); + (S0 => O) = (486, 680); + endspecify + assign O = S0 ? I1 : I0; endmodule @@ -35,6 +114,13 @@ module MUX2_LUT5 (O, I0, I1, S0); input I0,I1; input S0; output O; + + specify + (I0 => O) = (141, 160); + (I1 => O) = (141, 160); + (S0 => O) = (486, 680); + endspecify + MUX2 mux2_lut5 (O, I0, I1, S0); endmodule @@ -42,6 +128,13 @@ module MUX2_LUT6 (O, I0, I1, S0); input I0,I1; input S0; output O; + + specify + (I0 => O) = (136, 255); + (I1 => O) = (136, 255); + (S0 => O) = (478, 723); + endspecify + MUX2 mux2_lut6 (O, I0, I1, S0); endmodule @@ -49,6 +142,13 @@ module MUX2_LUT7 (O, I0, I1, S0); input I0,I1; input S0; output O; + + specify + (I0 => O) = (136, 255); + (I1 => O) = (136, 255); + (S0 => O) = (478, 723); + endspecify + MUX2 mux2_lut7 (O, I0, I1, S0); endmodule @@ -56,29 +156,58 @@ module MUX2_LUT8 (O, I0, I1, S0); input I0,I1; input S0; output O; + + specify + (I0 => O) = (136, 255); + (I1 => O) = (136, 255); + (S0 => O) = (478, 723); + endspecify + MUX2 mux2_lut8 (O, I0, I1, S0); endmodule +(* abc9_flop, lib_whitebox *) module DFF (output reg Q, input CLK, D); parameter [0:0] INIT = 1'b0; initial Q = INIT; + + specify + (posedge CLK => (Q : D)) = (480, 660); + $setup(D, posedge CLK, 576); + endspecify + always @(posedge CLK) Q <= D; endmodule +(* abc9_flop, lib_whitebox *) module DFFE (output reg Q, input D, CLK, CE); parameter [0:0] INIT = 1'b0; initial Q = INIT; + + specify + if (CE) (posedge CLK => (Q : D)) = (480, 660); + $setup(D, posedge CLK &&& CE, 576); + $setup(CE, posedge CLK, 63); + endspecify + always @(posedge CLK) begin if (CE) Q <= D; end endmodule // DFFE (positive clock edge; clock enable) - +(* abc9_box, lib_whitebox *) module DFFS (output reg Q, input D, CLK, SET); parameter [0:0] INIT = 1'b1; initial Q = INIT; + + specify + (posedge CLK => (Q : D)) = (480, 660); + $setup(D, posedge CLK, 576); + $setup(SET, posedge CLK, 63); + endspecify + always @(posedge CLK) begin if (SET) Q <= 1'b1; @@ -87,10 +216,18 @@ module DFFS (output reg Q, input D, CLK, SET); end endmodule // DFFS (positive clock edge; synchronous set) - +(* abc9_box, lib_whitebox *) module DFFSE (output reg Q, input D, CLK, CE, SET); parameter [0:0] INIT = 1'b1; initial Q = INIT; + + specify + if (CE) (posedge CLK => (Q : D)) = (480, 660); + $setup(D, posedge CLK &&& CE, 576); + $setup(CE, posedge CLK, 63); + $setup(SET, posedge CLK, 63); + endspecify + always @(posedge CLK) begin if (SET) Q <= 1'b1; @@ -99,10 +236,17 @@ module DFFSE (output reg Q, input D, CLK, CE, SET); end endmodule // DFFSE (positive clock edge; synchronous set takes precedence over clock enable) - +(* abc9_flop, lib_whitebox *) module DFFR (output reg Q, input D, CLK, RESET); parameter [0:0] INIT = 1'b0; initial Q = INIT; + + specify + (posedge CLK => (Q : D)) = (480, 660); + $setup(D, posedge CLK, 576); + $setup(RESET, posedge CLK, 63); + endspecify + always @(posedge CLK) begin if (RESET) Q <= 1'b0; @@ -111,10 +255,18 @@ module DFFR (output reg Q, input D, CLK, RESET); end endmodule // DFFR (positive clock edge; synchronous reset) - +(* abc9_flop, lib_whitebox *) module DFFRE (output reg Q, input D, CLK, CE, RESET); parameter [0:0] INIT = 1'b0; initial Q = INIT; + + specify + if (CE) (posedge CLK => (Q : D)) = (480, 660); + $setup(D, posedge CLK &&& CE, 576); + $setup(CE, posedge CLK, 63); + $setup(RESET, posedge CLK, 63); + endspecify + always @(posedge CLK) begin if (RESET) Q <= 1'b0; @@ -123,10 +275,17 @@ module DFFRE (output reg Q, input D, CLK, CE, RESET); end endmodule // DFFRE (positive clock edge; synchronous reset takes precedence over clock enable) - +(* abc9_box, lib_whitebox *) module DFFP (output reg Q, input D, CLK, PRESET); parameter [0:0] INIT = 1'b1; initial Q = INIT; + + specify + (posedge CLK => (Q : D)) = (480, 660); + (posedge PRESET => (Q : 1'b1)) = (1800, 2679); + $setup(D, posedge CLK, 576); + endspecify + always @(posedge CLK or posedge PRESET) begin if(PRESET) Q <= 1'b1; @@ -135,10 +294,18 @@ module DFFP (output reg Q, input D, CLK, PRESET); end endmodule // DFFP (positive clock edge; asynchronous preset) - +(* abc9_box, lib_whitebox *) module DFFPE (output reg Q, input D, CLK, CE, PRESET); parameter [0:0] INIT = 1'b1; initial Q = INIT; + + specify + if (CE) (posedge CLK => (Q : D)) = (480, 660); + (posedge PRESET => (Q : 1'b1)) = (1800, 2679); + $setup(D, posedge CLK &&& CE, 576); + $setup(CE, posedge CLK, 63); + endspecify + always @(posedge CLK or posedge PRESET) begin if(PRESET) Q <= 1'b1; @@ -147,10 +314,17 @@ module DFFPE (output reg Q, input D, CLK, CE, PRESET); end endmodule // DFFPE (positive clock edge; asynchronous preset; clock enable) - +(* abc9_box, lib_whitebox *) module DFFC (output reg Q, input D, CLK, CLEAR); parameter [0:0] INIT = 1'b0; initial Q = INIT; + + specify + (posedge CLK => (Q : D)) = (480, 660); + (posedge CLEAR => (Q : 1'b0)) = (1800, 2679); + $setup(D, posedge CLK, 576); + endspecify + always @(posedge CLK or posedge CLEAR) begin if(CLEAR) Q <= 1'b0; @@ -159,10 +333,18 @@ module DFFC (output reg Q, input D, CLK, CLEAR); end endmodule // DFFC (positive clock edge; asynchronous clear) - +(* abc9_box, lib_whitebox *) module DFFCE (output reg Q, input D, CLK, CE, CLEAR); parameter [0:0] INIT = 1'b0; initial Q = INIT; + + specify + if (CE) (posedge CLK => (Q : D)) = (480, 660); + (posedge CLEAR => (Q : 1'b0)) = (1800, 2679); + $setup(D, posedge CLK &&& CE, 576); + $setup(CE, posedge CLK, 63); + endspecify + always @(posedge CLK or posedge CLEAR) begin if(CLEAR) Q <= 1'b0; @@ -171,27 +353,48 @@ module DFFCE (output reg Q, input D, CLK, CE, CLEAR); end endmodule // DFFCE (positive clock edge; asynchronous clear; clock enable) - +(* abc9_flop, lib_whitebox *) module DFFN (output reg Q, input CLK, D); parameter [0:0] INIT = 1'b0; initial Q = INIT; + + specify + (negedge CLK => (Q : D)) = (480, 660); + $setup(D, negedge CLK, 576); + endspecify + always @(negedge CLK) Q <= D; endmodule +(* abc9_flop, lib_whitebox *) module DFFNE (output reg Q, input D, CLK, CE); parameter [0:0] INIT = 1'b0; initial Q = INIT; + + specify + if (CE) (negedge CLK => (Q : D)) = (480, 660); + $setup(D, negedge CLK &&& CE, 576); + $setup(CE, negedge CLK, 63); + endspecify + always @(negedge CLK) begin if (CE) Q <= D; end endmodule // DFFNE (negative clock edge; clock enable) - +(* abc9_box, lib_whitebox *) module DFFNS (output reg Q, input D, CLK, SET); parameter [0:0] INIT = 1'b1; initial Q = INIT; + + specify + (negedge CLK => (Q : D)) = (480, 660); + $setup(D, negedge CLK, 576); + $setup(SET, negedge CLK, 63); + endspecify + always @(negedge CLK) begin if (SET) Q <= 1'b1; @@ -200,10 +403,18 @@ module DFFNS (output reg Q, input D, CLK, SET); end endmodule // DFFNS (negative clock edge; synchronous set) - +(* abc9_box, lib_whitebox *) module DFFNSE (output reg Q, input D, CLK, CE, SET); parameter [0:0] INIT = 1'b1; initial Q = INIT; + + specify + if (CE) (negedge CLK => (Q : D)) = (480, 660); + $setup(D, negedge CLK &&& CE, 576); + $setup(CE, negedge CLK, 63); + $setup(SET, negedge CLK, 63); + endspecify + always @(negedge CLK) begin if (SET) Q <= 1'b1; @@ -212,10 +423,17 @@ module DFFNSE (output reg Q, input D, CLK, CE, SET); end endmodule // DFFNSE (negative clock edge; synchronous set takes precedence over clock enable) - +(* abc9_flop, lib_whitebox *) module DFFNR (output reg Q, input D, CLK, RESET); parameter [0:0] INIT = 1'b0; initial Q = INIT; + + specify + (negedge CLK => (Q : D)) = (480, 660); + $setup(D, negedge CLK, 576); + $setup(RESET, negedge CLK, 63); + endspecify + always @(negedge CLK) begin if (RESET) Q <= 1'b0; @@ -224,10 +442,18 @@ module DFFNR (output reg Q, input D, CLK, RESET); end endmodule // DFFNR (negative clock edge; synchronous reset) - +(* abc9_flop, lib_whitebox *) module DFFNRE (output reg Q, input D, CLK, CE, RESET); parameter [0:0] INIT = 1'b0; initial Q = INIT; + + specify + if (CE) (negedge CLK => (Q : D)) = (480, 660); + $setup(D, negedge CLK &&& CE, 576); + $setup(CE, negedge CLK, 63); + $setup(RESET, negedge CLK, 63); + endspecify + always @(negedge CLK) begin if (RESET) Q <= 1'b0; @@ -236,10 +462,17 @@ module DFFNRE (output reg Q, input D, CLK, CE, RESET); end endmodule // DFFNRE (negative clock edge; synchronous reset takes precedence over clock enable) - +(* abc9_box, lib_whitebox *) module DFFNP (output reg Q, input D, CLK, PRESET); parameter [0:0] INIT = 1'b1; initial Q = INIT; + + specify + (negedge CLK => (Q : D)) = (480, 660); + (posedge PRESET => (Q : 1'b1)) = (1800, 2679); + $setup(D, negedge CLK, 576); + endspecify + always @(negedge CLK or posedge PRESET) begin if(PRESET) Q <= 1'b1; @@ -248,10 +481,18 @@ module DFFNP (output reg Q, input D, CLK, PRESET); end endmodule // DFFNP (negative clock edge; asynchronous preset) - +(* abc9_box, lib_whitebox *) module DFFNPE (output reg Q, input D, CLK, CE, PRESET); parameter [0:0] INIT = 1'b1; initial Q = INIT; + + specify + if (CE) (negedge CLK => (Q : D)) = (480, 660); + (posedge PRESET => (Q : 1'b1)) = (1800, 2679); + $setup(D, negedge CLK &&& CE, 576); + $setup(CE, negedge CLK, 63); + endspecify + always @(negedge CLK or posedge PRESET) begin if(PRESET) Q <= 1'b1; @@ -260,10 +501,17 @@ module DFFNPE (output reg Q, input D, CLK, CE, PRESET); end endmodule // DFFNPE (negative clock edge; asynchronous preset; clock enable) - +(* abc9_box, lib_whitebox *) module DFFNC (output reg Q, input D, CLK, CLEAR); parameter [0:0] INIT = 1'b0; initial Q = INIT; + + specify + (negedge CLK => (Q : D)) = (480, 660); + (posedge CLEAR => (Q : 1'b0)) = (1800, 2679); + $setup(D, negedge CLK, 576); + endspecify + always @(negedge CLK or posedge CLEAR) begin if(CLEAR) Q <= 1'b0; @@ -272,10 +520,18 @@ module DFFNC (output reg Q, input D, CLK, CLEAR); end endmodule // DFFNC (negative clock edge; asynchronous clear) - +(* abc9_box, lib_whitebox *) module DFFNCE (output reg Q, input D, CLK, CE, CLEAR); parameter [0:0] INIT = 1'b0; initial Q = INIT; + + specify + if (CE) (negedge CLK => (Q : D)) = (480, 660); + (posedge CLEAR => (Q : 1'b0)) = (1800, 2679); + $setup(D, negedge CLK &&& CE, 576); + $setup(CE, negedge CLK, 63); + endspecify + always @(negedge CLK or posedge CLEAR) begin if(CLEAR) Q <= 1'b0; @@ -294,11 +550,23 @@ module GND(output G); assign G = 0; endmodule +(* abc9_box *) module IBUF(output O, input I); + + specify + (I => O) = 0; + endspecify + assign O = I; endmodule +(* abc9_box *) module OBUF(output O, input I); + + specify + (I => O) = 0; + endspecify + assign O = I; endmodule @@ -320,14 +588,15 @@ module GSR (input GSRI); wire GSRO = GSRI; endmodule +(* abc9_box, lib_whitebox *) module ALU (SUM, COUT, I0, I1, I3, CIN); input I0; input I1; input I3; -input CIN; +(* abc9_carry *) input CIN; output SUM; -output COUT; +(* abc9_carry *) output COUT; localparam ADD = 0; localparam SUB = 1; @@ -344,6 +613,17 @@ parameter ALU_MODE = 0; reg S, C; +specify + (I0 => SUM) = (1043, 1432); + (I1 => SUM) = (775, 1049); + (I3 => SUM) = (751, 1010); + (CIN => SUM) = (694, 811); + (I0 => COUT) = (1010, 1380); + (I1 => COUT) = (1021, 1505); + (I3 => COUT) = (483, 792); + (CIN => COUT) = (49, 82); +endspecify + assign SUM = S ^ CIN; assign COUT = S? CIN : C; @@ -394,7 +674,6 @@ end endmodule - module RAM16S4 (DO, DI, AD, WRE, CLK); parameter WIDTH = 4; parameter INIT_0 = 16'h0000; @@ -408,6 +687,14 @@ module RAM16S4 (DO, DI, AD, WRE, CLK); input CLK; input WRE; + specify + (AD => DO) = (270, 405); + $setup(DI, posedge CLK, 62); + $setup(WRE, posedge CLK, 62); + $setup(AD, posedge CLK, 62); + (posedge CLK => (DO : {WIDTH{1'bx}})) = (474, 565); + endspecify + reg [15:0] mem0, mem1, mem2, mem3; initial begin @@ -516,5 +803,21 @@ input [31:0] DI; input [2:0] BLKSEL; output [31:0] DO; +specify + (posedge CLKB => (DO : DI)) = (419, 493); + $setup(RESETA, posedge CLKA, 62); + $setup(RESETB, posedge CLKB, 62); + $setup(OCE, posedge CLKB, 62); + $setup(CEA, posedge CLKA, 62); + $setup(CEB, posedge CLKB, 62); + $setup(OCE, posedge CLKB, 62); + $setup(WREA, posedge CLKA, 62); + $setup(WREB, posedge CLKB, 62); + $setup(DI, posedge CLKA, 62); + $setup(ADA, posedge CLKA, 62); + $setup(ADB, posedge CLKB, 62); + $setup(BLKSEL, posedge CLKA, 62); +endspecify + endmodule diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 1e82e1ed6ed..987d3184033 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -69,9 +69,9 @@ struct SynthGowinPass : public ScriptPass log("\n"); log(" -noiopads\n"); log(" do not emit IOB at top level ports\n"); - //log("\n"); - //log(" -abc9\n"); - //log(" use new ABC9 flow (EXPERIMENTAL)\n"); + log("\n"); + log(" -abc9\n"); + log(" use new ABC9 flow (EXPERIMENTAL)\n"); log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); @@ -144,10 +144,10 @@ struct SynthGowinPass : public ScriptPass nowidelut = true; continue; } - //if (args[argidx] == "-abc9") { - // abc9 = true; - // continue; - //} + if (args[argidx] == "-abc9") { + abc9 = true; + continue; + } if (args[argidx] == "-noiopads") { noiopads = true; continue; @@ -171,7 +171,7 @@ struct SynthGowinPass : public ScriptPass { if (check_label("begin")) { - run("read_verilog -lib +/gowin/cells_sim.v"); + run("read_verilog -specify -lib +/gowin/cells_sim.v"); run(stringf("hierarchy -check %s", help_mode ? "-top " : top_opt.c_str())); } @@ -230,13 +230,15 @@ struct SynthGowinPass : public ScriptPass if (check_label("map_luts")) { - /*if (nowidelut && abc9) { - run("abc9 -lut 4"); - } else*/ if (nowidelut && !abc9) { + if (nowidelut && abc9) { + run("read_verilog -icells -lib -specify +/abc9_model.v"); + run("abc9 -maxlut 4 -W 500"); + } else if (nowidelut && !abc9) { run("abc -lut 4"); - } else /*if (!nowidelut && abc9) { - run("abc9 -lut 4:8"); - } else*/ if (!nowidelut && !abc9) { + } else if (!nowidelut && abc9) { + run("read_verilog -icells -lib -specify +/abc9_model.v"); + run("abc9 -maxlut 8 -W 500"); + } else if (!nowidelut && !abc9) { run("abc -lut 4:8"); } run("clean"); @@ -252,6 +254,7 @@ struct SynthGowinPass : public ScriptPass run("iopadmap -bits -inpad IBUF O:I -outpad OBUF I:O " "-toutpad TBUF OEN:I:O -tinoutpad IOBUF OEN:O:I:IO", "(unless -noiopads)"); run("clean"); + run("autoname"); } if (check_label("check")) diff --git a/tests/arch/gowin/init.ys b/tests/arch/gowin/init.ys index ddc0e47579f..4d8e442ac7a 100644 --- a/tests/arch/gowin/init.ys +++ b/tests/arch/gowin/init.ys @@ -30,7 +30,6 @@ select -assert-count 1 t:DFFRE select -assert-count 1 t:DFFS select -assert-count 1 t:DFFSE -delete design -load read # these should synth to a flop with reset @@ -68,6 +67,11 @@ select -assert-count 2 t:DFFS select -assert-count 2 t:DFFSE select -assert-count 12 t:LUT2 +# Remove all whiteboxes so we don't inadvertently +# count init attributes inside them +# Should be superseded by https://github.com/YosysHQ/yosys/pull/1949 +delete A:whitebox=1 + # check the expected leftover init values # this would happen if your reset value is not the initial value # which would be weird From af54b8bc6123f6e90a97268624b84ac270dc1879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Sun, 5 Jul 2020 22:21:59 +0200 Subject: [PATCH 047/287] Naming fixes. --- passes/techmap/clkbufmap.cc | 2 +- passes/techmap/extractinv.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/techmap/clkbufmap.cc b/passes/techmap/clkbufmap.cc index 451325fee45..4e9b910db46 100644 --- a/passes/techmap/clkbufmap.cc +++ b/passes/techmap/clkbufmap.cc @@ -2,7 +2,7 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf - * Copyright (C) 2019 Marcin Koƛcielnicki + * Copyright (C) 2019 Marcelina Koƛcielnicka * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/passes/techmap/extractinv.cc b/passes/techmap/extractinv.cc index 9b350456f01..11463380cc8 100644 --- a/passes/techmap/extractinv.cc +++ b/passes/techmap/extractinv.cc @@ -2,7 +2,7 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf - * Copyright (C) 2019 Marcin Koƛcielnicki + * Copyright (C) 2019 Marcelina Koƛcielnicka * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above From 09ecb9b2cf3ab76841d30712bf70dafc6d47ef67 Mon Sep 17 00:00:00 2001 From: Dan Ravensloft Date: Thu, 11 Jun 2020 22:25:04 +0100 Subject: [PATCH 048/287] intel_alm: direct M10K instantiation --- techlibs/intel_alm/Makefile.inc | 6 +-- techlibs/intel_alm/common/bram_m10k.txt | 4 +- techlibs/intel_alm/common/bram_m10k_map.v | 31 -------------- techlibs/intel_alm/common/megafunction_bb.v | 37 ++++++++++++++++- techlibs/intel_alm/common/mem_sim.v | 34 ++++++++++++++++ techlibs/intel_alm/common/quartus_rename.v | 45 +++++++++++++++++++++ techlibs/intel_alm/synth_intel_alm.cc | 3 +- tests/arch/intel_alm/blockram.ys | 6 +++ 8 files changed, 128 insertions(+), 38 deletions(-) delete mode 100644 techlibs/intel_alm/common/bram_m10k_map.v create mode 100644 tests/arch/intel_alm/blockram.ys diff --git a/techlibs/intel_alm/Makefile.inc b/techlibs/intel_alm/Makefile.inc index 552f00c658e..e36c81c0ec4 100644 --- a/techlibs/intel_alm/Makefile.inc +++ b/techlibs/intel_alm/Makefile.inc @@ -15,9 +15,9 @@ $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/ds $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/mem_sim.v)) # RAM -bramtypes := m10k m20k -$(foreach bramtype, $(bramtypes), $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_$(bramtype).txt))) -$(foreach bramtype, $(bramtypes), $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_$(bramtype)_map.v))) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_m10k.txt)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_m20k.txt)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_m20k_map.v)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/lutram_mlab.txt)) # Miscellaneous diff --git a/techlibs/intel_alm/common/bram_m10k.txt b/techlibs/intel_alm/common/bram_m10k.txt index 837e3a33032..e9355fe2cc9 100644 --- a/techlibs/intel_alm/common/bram_m10k.txt +++ b/techlibs/intel_alm/common/bram_m10k.txt @@ -1,4 +1,4 @@ -bram __MISTRAL_M10K_SDP +bram MISTRAL_M10K init 0 # TODO: Re-enable when I figure out how BRAM init works abits 13 @D8192x1 dbits 1 @D8192x1 @@ -27,7 +27,7 @@ bram __MISTRAL_M10K_SDP endbram -match __MISTRAL_M10K_SDP +match MISTRAL_M10K min efficiency 5 make_transp endmatch diff --git a/techlibs/intel_alm/common/bram_m10k_map.v b/techlibs/intel_alm/common/bram_m10k_map.v deleted file mode 100644 index 061463c3e1d..00000000000 --- a/techlibs/intel_alm/common/bram_m10k_map.v +++ /dev/null @@ -1,31 +0,0 @@ -module __MISTRAL_M10K_SDP(CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); - -parameter CFG_ABITS = 10; -parameter CFG_DBITS = 10; -parameter CFG_ENABLE_A = 1; -parameter CFG_ENABLE_B = 1; - -input CLK1; -input [CFG_ABITS-1:0] A1ADDR, B1ADDR; -input [CFG_DBITS-1:0] A1DATA; -output [CFG_DBITS-1:0] B1DATA; -input [CFG_ENABLE_A-1:0] A1EN, B1EN; - -altsyncram #( - .operation_mode("dual_port"), - .ram_block_type("m10k"), - .widthad_a(CFG_ABITS), - .width_a(CFG_DBITS), - .widthad_b(CFG_ABITS), - .width_b(CFG_DBITS), -) _TECHMAP_REPLACE_ ( - .address_a(A1ADDR), - .data_a(A1DATA), - .wren_a(A1EN), - .address_b(B1ADDR), - .q_b(B1DATA), - .clock0(CLK1), - .clock1(CLK1) -); - -endmodule diff --git a/techlibs/intel_alm/common/megafunction_bb.v b/techlibs/intel_alm/common/megafunction_bb.v index b5a3d889261..820b0430e0b 100644 --- a/techlibs/intel_alm/common/megafunction_bb.v +++ b/techlibs/intel_alm/common/megafunction_bb.v @@ -156,4 +156,39 @@ input [ax_width-1:0] ax; input [ay_scan_in_width-1:0] ay; output [result_a_width-1:0] resulta; -endmodule \ No newline at end of file +endmodule + +(* blackbox *) +module cyclonev_ram_block(portaaddr, portadatain, portawe, portbaddr, portbdataout, portbre, clk0); + +parameter operation_mode = "dual_port"; +parameter logical_ram_name = ""; +parameter port_a_address_width = 10; +parameter port_a_data_width = 10; +parameter port_a_logical_ram_depth = 1024; +parameter port_a_logical_ram_width = 10; +parameter port_a_first_address = 0; +parameter port_a_last_address = 1023; +parameter port_a_first_bit_number = 0; +parameter port_b_address_width = 10; +parameter port_b_data_width = 10; +parameter port_b_logical_ram_depth = 1024; +parameter port_b_logical_ram_width = 10; +parameter port_b_first_address = 0; +parameter port_b_last_address = 1023; +parameter port_b_first_bit_number = 0; +parameter port_b_address_clock = "clock0"; +parameter port_b_read_enable_clock = "clock0"; +parameter mem_init0 = ""; +parameter mem_init1 = ""; +parameter mem_init2 = ""; +parameter mem_init3 = ""; +parameter mem_init4 = ""; + +input [port_a_address_width-1:0] portaaddr; +input [port_b_address_width-1:0] portbaddr; +input [port_a_data_width-1:0] portadatain; +output [port_b_data_width-1:0] portbdataout; +input clk0, portawe, portbre; + +endmodule diff --git a/techlibs/intel_alm/common/mem_sim.v b/techlibs/intel_alm/common/mem_sim.v index f6f9ecb02b0..23ffc6c878d 100644 --- a/techlibs/intel_alm/common/mem_sim.v +++ b/techlibs/intel_alm/common/mem_sim.v @@ -68,3 +68,37 @@ always @(posedge CLK1) assign B1DATA = mem[B1ADDR]; endmodule + +// The M10K +// -------- +// TODO + +module MISTRAL_M10K(CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); + +parameter CFG_ABITS = 10; +parameter CFG_DBITS = 10; + +input CLK1; +input [CFG_ABITS-1:0] A1ADDR, B1ADDR; +input [CFG_DBITS-1:0] A1DATA; +input A1EN, B1EN; +output reg [CFG_DBITS-1:0] B1DATA; + +reg [2**CFG_ABITS * CFG_DBITS - 1 : 0] mem = 0; + +specify + $setup(A1ADDR, posedge CLK1, 0); + $setup(A1DATA, posedge CLK1, 0); + + if (B1EN) (posedge CLK1 => (B1DATA : A1DATA)) = 0; +endspecify + +always @(posedge CLK1) begin + if (A1EN) + mem[(A1ADDR + 1) * CFG_DBITS - 1 : A1ADDR * CFG_DBITS] <= A1DATA; + + if (B1EN) + B1DATA <= mem[(B1ADDR + 1) * CFG_DBITS - 1 : B1ADDR * CFG_DBITS]; +end + +endmodule diff --git a/techlibs/intel_alm/common/quartus_rename.v b/techlibs/intel_alm/common/quartus_rename.v index 46ef2aa0dc7..926d2d64f9f 100644 --- a/techlibs/intel_alm/common/quartus_rename.v +++ b/techlibs/intel_alm/common/quartus_rename.v @@ -123,6 +123,51 @@ module MISTRAL_MLAB(input [4:0] A1ADDR, input A1DATA, A1EN, CLK1, input [4:0] B1 endmodule +module MISTRAL_M10K(A1ADDR, A1DATA, A1EN, CLK1, B1ADDR, B1DATA, B1EN); + +parameter CFG_ABITS = 10; +parameter CFG_DBITS = 10; + +input [CFG_ABITS-1:0] A1ADDR, B1ADDR; +input [CFG_DBITS-1:0] A1DATA; +input CLK1, A1EN, B1EN; +output [CFG_DBITS-1:0] B1DATA; + +// Much like the MLAB, the M10K has mem_init[01234] parameters which would let +// you initialise the RAM cell via hex literals. If they were implemented. + +cyclonev_ram_block #( + .operation_mode("dual_port"), + .logical_ram_name("MISTRAL_M10K"), + .port_a_address_width(CFG_ABITS), + .port_a_data_width(CFG_DBITS), + .port_a_logical_ram_depth(2**CFG_ABITS), + .port_a_logical_ram_width(CFG_DBITS), + .port_a_first_address(0), + .port_a_last_address(2**CFG_DBITS - 1), + .port_a_first_bit_number(0), + .port_b_address_width(CFG_ABITS), + .port_b_data_width(CFG_DBITS), + .port_b_logical_ram_depth(2**CFG_ABITS), + .port_b_logical_ram_width(CFG_DBITS), + .port_b_first_address(0), + .port_b_last_address(2**CFG_DBITS - 1), + .port_b_first_bit_number(0), + .port_b_address_clock("clock0"), + .port_b_read_enable_clock("clock0") +) _TECHMAP_REPLACE_ ( + .portaaddr(A1ADDR), + .portadatain(A1DATA), + .portawe(A1EN), + .portbaddr(B1ADDR), + .portbdataout(B1DATA), + .portbre(B1EN), + .clk0(CLK1) +); + +endmodule + + module MISTRAL_MUL27X27(input [26:0] A, B, output [53:0] Y); `MAC #(.ax_width(27), .ay_scan_in_width(27), .result_a_width(54), .operation_mode("M27x27")) _TECHMAP_REPLACE_ (.ax(A), .ay(B), .resulta(Y)); diff --git a/techlibs/intel_alm/synth_intel_alm.cc b/techlibs/intel_alm/synth_intel_alm.cc index b751e8413fc..12137cdeae9 100644 --- a/techlibs/intel_alm/synth_intel_alm.cc +++ b/techlibs/intel_alm/synth_intel_alm.cc @@ -235,7 +235,8 @@ struct SynthIntelALMPass : public ScriptPass { if (!nobram && check_label("map_bram", "(skip if -nobram)")) { run(stringf("memory_bram -rules +/intel_alm/common/bram_%s.txt", bram_type.c_str())); - run(stringf("techmap -map +/intel_alm/common/bram_%s_map.v", bram_type.c_str())); + if (help_mode || bram_type != "m10k") + run(stringf("techmap -map +/intel_alm/common/bram_%s_map.v", bram_type.c_str())); } if (!nolutram && check_label("map_lutram", "(skip if -nolutram)")) { diff --git a/tests/arch/intel_alm/blockram.ys b/tests/arch/intel_alm/blockram.ys new file mode 100644 index 00000000000..610ae1ffdbd --- /dev/null +++ b/tests/arch/intel_alm/blockram.ys @@ -0,0 +1,6 @@ +read_verilog ../common/blockram.v +chparam -set ADDRESS_WIDTH 10 -set DATA_WIDTH 10 sync_ram_sdp +synth_intel_alm -family cyclonev +cd sync_ram_sdp +select -assert-count 1 t:MISTRAL_M10K +select -assert-none t:MISTRAL_M10K %% t:* %D From 7e83a51fc96495c558a31fc3ca6c1a5ba4764f15 Mon Sep 17 00:00:00 2001 From: Lukasz Dalek Date: Mon, 18 May 2020 21:02:19 +0200 Subject: [PATCH 049/287] Support logic typed parameters Signed-off-by: Lukasz Dalek --- frontends/verilog/verilog_parser.y | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 656910c0cb3..dfdb11cf0e6 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -1337,8 +1337,6 @@ param_signed: param_integer: TOK_INTEGER { - if (astbuf1->children.size() != 1) - frontend_verilog_yyerror("Internal error in param_integer - should not happen?"); astbuf1->children.push_back(new AstNode(AST_RANGE)); astbuf1->children.back()->children.push_back(AstNode::mkconst_int(31, true)); astbuf1->children.back()->children.push_back(AstNode::mkconst_int(0, true)); @@ -1347,16 +1345,19 @@ param_integer: param_real: TOK_REAL { - if (astbuf1->children.size() != 1) - frontend_verilog_yyerror("Parameter already declared as integer, cannot set to real."); astbuf1->children.push_back(new AstNode(AST_REALVALUE)); } +param_logic: + TOK_LOGIC { + // SV LRM 6.11, Table 6-8: logic -- 4-state, user-defined vector size, unsigned + astbuf1->is_signed = false; + astbuf1->is_logic = true; + } + param_range: range { if ($1 != NULL) { - if (astbuf1->children.size() != 1) - frontend_verilog_yyerror("integer/real parameters should not have a range."); astbuf1->children.push_back($1); } }; @@ -1365,8 +1366,10 @@ param_integer_type: param_integer param_signed param_range_type: type_vec param_signed param_range param_implicit_type: param_signed param_range +param_integer_vector_type: param_logic param_signed param_range + param_type: - param_integer_type | param_real | param_range_type | param_implicit_type | + param_integer_type | param_integer_vector_type | param_real | param_range_type | param_implicit_type | hierarchical_type_id { astbuf1->is_custom_type = true; astbuf1->children.push_back(new AstNode(AST_WIRETYPE)); From b422f2e4d0b8d5bfa97913d6b9dee488b59fc405 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Mon, 6 Jul 2020 09:05:34 +0200 Subject: [PATCH 050/287] Add logic param and integer bad syntax tests Signed-off-by: Kamil Rakoczy --- tests/various/integer_range_bad_syntax.ys | 6 ++++++ tests/various/integer_real_bad_syntax.ys | 6 ++++++ tests/various/logic_param_simple.ys | 9 +++++++++ 3 files changed, 21 insertions(+) create mode 100644 tests/various/integer_range_bad_syntax.ys create mode 100644 tests/various/integer_real_bad_syntax.ys create mode 100644 tests/various/logic_param_simple.ys diff --git a/tests/various/integer_range_bad_syntax.ys b/tests/various/integer_range_bad_syntax.ys new file mode 100644 index 00000000000..4f427211f3e --- /dev/null +++ b/tests/various/integer_range_bad_syntax.ys @@ -0,0 +1,6 @@ +logger -expect error "syntax error, unexpected" 1 +read_verilog -sv < Date: Fri, 3 Jul 2020 00:23:18 +0200 Subject: [PATCH 051/287] gowin: Use dfflegalize. --- techlibs/gowin/cells_map.v | 185 +++++++-------------------------- techlibs/gowin/synth_gowin.cc | 1 + tests/arch/gowin/init-error.ys | 5 + tests/arch/gowin/init.ys | 16 +-- 4 files changed, 49 insertions(+), 158 deletions(-) create mode 100644 tests/arch/gowin/init-error.ys diff --git a/techlibs/gowin/cells_map.v b/techlibs/gowin/cells_map.v index 5460274cacf..851ef20b262 100644 --- a/techlibs/gowin/cells_map.v +++ b/techlibs/gowin/cells_map.v @@ -3,228 +3,123 @@ //value regardless. The parameter is ignored. // DFFN D Flip-Flop with Negative-Edge Clock -module \$_DFF_N_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, output Q); - generate - if (_TECHMAP_WIREINIT_Q_ === 1'b1) - DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .SET(1'b0)); - else - DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); - endgenerate +module \$_DFF_N_ (input D, C, output Q); + DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule // DFF D Flip-Flop -module \$_DFF_P_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, output Q); - generate - if (_TECHMAP_WIREINIT_Q_ === 1'b1) - DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .SET(1'b0)); - else - DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); - endgenerate +module \$_DFF_P_ (input D, C, output Q); + DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule // DFFE D Flip-Flop with Clock Enable -module \$_DFFE_PP_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, E, output Q); - generate - if (_TECHMAP_WIREINIT_Q_ === 1'b1) - DFFSE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CE(E), .SET(1'b0)); - else - DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CE(E)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -module \$_DFFE_PN_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, E, output Q); - generate - if (_TECHMAP_WIREINIT_Q_ === 1'b1) - DFFSE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CE(!E), .SET(1'b0)); - else - DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CE(!E)); - endgenerate +module \$_DFFE_PP_ (input D, C, E, output Q); + DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CE(E)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule // DFFNE D Flip-Flop with Negative-Edge Clock and Clock Enable -module \$_DFFE_NP_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, E, output Q); - generate - if (_TECHMAP_WIREINIT_Q_ === 1'b1) - DFFNSE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CE(E), .SET(1'b0)); - else - DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CE(E)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -module \$_DFFE_NN_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, E, output Q); - generate - if (_TECHMAP_WIREINIT_Q_ === 1'b1) - DFFNSE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CE(!E), .SET(1'b0)); - else - DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CE(!E)); - endgenerate +module \$_DFFE_NP_ (input D, C, E, output Q); + DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CE(E)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule // DFFR D Flip-Flop with Synchronous Reset -module \$_SDFF_PN0_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, output Q); - DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(!R)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b1; -endmodule - -module \$_SDFF_PP0_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, output Q); +module \$_SDFF_PP0_ (input D, C, R, output Q); DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(R)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b1; + wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule // DFFNR D Flip-Flop with Negative-Edge Clock and Synchronous Reset -module \$_SDFF_NN0_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, output Q); - DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(!R)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b1; -endmodule -module \$_SDFF_NP0_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, output Q); +module \$_SDFF_NP0_ (input D, C, R, output Q); DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(R)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b1; + wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule // DFFRE D Flip-Flop with Clock Enable and Synchronous Reset -module \$_SDFFE_PN0P_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, E, output Q); - DFFRE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(!R), .CE(E)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b1; -endmodule -module \$_SDFFE_PP0P_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, E, output Q); +module \$_SDFFE_PP0P_ (input D, C, R, E, output Q); DFFRE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(R), .CE(E)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b1; + wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule // DFFNRE D Flip-Flop with Negative-Edge Clock,Clock Enable, and Synchronous Reset -module \$_SDFFE_NN0P_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, E, output Q); - DFFNRE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(!R), .CE(E)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b1; -endmodule -module \$_SDFFE_NP0P_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, E, output Q); +module \$_SDFFE_NP0P_ (input D, C, R, E, output Q); DFFNRE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(R), .CE(E)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b1; + wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule // DFFS D Flip-Flop with Synchronous Set -module \$_SDFF_PN1_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, output Q); - DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .SET(!R)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b0; -endmodule -module \$_SDFF_PP1_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, output Q); +module \$_SDFF_PP1_ (input D, C, R, output Q); DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .SET(R)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b0; + wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule // DFFNS D Flip-Flop with Negative-Edge Clock and Synchronous Set -module \$_SDFF_NN1_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, output Q); - DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .SET(!R)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b0; -endmodule -module \$_SDFF_NP1_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, output Q); +module \$_SDFF_NP1_ (input D, C, R, output Q); DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .SET(R)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b0; + wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule // DFFSE D Flip-Flop with Clock Enable and Synchronous Set -module \$_SDFFE_PN1P_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, E, output Q); - DFFSE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .SET(!R), .CE(E)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b0; -endmodule -module \$_SDFFE_PP1P_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, E, output Q); +module \$_SDFFE_PP1P_ (input D, C, R, E, output Q); DFFSE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .SET(R), .CE(E)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b0; + wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule // DFFNSE D Flip-Flop with Negative-Edge Clock,Clock Enable,and Synchronous Set -module \$_SDFFE_NN1P_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, E, output Q); - DFFNSE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .SET(!R), .CE(E)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b0; -endmodule -module \$_SDFFE_NP1P_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, E, output Q); +module \$_SDFFE_NP1P_ (input D, C, R, E, output Q); DFFNSE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .SET(R), .CE(E)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b0; + wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule // DFFP D Flip-Flop with Asynchronous Preset -module \$_DFF_PP1_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, output Q); +module \$_DFF_PP1_ (input D, C, R, output Q); DFFP _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .PRESET(R)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b0; -endmodule -module \$_DFF_PN1_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, output Q); - DFFP _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .PRESET(!R)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b0; + wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule // DFFNP D Flip-Flop with Negative-Edge Clock and Asynchronous Preset -module \$_DFF_NP1_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, output Q); +module \$_DFF_NP1_ (input D, C, R, output Q); DFFNP _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .PRESET(R)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b0; -endmodule -module \$_DFF_NN1_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, output Q); - DFFNP _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .PRESET(!R)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b0; + wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule // DFFC D Flip-Flop with Asynchronous Clear -module \$_DFF_PP0_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, output Q); +module \$_DFF_PP0_ (input D, C, R, output Q); DFFC _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CLEAR(R)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b1; -endmodule -module \$_DFF_PN0_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, output Q); - DFFC _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CLEAR(!R)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b1; + wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule // DFFNC D Flip-Flop with Negative-Edge Clock and Asynchronous Clear -module \$_DFF_NP0_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, output Q); +module \$_DFF_NP0_ (input D, C, R, output Q); DFFNC _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CLEAR(R)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b1; -endmodule -module \$_DFF_NN0_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, output Q); - DFFNC _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CLEAR(!R)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b1; + wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule // DFFPE D Flip-Flop with Clock Enable and Asynchronous Preset -module \$_DFFE_PP1P_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, E, output Q); +module \$_DFFE_PP1P_ (input D, C, R, E, output Q); DFFPE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .PRESET(R), .CE(E)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b0; -endmodule -module \$_DFFE_PN1P_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, E, output Q); - DFFPE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .PRESET(!R), .CE(E)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b0; + wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule // DFFNPE D Flip-Flop with Negative-Edge Clock,Clock Enable, and Asynchronous Preset -module \$_DFFE_NP1P_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, E, output Q); +module \$_DFFE_NP1P_ (input D, C, R, E, output Q); DFFNPE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .PRESET(R), .CE(E)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b0; -endmodule -module \$_DFFE_NN1P_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, E, output Q); - DFFNPE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .PRESET(!R), .CE(E)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b0; + wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule // DFFCE D Flip-Flop with Clock Enable and Asynchronous Clear -module \$_DFFE_PP0P_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, E, output Q); +module \$_DFFE_PP0P_ (input D, C, R, E, output Q); DFFCE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CLEAR(R), .CE(E)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b1; -endmodule -module \$_DFFE_PN0P_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, E, output Q); - DFFCE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CLEAR(!R), .CE(E)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b1; + wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule // DFFNCE D Flip-Flop with Negative-Edge Clock,Clock Enable and Asynchronous Clear -module \$_DFFE_NP0P_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, E, output Q); +module \$_DFFE_NP0P_ (input D, C, R, E, output Q); DFFNCE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CLEAR(R), .CE(E)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b1; -endmodule -module \$_DFFE_NN0P_ #(parameter _TECHMAP_WIREINIT_Q_ = 1'bx) (input D, C, R, E, output Q); - DFFNCE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .CLEAR(!R), .CE(E)); - wire _TECHMAP_REMOVEINIT_Q_ = _TECHMAP_WIREINIT_Q_ !== 1'b1; + wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 987d3184033..d7b11d4311f 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -223,6 +223,7 @@ struct SynthGowinPass : public ScriptPass run("opt_clean"); if (!nodffe) run("dff2dffe -direct-match $_DFF_* -direct-match $_SDFF_*"); + run("dfflegalize -cell $_DFF_?_ 0 -cell $_DFFE_?P_ 0 -cell $_SDFF_?P?_ r -cell $_SDFFE_?P?P_ r -cell $_DFF_?P?_ r -cell $_DFFE_?P?P_ r"); run("techmap -map +/gowin/cells_map.v"); run("opt_expr -mux_undef"); run("simplemap"); diff --git a/tests/arch/gowin/init-error.ys b/tests/arch/gowin/init-error.ys new file mode 100644 index 00000000000..de3813d6f8a --- /dev/null +++ b/tests/arch/gowin/init-error.ys @@ -0,0 +1,5 @@ +read_verilog init.v +chparam -set INIT 0 myDFF*P* +hierarchy -top myDFFP +logger -expect error "unsupported initial value and async reset value combination" 1 +synth_gowin diff --git a/tests/arch/gowin/init.ys b/tests/arch/gowin/init.ys index 4d8e442ac7a..88e88c15ae2 100644 --- a/tests/arch/gowin/init.ys +++ b/tests/arch/gowin/init.ys @@ -35,10 +35,10 @@ design -load read # these should synth to a flop with reset chparam -set INIT 1 myDFF myDFFN myDFFE myDFFNE -# async should give a warning +# async would give an error # sync should synth to a mux -chparam -set INIT 0 myDFF*S* myDFF*P* -chparam -set INIT 1 myDFF*R* myDFF*C* +chparam -set INIT 0 myDFF*S* +chparam -set INIT 1 myDFF*R* proc flatten @@ -66,13 +66,3 @@ select -assert-count 0 t:DFFRE select -assert-count 2 t:DFFS select -assert-count 2 t:DFFSE select -assert-count 12 t:LUT2 - -# Remove all whiteboxes so we don't inadvertently -# count init attributes inside them -# Should be superseded by https://github.com/YosysHQ/yosys/pull/1949 -delete A:whitebox=1 - -# check the expected leftover init values -# this would happen if your reset value is not the initial value -# which would be weird -select -assert-count 8 a:init From d5e5d9652738a7d3a4e46a9a6825704957b42919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Fri, 3 Jul 2020 00:23:32 +0200 Subject: [PATCH 052/287] efinix: Use dfflegalize. --- techlibs/efinix/cells_map.v | 66 ++++++++++++++++++++++++++------- techlibs/efinix/synth_efinix.cc | 2 +- 2 files changed, 53 insertions(+), 15 deletions(-) diff --git a/techlibs/efinix/cells_map.v b/techlibs/efinix/cells_map.v index 1090f8b279d..3091ad1964e 100644 --- a/techlibs/efinix/cells_map.v +++ b/techlibs/efinix/cells_map.v @@ -1,21 +1,59 @@ -module \$_DFF_N_ (input D, C, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(1'b0), .Q(Q)); endmodule -module \$_DFF_P_ (input D, C, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(1'b0), .Q(Q)); endmodule +(* techmap_celltype = "$_DFFE_PP0P_ $_DFFE_PP0N_ $_DFFE_PP1P_ $_DFFE_PP1N_ $_DFFE_PN0P_ $_DFFE_PN0N_ $_DFFE_PN1P_ $_DFFE_PN1N_ $_DFFE_NP0P_ $_DFFE_NP0N_ $_DFFE_NP1P_ $_DFFE_NP1N_ $_DFFE_NN0P_ $_DFFE_NN0N_ $_DFFE_NN1P_ $_DFFE_NN1N_" *) +module \$_DFFE_xxxx_ (input D, C, R, E, output Q); -module \$_DFFE_NN_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b0), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule -module \$_DFFE_NP_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule + parameter _TECHMAP_CELLTYPE_ = ""; -module \$_DFFE_PN_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b0), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule -module \$_DFFE_PP_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule + EFX_FF #( + .CLK_POLARITY(_TECHMAP_CELLTYPE_[39:32] == "P"), + .CE_POLARITY(_TECHMAP_CELLTYPE_[15:8] == "P"), + .SR_POLARITY(_TECHMAP_CELLTYPE_[31:24] == "P"), + .D_POLARITY(1'b1), + .SR_SYNC(1'b0), + .SR_VALUE(_TECHMAP_CELLTYPE_[23:16] == "1"), + .SR_SYNC_PRIORITY(1'b1) + ) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(R), .Q(Q)); -module \$_DFF_NN0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule -module \$_DFF_NN1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule -module \$_DFF_PN0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule -module \$_DFF_PN1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; -module \$_DFF_NP0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule -module \$_DFF_NP1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule -module \$_DFF_PP0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule -module \$_DFF_PP1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule +endmodule + +(* techmap_celltype = "$_SDFFE_PP0P_ $_SDFFE_PP0N_ $_SDFFE_PP1P_ $_SDFFE_PP1N_ $_SDFFE_PN0P_ $_SDFFE_PN0N_ $_SDFFE_PN1P_ $_SDFFE_PN1N_ $_SDFFE_NP0P_ $_SDFFE_NP0N_ $_SDFFE_NP1P_ $_SDFFE_NP1N_ $_SDFFE_NN0P_ $_SDFFE_NN0N_ $_SDFFE_NN1P_ $_SDFFE_NN1N_" *) +module \$_SDFFE_xxxx_ (input D, C, R, E, output Q); + + parameter _TECHMAP_CELLTYPE_ = ""; + + EFX_FF #( + .CLK_POLARITY(_TECHMAP_CELLTYPE_[39:32] == "P"), + .CE_POLARITY(_TECHMAP_CELLTYPE_[15:8] == "P"), + .SR_POLARITY(_TECHMAP_CELLTYPE_[31:24] == "P"), + .D_POLARITY(1'b1), + .SR_SYNC(1'b1), + .SR_VALUE(_TECHMAP_CELLTYPE_[23:16] == "1"), + .SR_SYNC_PRIORITY(1'b1) + ) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(R), .Q(Q)); + + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + +endmodule + +(* techmap_celltype = "$_SDFFCE_PP0P_ $_SDFFCE_PP0N_ $_SDFFCE_PP1P_ $_SDFFCE_PP1N_ $_SDFFCE_PN0P_ $_SDFFCE_PN0N_ $_SDFFCE_PN1P_ $_SDFFCE_PN1N_ $_SDFFCE_NP0P_ $_SDFFCE_NP0N_ $_SDFFCE_NP1P_ $_SDFFCE_NP1N_ $_SDFFCE_NN0P_ $_SDFFCE_NN0N_ $_SDFFCE_NN1P_ $_SDFFCE_NN1N_" *) +module \$_SDFFCE_xxxx_ (input D, C, R, E, output Q); + + parameter _TECHMAP_CELLTYPE_ = ""; + + EFX_FF #( + .CLK_POLARITY(_TECHMAP_CELLTYPE_[39:32] == "P"), + .CE_POLARITY(_TECHMAP_CELLTYPE_[15:8] == "P"), + .SR_POLARITY(_TECHMAP_CELLTYPE_[31:24] == "P"), + .D_POLARITY(1'b1), + .SR_SYNC(1'b1), + .SR_VALUE(_TECHMAP_CELLTYPE_[23:16] == "1"), + .SR_SYNC_PRIORITY(1'b0) + ) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(R), .Q(Q)); + + wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + +endmodule module \$_DLATCH_N_ (E, D, Q); wire [1023:0] _TECHMAP_DO_ = "simplemap; opt"; diff --git a/techlibs/efinix/synth_efinix.cc b/techlibs/efinix/synth_efinix.cc index 6ca44eed140..d994ae524e0 100644 --- a/techlibs/efinix/synth_efinix.cc +++ b/techlibs/efinix/synth_efinix.cc @@ -182,8 +182,8 @@ struct SynthEfinixPass : public ScriptPass if (check_label("map_ffs")) { + run("dfflegalize -cell $_DFFE_????_ 0 -cell $_SDFFE_????_ 0 -cell $_SDFFCE_????_ 0 -cell $_DLATCH_?_ x"); run("techmap -D NO_LUT -map +/efinix/cells_map.v"); - run("dffinit -strinit SET RESET -ff AL_MAP_SEQ q REGSET -noreinit"); run("opt_expr -mux_undef"); run("simplemap"); } From 943147b768bbaa47933f002477790df43ba462c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Tue, 7 Jul 2020 15:00:52 +0200 Subject: [PATCH 053/287] dfflegalize: typo fix --- passes/techmap/dfflegalize.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/dfflegalize.cc b/passes/techmap/dfflegalize.cc index b2fe90702da..eb35d778a59 100644 --- a/passes/techmap/dfflegalize.cc +++ b/passes/techmap/dfflegalize.cc @@ -529,7 +529,7 @@ struct DffLegalizePass : public Pass { } if (supported_dffsr & flip_initmask(initmask)) { flip_dqisr:; - log_warning("Flipping D/Q/init and inseerting set/reset fixup to handle init value on %s.%s [%s]\n", log_id(cell->module->name), log_id(cell->name), log_id(cell->type)); + log_warning("Flipping D/Q/init and inserting set/reset fixup to handle init value on %s.%s [%s]\n", log_id(cell->module->name), log_id(cell->name), log_id(cell->type)); SigSpec new_r; bool neg_r = (ff_neg & NEG_R); bool neg_s = (ff_neg & NEG_S); From e9c2c1b7175604acd4285800c441c4bd1d676f9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Mon, 6 Jul 2020 22:52:05 +0200 Subject: [PATCH 054/287] dfflegalize: Add special support for const-D latches. Those can be created by `opt_dff` when optimizing `$adff` with const clock, or with D == Q. Make dfflegalize do the opposite transform when such dlatches would be otherwise unimplementable. --- passes/techmap/dfflegalize.cc | 18 ++++++++ tests/techmap/dfflegalize_dlatch_const.ys | 53 +++++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 tests/techmap/dfflegalize_dlatch_const.ys diff --git a/passes/techmap/dfflegalize.cc b/passes/techmap/dfflegalize.cc index eb35d778a59..c0f112836ed 100644 --- a/passes/techmap/dfflegalize.cc +++ b/passes/techmap/dfflegalize.cc @@ -659,6 +659,24 @@ flip_dqisr:; // This init value is not supported at all... if (supported_dlatch & flip_initmask(initmask)) goto flip_dqi; + + if ((sig_d == State::S0 && (supported_adff0 & initmask)) || + (sig_d == State::S1 && (supported_adff1 & initmask)) || + (sig_d == State::S0 && (supported_adff1 & flip_initmask(initmask))) || + (sig_d == State::S1 && (supported_adff0 & flip_initmask(initmask))) + ) { + // Special case: const-D dlatch can be converted into adff with const clock. + ff_type = (sig_d == State::S0) ? FF_ADFF0 : FF_ADFF1; + if (ff_neg & NEG_E) { + ff_neg &= ~NEG_E; + ff_neg |= NEG_R; + } + sig_r = sig_e; + sig_d = State::Sx; + sig_c = State::S1; + continue; + } + if (!supported_dlatch) reason = "dlatch are not supported"; else diff --git a/tests/techmap/dfflegalize_dlatch_const.ys b/tests/techmap/dfflegalize_dlatch_const.ys new file mode 100644 index 00000000000..0b5167a0648 --- /dev/null +++ b/tests/techmap/dfflegalize_dlatch_const.ys @@ -0,0 +1,53 @@ +read_verilog -icells < Date: Tue, 7 Jul 2020 14:22:04 +0200 Subject: [PATCH 055/287] clk2fflogic: Consistently treat async control signals as negative hold. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes some dfflegalize equivalence checks, and breaks others — and I strongly suspect the others are due to bad support for multiple async inputs in `proc` (in particular, lack of proper support for dlatchsr and sketchy circuits on dffsr control inputs). --- passes/sat/clk2fflogic.cc | 108 ++++++++++------------ tests/techmap/dfflegalize_adff.ys | 4 +- tests/techmap/dfflegalize_adff_init.ys | 8 +- tests/techmap/dfflegalize_adlatch.ys | 2 +- tests/techmap/dfflegalize_adlatch_init.ys | 4 +- tests/techmap/dfflegalize_dffsr_init.ys | 8 +- tests/techmap/dfflegalize_sr.ys | 12 +-- tests/techmap/dfflegalize_sr_init.ys | 24 ++--- 8 files changed, 82 insertions(+), 88 deletions(-) diff --git a/passes/sat/clk2fflogic.cc b/passes/sat/clk2fflogic.cc index e5c5d0486d6..cc24db6d495 100644 --- a/passes/sat/clk2fflogic.cc +++ b/passes/sat/clk2fflogic.cc @@ -36,6 +36,30 @@ struct Clk2fflogicPass : public Pass { log("multiple clocks.\n"); log("\n"); } + SigSpec wrap_async_control(Module *module, SigSpec sig, bool polarity) { + Wire *past_sig = module->addWire(NEW_ID, GetSize(sig)); + module->addFf(NEW_ID, sig, past_sig); + if (polarity) + sig = module->Or(NEW_ID, sig, past_sig); + else + sig = module->And(NEW_ID, sig, past_sig); + if (polarity) + return sig; + else + return module->Not(NEW_ID, sig); + } + SigSpec wrap_async_control_gate(Module *module, SigSpec sig, bool polarity) { + Wire *past_sig = module->addWire(NEW_ID); + module->addFfGate(NEW_ID, sig, past_sig); + if (polarity) + sig = module->OrGate(NEW_ID, sig, past_sig); + else + sig = module->AndGate(NEW_ID, sig, past_sig); + if (polarity) + return sig; + else + return module->NotGate(NEW_ID, sig); + } void execute(std::vector args, RTLIL::Design *design) override { // bool flag_noinit = false; @@ -153,7 +177,7 @@ struct Clk2fflogicPass : public Pass { cell->setPort(ID::WR_DATA, wr_data_port); } - if (cell->type.in(ID($dlatch), ID($dlatchsr))) + if (cell->type.in(ID($dlatch), ID($adlatch), ID($dlatchsr))) { bool enpol = cell->parameters[ID::EN_POLARITY].as_bool(); @@ -165,32 +189,32 @@ struct Clk2fflogicPass : public Pass { log_id(module), log_id(cell), log_id(cell->type), log_signal(sig_en), log_signal(sig_d), log_signal(sig_q)); + sig_en = wrap_async_control(module, sig_en, enpol); + Wire *past_q = module->addWire(NEW_ID, GetSize(sig_q)); module->addFf(NEW_ID, sig_q, past_q); if (cell->type == ID($dlatch)) { - if (enpol) - module->addMux(NEW_ID, past_q, sig_d, sig_en, sig_q); - else - module->addMux(NEW_ID, sig_d, past_q, sig_en, sig_q); + module->addMux(NEW_ID, past_q, sig_d, sig_en, sig_q); + } + else if (cell->type == ID($adlatch)) + { + SigSpec t = module->Mux(NEW_ID, past_q, sig_d, sig_en); + SigSpec arst = wrap_async_control(module, cell->getPort(ID::ARST), cell->parameters[ID::ARST_POLARITY].as_bool()); + Const rstval = cell->parameters[ID::ARST_VALUE]; + + module->addMux(NEW_ID, t, rstval, arst, sig_q); } else { - SigSpec t; - if (enpol) - t = module->Mux(NEW_ID, past_q, sig_d, sig_en); - else - t = module->Mux(NEW_ID, sig_d, past_q, sig_en); - - SigSpec s = cell->getPort(ID::SET); - if (!cell->parameters[ID::SET_POLARITY].as_bool()) - s = module->Not(NEW_ID, s); + SigSpec t = module->Mux(NEW_ID, past_q, sig_d, sig_en); + + SigSpec s = wrap_async_control(module, cell->getPort(ID::SET), cell->parameters[ID::SET_POLARITY].as_bool()); t = module->Or(NEW_ID, t, s); - SigSpec c = cell->getPort(ID::CLR); - if (cell->parameters[ID::CLR_POLARITY].as_bool()) - c = module->Not(NEW_ID, c); + SigSpec c = wrap_async_control(module, cell->getPort(ID::CLR), cell->parameters[ID::CLR_POLARITY].as_bool()); + c = module->Not(NEW_ID, c); module->addAnd(NEW_ID, t, c, sig_q); } @@ -279,55 +303,30 @@ struct Clk2fflogicPass : public Pass { if (cell->type == ID($adff)) { - SigSpec arst = cell->getPort(ID::ARST); + SigSpec arst = wrap_async_control(module, cell->getPort(ID::ARST), cell->parameters[ID::ARST_POLARITY].as_bool()); SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge); Const rstval = cell->parameters[ID::ARST_VALUE]; - Wire *past_arst = module->addWire(NEW_ID); - module->addFf(NEW_ID, arst, past_arst); - if (cell->parameters[ID::ARST_POLARITY].as_bool()) - arst = module->LogicOr(NEW_ID, arst, past_arst); - else - arst = module->LogicAnd(NEW_ID, arst, past_arst); - - if (cell->parameters[ID::ARST_POLARITY].as_bool()) - module->addMux(NEW_ID, qval, rstval, arst, sig_q); - else - module->addMux(NEW_ID, rstval, qval, arst, sig_q); + module->addMux(NEW_ID, qval, rstval, arst, sig_q); } else if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), ID($_DFF_PP0_), ID($_DFF_PP1_), ID($_DFF_PN0_), ID($_DFF_PN1_))) { - SigSpec arst = cell->getPort(ID::R); + SigSpec arst = wrap_async_control_gate(module, cell->getPort(ID::R), cell->type[7] == 'P'); SigSpec qval = module->MuxGate(NEW_ID, past_q, past_d, clock_edge); SigBit rstval = (cell->type[8] == '1'); - Wire *past_arst = module->addWire(NEW_ID); - module->addFfGate(NEW_ID, arst, past_arst); - if (cell->type[7] == 'P') - arst = module->OrGate(NEW_ID, arst, past_arst); - else - arst = module->AndGate(NEW_ID, arst, past_arst); - - if (cell->type[7] == 'P') - module->addMuxGate(NEW_ID, qval, rstval, arst, sig_q); - else - module->addMuxGate(NEW_ID, rstval, qval, arst, sig_q); + module->addMuxGate(NEW_ID, qval, rstval, arst, sig_q); } else if (cell->type == ID($dffsr)) { SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge); - SigSpec setval = cell->getPort(ID::SET); - SigSpec clrval = cell->getPort(ID::CLR); - - if (!cell->parameters[ID::SET_POLARITY].as_bool()) - setval = module->Not(NEW_ID, setval); - - if (cell->parameters[ID::CLR_POLARITY].as_bool()) - clrval = module->Not(NEW_ID, clrval); + SigSpec setval = wrap_async_control(module, cell->getPort(ID::SET), cell->parameters[ID::SET_POLARITY].as_bool()); + SigSpec clrval = wrap_async_control(module, cell->getPort(ID::CLR), cell->parameters[ID::CLR_POLARITY].as_bool()); + clrval = module->Not(NEW_ID, clrval); qval = module->Or(NEW_ID, qval, setval); module->addAnd(NEW_ID, qval, clrval, sig_q); } @@ -336,15 +335,10 @@ struct Clk2fflogicPass : public Pass { ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_))) { SigSpec qval = module->MuxGate(NEW_ID, past_q, past_d, clock_edge); - SigSpec setval = cell->getPort(ID::S); - SigSpec clrval = cell->getPort(ID::R); - - if (cell->type[9] != 'P') - setval = module->Not(NEW_ID, setval); - - if (cell->type[10] == 'P') - clrval = module->Not(NEW_ID, clrval); + SigSpec setval = wrap_async_control_gate(module, cell->getPort(ID::S), cell->type[9] == 'P'); + SigSpec clrval = wrap_async_control_gate(module, cell->getPort(ID::R), cell->type[10] == 'P'); + clrval = module->NotGate(NEW_ID, clrval); qval = module->OrGate(NEW_ID, qval, setval); module->addAndGate(NEW_ID, qval, clrval, sig_q); } diff --git a/tests/techmap/dfflegalize_adff.ys b/tests/techmap/dfflegalize_adff.ys index a563e8c611f..cf3e925a348 100644 --- a/tests/techmap/dfflegalize_adff.ys +++ b/tests/techmap/dfflegalize_adff.ys @@ -39,8 +39,8 @@ design -save orig flatten equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFF_PP0_ x equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFE_PP0P_ x -#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ x -#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ x +equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ x +equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ x # Convert everything to ADFFs. diff --git a/tests/techmap/dfflegalize_adff_init.ys b/tests/techmap/dfflegalize_adff_init.ys index 92f249815e5..a101617014e 100644 --- a/tests/techmap/dfflegalize_adff_init.ys +++ b/tests/techmap/dfflegalize_adff_init.ys @@ -45,10 +45,10 @@ equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFE_PP0P_ 0 equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFE_PP0P_ 1 -cell $_DLATCH_P_ 1 equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFE_PP1P_ 0 -cell $_DLATCH_P_ 1 equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFE_PP1P_ 1 -cell $_DLATCH_P_ 1 -#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 0 -#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 1 -#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 0 -#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 1 +equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 0 +equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 1 +equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 0 +equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 1 # Convert everything to ADFFs. diff --git a/tests/techmap/dfflegalize_adlatch.ys b/tests/techmap/dfflegalize_adlatch.ys index dee17e40c73..ea5aaa53c5d 100644 --- a/tests/techmap/dfflegalize_adlatch.ys +++ b/tests/techmap/dfflegalize_adlatch.ys @@ -22,7 +22,7 @@ EOT design -save orig flatten equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP0_ x -#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ x +equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ x # Convert everything to ADLATCHs. diff --git a/tests/techmap/dfflegalize_adlatch_init.ys b/tests/techmap/dfflegalize_adlatch_init.ys index c221bbe0e18..0a31d773644 100644 --- a/tests/techmap/dfflegalize_adlatch_init.ys +++ b/tests/techmap/dfflegalize_adlatch_init.ys @@ -25,8 +25,8 @@ equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP0_ equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP0_ 1 equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP1_ 0 equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP1_ 1 -#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ 0 -#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ 1 +equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ 0 +equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ 1 # Convert everything to ADLATCHs. diff --git a/tests/techmap/dfflegalize_dffsr_init.ys b/tests/techmap/dfflegalize_dffsr_init.ys index 646c086e0bf..a98bd0cfe59 100644 --- a/tests/techmap/dfflegalize_dffsr_init.ys +++ b/tests/techmap/dfflegalize_dffsr_init.ys @@ -49,10 +49,10 @@ flatten #equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFE_PP0P_ 1 -cell $_SR_PP_ 0 #equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFE_PP1P_ 0 -cell $_SR_PP_ 0 #equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFE_PP1P_ 1 -cell $_SR_PP_ 0 -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 0 -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 1 -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 0 -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 1 +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 0 +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 1 +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 0 +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 1 # Convert everything to ADFFs. diff --git a/tests/techmap/dfflegalize_sr.ys b/tests/techmap/dfflegalize_sr.ys index a75068ae064..b8c91f7538d 100644 --- a/tests/techmap/dfflegalize_sr.ys +++ b/tests/techmap/dfflegalize_sr.ys @@ -9,12 +9,12 @@ endmodule EOT design -save orig -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_SR_PP_ x -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP0_ x -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP1_ x -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ x -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ x -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ x +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_SR_PP_ x +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP0_ x +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP1_ x +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ x +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ x +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ x # Convert everything to SRs. diff --git a/tests/techmap/dfflegalize_sr_init.ys b/tests/techmap/dfflegalize_sr_init.ys index 39bfdcdcff5..5c52a0b28e2 100644 --- a/tests/techmap/dfflegalize_sr_init.ys +++ b/tests/techmap/dfflegalize_sr_init.ys @@ -21,18 +21,18 @@ EOT design -save orig flatten -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_SR_PP_ 0 -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_SR_PP_ 1 -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP0_ 0 -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP0_ 1 -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP1_ 0 -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP1_ 1 -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ 0 -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ 1 -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 0 -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 1 -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 0 -equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 1 +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_SR_PP_ 0 +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_SR_PP_ 1 +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP0_ 0 +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP0_ 1 +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP1_ 0 +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCH_PP1_ 1 +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ 0 +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DLATCHSR_PPP_ 1 +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 0 +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSR_PPP_ 1 +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 0 +#equiv_opt -assert -multiclock -map +/simcells.v dfflegalize -cell $_DFFSRE_PPPP_ 1 # Convert everything to SRs. From 32d2cc8c285682c3d9613ea0f116679c816b7ac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Sat, 4 Jul 2020 23:09:00 +0200 Subject: [PATCH 056/287] clkbufmap: improve input pad handling. - allow inserting only the input pad cell - do not insert the usual buffer if the input pad already acts as a buffer --- passes/techmap/clkbufmap.cc | 56 ++++++++++++++++++-------- tests/techmap/clkbufmap.ys | 79 +++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 17 deletions(-) diff --git a/passes/techmap/clkbufmap.cc b/passes/techmap/clkbufmap.cc index 4e9b910db46..1cbd12e3d2c 100644 --- a/passes/techmap/clkbufmap.cc +++ b/passes/techmap/clkbufmap.cc @@ -34,33 +34,34 @@ void split_portname_pair(std::string &port1, std::string &port2) } struct ClkbufmapPass : public Pass { - ClkbufmapPass() : Pass("clkbufmap", "insert global buffers on clock networks") { } + ClkbufmapPass() : Pass("clkbufmap", "insert clock buffers on clock networks") { } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" clkbufmap [options] [selection]\n"); log("\n"); - log("Inserts global buffers between nets connected to clock inputs and their drivers.\n"); + log("Inserts clock buffers between nets connected to clock inputs and their drivers.\n"); log("\n"); log("In the absence of any selection, all wires without the 'clkbuf_inhibit'\n"); - log("attribute will be considered for global buffer insertion.\n"); + log("attribute will be considered for clock buffer insertion.\n"); log("Alternatively, to consider all wires without the 'buffer_type' attribute set to\n"); log("'none' or 'bufr' one would specify:\n"); log(" 'w:* a:buffer_type=none a:buffer_type=bufr %%u %%d'\n"); log("as the selection.\n"); log("\n"); log(" -buf :\n"); - log(" Specifies the cell type to use for the global buffers\n"); + log(" Specifies the cell type to use for the clock buffers\n"); log(" and its port names. The first port will be connected to\n"); log(" the clock network sinks, and the second will be connected\n"); - log(" to the actual clock source. This option is required.\n"); + log(" to the actual clock source.\n"); log("\n"); log(" -inpad :\n"); log(" If specified, a PAD cell of the given type is inserted on\n"); log(" clock nets that are also top module's inputs (in addition\n"); - log(" to the global buffer).\n"); + log(" to the clock buffer, if any).\n"); log("\n"); + log("At least one of -buf or -inpad should be specified.\n"); } void module_queue(Design *design, Module *module, std::vector &modules_sorted, pool &modules_processed) { @@ -78,7 +79,7 @@ struct ClkbufmapPass : public Pass { void execute(std::vector args, RTLIL::Design *design) override { - log_header(design, "Executing CLKBUFMAP pass (inserting global clock buffers).\n"); + log_header(design, "Executing CLKBUFMAP pass (inserting clock buffers).\n"); std::string buf_celltype, buf_portname, buf_portname2; std::string inpad_celltype, inpad_portname, inpad_portname2; @@ -109,8 +110,8 @@ struct ClkbufmapPass : public Pass { extra_args(args, argidx, design); } - if (buf_celltype.empty()) - log_error("The -buf option is required.\n"); + if (buf_celltype.empty() && inpad_celltype.empty()) + log_error("Either the -buf option or -inpad option is required.\n"); // Cell type, port name, bit index. pool>> sink_ports; @@ -118,6 +119,16 @@ struct ClkbufmapPass : public Pass { dict>, pair> inv_ports_out; dict>, pair> inv_ports_in; + // If true, use both ther -buf and -inpad cell for input ports that are clocks. + bool buffer_inputs = true; + + Module *inpad_mod = design->module(RTLIL::escape_id(inpad_celltype)); + if (inpad_mod) { + Wire *buf_wire = inpad_mod->wire(RTLIL::escape_id(buf_portname)); + if (buf_wire && buf_wire->get_bool_attribute(ID::clkbuf_driver)) + buffer_inputs = false; + } + // Process submodules before module using them. std::vector modules_sorted; pool modules_processed; @@ -242,19 +253,30 @@ struct ClkbufmapPass : public Pass { // Clock network not yet buffered, driven by one of // our cells or a top-level input -- buffer it. - log("Inserting %s on %s.%s[%d].\n", buf_celltype.c_str(), log_id(module), log_id(wire), i); - RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(buf_celltype)); - Wire *iwire = module->addWire(NEW_ID); - cell->setPort(RTLIL::escape_id(buf_portname), mapped_wire_bit); - cell->setPort(RTLIL::escape_id(buf_portname2), iwire); - if (wire->port_input && !inpad_celltype.empty() && module->get_bool_attribute(ID::top)) { + Wire *iwire = nullptr; + RTLIL::Cell *cell = nullptr; + bool is_input = wire->port_input && !inpad_celltype.empty() && module->get_bool_attribute(ID::top); + if (!buf_celltype.empty() && (!is_input || buffer_inputs)) { + log("Inserting %s on %s.%s[%d].\n", buf_celltype.c_str(), log_id(module), log_id(wire), i); + cell = module->addCell(NEW_ID, RTLIL::escape_id(buf_celltype)); + iwire = module->addWire(NEW_ID); + cell->setPort(RTLIL::escape_id(buf_portname), mapped_wire_bit); + cell->setPort(RTLIL::escape_id(buf_portname2), iwire); + } + if (is_input) { log("Inserting %s on %s.%s[%d].\n", inpad_celltype.c_str(), log_id(module), log_id(wire), i); RTLIL::Cell *cell2 = module->addCell(NEW_ID, RTLIL::escape_id(inpad_celltype)); - cell2->setPort(RTLIL::escape_id(inpad_portname), iwire); + if (iwire) { + cell2->setPort(RTLIL::escape_id(inpad_portname), iwire); + } else { + cell2->setPort(RTLIL::escape_id(inpad_portname), mapped_wire_bit); + cell = cell2; + } iwire = module->addWire(NEW_ID); cell2->setPort(RTLIL::escape_id(inpad_portname2), iwire); } - buffered_bits[mapped_wire_bit] = make_pair(cell, iwire); + if (iwire) + buffered_bits[mapped_wire_bit] = make_pair(cell, iwire); if (wire->port_input) { input_bits.insert(i); diff --git a/tests/techmap/clkbufmap.ys b/tests/techmap/clkbufmap.ys index b81a35e7488..abe830109ae 100644 --- a/tests/techmap/clkbufmap.ys +++ b/tests/techmap/clkbufmap.ys @@ -1,5 +1,7 @@ read_verilog < Date: Thu, 9 Jul 2020 13:50:26 -0300 Subject: [PATCH 057/287] Fix issue #2251 (#2252) * Fix #2251 - YosysJS ReferenceError: _memset is not defined. Add '_memset' in emcc EXPORTED_FUNCTIONS in Makefile. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b9c3d14eb1e..ec8b38c480c 100644 --- a/Makefile +++ b/Makefile @@ -247,7 +247,7 @@ CXXFLAGS := -std=c++11 $(filter-out -fPIC -ggdb,$(CXXFLAGS)) ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DABC_MEMALIGN=8" EMCCFLAGS := -Os -Wno-warn-absolute-paths EMCCFLAGS += --memory-init-file 0 --embed-file share -s NO_EXIT_RUNTIME=1 -EMCCFLAGS += -s EXPORTED_FUNCTIONS="['_main','_run','_prompt','_errmsg']" +EMCCFLAGS += -s EXPORTED_FUNCTIONS="['_main','_run','_prompt','_errmsg','_memset']" EMCCFLAGS += -s TOTAL_MEMORY=134217728 EMCCFLAGS += -s EXTRA_EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]' # https://github.com/kripken/emscripten/blob/master/src/settings.js From 7ed9d189079135ef53e8a19a5e3a38e240994103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Thu, 2 Jul 2020 18:22:43 +0200 Subject: [PATCH 058/287] dfflibmap: Refactor to use dfflegalize internally. --- passes/techmap/dfflibmap.cc | 289 +++++++++------------------------- tests/liberty/run-test.sh | 2 +- tests/techmap/dfflibmap-sim.v | 22 +++ tests/techmap/dfflibmap.lib | 55 +++++++ tests/techmap/dfflibmap.ys | 58 +++++++ 5 files changed, 214 insertions(+), 212 deletions(-) create mode 100644 tests/techmap/dfflibmap-sim.v create mode 100644 tests/techmap/dfflibmap.lib create mode 100644 tests/techmap/dfflibmap.ys diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc index c189d649b68..78a6f1c0d57 100644 --- a/passes/techmap/dfflibmap.cc +++ b/passes/techmap/dfflibmap.cc @@ -115,7 +115,7 @@ static bool parse_pin(LibertyAst *cell, LibertyAst *attr, std::string &pin_name, return false; } -static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval, bool prepare_mode) +static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval) { LibertyAst *best_cell = nullptr; std::map best_cell_ports; @@ -222,21 +222,12 @@ static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has if (best_cell != nullptr) { log(" cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str()); - if (prepare_mode) { - cell_mappings[cell_type].cell_name = cell_type; - cell_mappings[cell_type].ports["C"] = 'C'; - if (has_reset) - cell_mappings[cell_type].ports["R"] = 'R'; - cell_mappings[cell_type].ports["D"] = 'D'; - cell_mappings[cell_type].ports["Q"] = 'Q'; - } else { - cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]); - cell_mappings[cell_type].ports = best_cell_ports; - } + cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]); + cell_mappings[cell_type].ports = best_cell_ports; } } -static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool setpol, bool clrpol, bool prepare_mode) +static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool setpol, bool clrpol) { LibertyAst *best_cell = nullptr; std::map best_cell_ports; @@ -339,141 +330,12 @@ static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool if (best_cell != nullptr) { log(" cell %s (%sinv, pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_noninv ? "non" : "", best_cell_pins, best_cell_area, cell_type.c_str()); - if (prepare_mode) { - cell_mappings[cell_type].cell_name = cell_type; - cell_mappings[cell_type].ports["C"] = 'C'; - cell_mappings[cell_type].ports["S"] = 'S'; - cell_mappings[cell_type].ports["R"] = 'R'; - cell_mappings[cell_type].ports["D"] = 'D'; - cell_mappings[cell_type].ports["Q"] = 'Q'; - } else { - cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]); - cell_mappings[cell_type].ports = best_cell_ports; - } + cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]); + cell_mappings[cell_type].ports = best_cell_ports; } } -static bool expand_cellmap_worker(std::string from, std::string to, std::string inv) -{ - if (cell_mappings.count(to) > 0) - return false; - - log(" create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str()); - cell_mappings[to].cell_name = cell_mappings[from].cell_name; - cell_mappings[to].ports = cell_mappings[from].ports; - - for (auto &it : cell_mappings[to].ports) { - char cmp_ch = it.second; - if ('a' <= cmp_ch && cmp_ch <= 'z') - cmp_ch -= 'a' - 'A'; - if (inv.find(cmp_ch) == std::string::npos) - continue; - if ('a' <= it.second && it.second <= 'z') - it.second -= 'a' - 'A'; - else if ('A' <= it.second && it.second <= 'Z') - it.second += 'a' - 'A'; - } - return true; -} - -static bool expand_cellmap(std::string pattern, std::string inv) -{ - std::vector> from_to_list; - bool return_status = false; - - for (auto &it : cell_mappings) { - std::string from = it.first.str(), to = it.first.str(); - if (from.size() != pattern.size()) - continue; - for (size_t i = 0; i < from.size(); i++) { - if (pattern[i] == '*') { - to[i] = from[i] == 'P' ? 'N' : - from[i] == 'N' ? 'P' : - from[i] == '1' ? '0' : - from[i] == '0' ? '1' : '*'; - } else - if (pattern[i] != '?' && pattern[i] != from[i]) - goto pattern_failed; - } - from_to_list.push_back(std::pair(from, to)); - pattern_failed:; - } - - for (auto &it : from_to_list) - return_status = return_status || expand_cellmap_worker(it.first, it.second, inv); - return return_status; -} - -static void map_sr_to_arst(IdString from, IdString to) -{ - if (!cell_mappings.count(from) || cell_mappings.count(to) > 0) - return; - - char from_clk_pol = from[8]; - char from_set_pol = from[9]; - char from_clr_pol = from[10]; - char to_clk_pol = to[6]; - char to_rst_pol = to[7]; - char to_rst_val = to[8]; - - log_assert(from_clk_pol == to_clk_pol); - log_assert(to_rst_pol == from_set_pol && to_rst_pol == from_clr_pol); - - log(" create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str()); - cell_mappings[to].cell_name = cell_mappings[from].cell_name; - cell_mappings[to].ports = cell_mappings[from].ports; - - for (auto &it : cell_mappings[to].ports) - { - bool is_set_pin = it.second == 'S' || it.second == 's'; - bool is_clr_pin = it.second == 'R' || it.second == 'r'; - - if (!is_set_pin && !is_clr_pin) - continue; - - if ((to_rst_val == '0' && is_set_pin) || (to_rst_val == '1' && is_clr_pin)) - { - // this is the unused set/clr pin -- deactivate it - if (is_set_pin) - it.second = (from_set_pol == 'P') == (it.second == 'S') ? '0' : '1'; - else - it.second = (from_clr_pol == 'P') == (it.second == 'R') ? '0' : '1'; - } - else - { - // this is the used set/clr pin -- rename it to 'reset' - if (it.second == 'S') - it.second = 'R'; - if (it.second == 's') - it.second = 'r'; - } - } -} - -static void map_adff_to_dff(IdString from, IdString to) -{ - if (!cell_mappings.count(from) || cell_mappings.count(to) > 0) - return; - - char from_clk_pol = from[6]; - char from_rst_pol = from[7]; - char to_clk_pol = to[6]; - - log_assert(from_clk_pol == to_clk_pol); - - log(" create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str()); - cell_mappings[to].cell_name = cell_mappings[from].cell_name; - cell_mappings[to].ports = cell_mappings[from].ports; - - for (auto &it : cell_mappings[to].ports) { - if (it.second == 'S' || it.second == 'R') - it.second = from_rst_pol == 'P' ? '0' : '1'; - if (it.second == 's' || it.second == 'r') - it.second = from_rst_pol == 'P' ? '1' : '0'; - } -} - -static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare_mode) +static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module) { log("Mapping DFF cells in module `%s':\n", module->name.c_str()); @@ -499,7 +361,7 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare module->remove(cell); cell_mapping &cm = cell_mappings[cell_type]; - RTLIL::Cell *new_cell = module->addCell(cell_name, prepare_mode ? cm.cell_name : cm.cell_name); + RTLIL::Cell *new_cell = module->addCell(cell_name, cm.cell_name); new_cell->set_src_attribute(src); @@ -552,7 +414,7 @@ struct DfflibmapPass : public Pass { void help() override { log("\n"); - log(" dfflibmap [-prepare] -liberty [selection]\n"); + log(" dfflibmap [-prepare] [-map-only] [-info] -liberty [selection]\n"); log("\n"); log("Map internal flip-flop cells to the flip-flop cells in the technology\n"); log("library specified in the given liberty file.\n"); @@ -562,15 +424,27 @@ struct DfflibmapPass : public Pass { log("\n"); log("When called with -prepare, this command will convert the internal FF cells\n"); log("to the internal cell types that best match the cells found in the given\n"); - log("liberty file.\n"); + log("liberty file, but won't actually map them to the target cells.\n"); + log("\n"); + log("When called with -map-only, this command will only map internal cell\n"); + log("types that are already of exactly the right type to match the target\n"); + log("cells, leaving remaining internal cells untouched.\n"); + log("\n"); + log("When called with -info, this command will only print the target cell\n"); + log("list, along with their associated internal cell types, and the arguments"); + log("that would be passed to the dfflegalize pass. The design will not be\n"); + log("changed.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { log_header(design, "Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n"); + log_push(); std::string liberty_file; bool prepare_mode = false; + bool map_only_mode = false; + bool info_mode = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -585,10 +459,28 @@ struct DfflibmapPass : public Pass { prepare_mode = true; continue; } + if (arg == "-map-only") { + map_only_mode = true; + continue; + } + if (arg == "-info") { + info_mode = true; + continue; + } break; } extra_args(args, argidx, design); + int modes = 0; + if (prepare_mode) + modes++; + if (map_only_mode) + modes++; + if (info_mode) + modes++; + if (modes > 1) + log_cmd_error("Only one of -prepare, -map-only, or -info options should be given!\n"); + if (liberty_file.empty()) log_cmd_error("Missing `-liberty liberty_file' option!\n"); @@ -599,74 +491,49 @@ struct DfflibmapPass : public Pass { LibertyParser libparser(f); f.close(); - find_cell(libparser.ast, ID($_DFF_N_), false, false, false, false, prepare_mode); - find_cell(libparser.ast, ID($_DFF_P_), true, false, false, false, prepare_mode); - - find_cell(libparser.ast, ID($_DFF_NN0_), false, true, false, false, prepare_mode); - find_cell(libparser.ast, ID($_DFF_NN1_), false, true, false, true, prepare_mode); - find_cell(libparser.ast, ID($_DFF_NP0_), false, true, true, false, prepare_mode); - find_cell(libparser.ast, ID($_DFF_NP1_), false, true, true, true, prepare_mode); - find_cell(libparser.ast, ID($_DFF_PN0_), true, true, false, false, prepare_mode); - find_cell(libparser.ast, ID($_DFF_PN1_), true, true, false, true, prepare_mode); - find_cell(libparser.ast, ID($_DFF_PP0_), true, true, true, false, prepare_mode); - find_cell(libparser.ast, ID($_DFF_PP1_), true, true, true, true, prepare_mode); - - find_cell_sr(libparser.ast, ID($_DFFSR_NNN_), false, false, false, prepare_mode); - find_cell_sr(libparser.ast, ID($_DFFSR_NNP_), false, false, true, prepare_mode); - find_cell_sr(libparser.ast, ID($_DFFSR_NPN_), false, true, false, prepare_mode); - find_cell_sr(libparser.ast, ID($_DFFSR_NPP_), false, true, true, prepare_mode); - find_cell_sr(libparser.ast, ID($_DFFSR_PNN_), true, false, false, prepare_mode); - find_cell_sr(libparser.ast, ID($_DFFSR_PNP_), true, false, true, prepare_mode); - find_cell_sr(libparser.ast, ID($_DFFSR_PPN_), true, true, false, prepare_mode); - find_cell_sr(libparser.ast, ID($_DFFSR_PPP_), true, true, true, prepare_mode); - - // try to implement as many cells as possible just by inverting - // the SET and RESET pins. If necessary, implement cell types - // by inverting both D and Q. Only invert clock pins if there - // is no other way of implementing the cell. - while (1) - { - if (expand_cellmap("$_DFF_?*?_", "R") || - expand_cellmap("$_DFFSR_?*?_", "S") || - expand_cellmap("$_DFFSR_??*_", "R")) - continue; - - if (expand_cellmap("$_DFF_??*_", "DQ")) - continue; - - if (expand_cellmap("$_DFF_*_", "C") || - expand_cellmap("$_DFF_*??_", "C") || - expand_cellmap("$_DFFSR_*??_", "C")) - continue; - - break; - } - - map_sr_to_arst(ID($_DFFSR_NNN_), ID($_DFF_NN0_)); - map_sr_to_arst(ID($_DFFSR_NNN_), ID($_DFF_NN1_)); - map_sr_to_arst(ID($_DFFSR_NPP_), ID($_DFF_NP0_)); - map_sr_to_arst(ID($_DFFSR_NPP_), ID($_DFF_NP1_)); - map_sr_to_arst(ID($_DFFSR_PNN_), ID($_DFF_PN0_)); - map_sr_to_arst(ID($_DFFSR_PNN_), ID($_DFF_PN1_)); - map_sr_to_arst(ID($_DFFSR_PPP_), ID($_DFF_PP0_)); - map_sr_to_arst(ID($_DFFSR_PPP_), ID($_DFF_PP1_)); - - map_adff_to_dff(ID($_DFF_NN0_), ID($_DFF_N_)); - map_adff_to_dff(ID($_DFF_NN1_), ID($_DFF_N_)); - map_adff_to_dff(ID($_DFF_NP0_), ID($_DFF_N_)); - map_adff_to_dff(ID($_DFF_NP1_), ID($_DFF_N_)); - map_adff_to_dff(ID($_DFF_PN0_), ID($_DFF_P_)); - map_adff_to_dff(ID($_DFF_PN1_), ID($_DFF_P_)); - map_adff_to_dff(ID($_DFF_PP0_), ID($_DFF_P_)); - map_adff_to_dff(ID($_DFF_PP1_), ID($_DFF_P_)); + find_cell(libparser.ast, ID($_DFF_N_), false, false, false, false); + find_cell(libparser.ast, ID($_DFF_P_), true, false, false, false); + + find_cell(libparser.ast, ID($_DFF_NN0_), false, true, false, false); + find_cell(libparser.ast, ID($_DFF_NN1_), false, true, false, true); + find_cell(libparser.ast, ID($_DFF_NP0_), false, true, true, false); + find_cell(libparser.ast, ID($_DFF_NP1_), false, true, true, true); + find_cell(libparser.ast, ID($_DFF_PN0_), true, true, false, false); + find_cell(libparser.ast, ID($_DFF_PN1_), true, true, false, true); + find_cell(libparser.ast, ID($_DFF_PP0_), true, true, true, false); + find_cell(libparser.ast, ID($_DFF_PP1_), true, true, true, true); + + find_cell_sr(libparser.ast, ID($_DFFSR_NNN_), false, false, false); + find_cell_sr(libparser.ast, ID($_DFFSR_NNP_), false, false, true); + find_cell_sr(libparser.ast, ID($_DFFSR_NPN_), false, true, false); + find_cell_sr(libparser.ast, ID($_DFFSR_NPP_), false, true, true); + find_cell_sr(libparser.ast, ID($_DFFSR_PNN_), true, false, false); + find_cell_sr(libparser.ast, ID($_DFFSR_PNP_), true, false, true); + find_cell_sr(libparser.ast, ID($_DFFSR_PPN_), true, true, false); + find_cell_sr(libparser.ast, ID($_DFFSR_PPP_), true, true, true); log(" final dff cell mappings:\n"); logmap_all(); - for (auto module : design->selected_modules()) - if (!module->get_blackbox_attribute()) - dfflibmap(design, module, prepare_mode); + if (!map_only_mode) { + std::string dfflegalize_cmd = "dfflegalize"; + for (auto it : cell_mappings) + dfflegalize_cmd += stringf(" -cell %s 01", it.first.c_str()); + dfflegalize_cmd += " t:$_DFF* t:$_SDFF*"; + if (info_mode) { + log("dfflegalize command line: %s\n", dfflegalize_cmd.c_str()); + } else { + Pass::call(design, dfflegalize_cmd); + } + } + + if (!prepare_mode && !info_mode) { + for (auto module : design->selected_modules()) + if (!module->get_blackbox_attribute()) + dfflibmap(design, module); + } + log_pop(); cell_mappings.clear(); } } DfflibmapPass; diff --git a/tests/liberty/run-test.sh b/tests/liberty/run-test.sh index 7e2ed2370a8..61f19b09bc7 100755 --- a/tests/liberty/run-test.sh +++ b/tests/liberty/run-test.sh @@ -5,6 +5,6 @@ for x in *.lib; do echo "Running $x.." echo "read_verilog small.v" > test.ys echo "synth -top small" >> test.ys - echo "dfflibmap -liberty ${x}" >> test.ys + echo "dfflibmap -info -liberty ${x}" >> test.ys ../../yosys -ql ${x%.lib}.log -s test.ys done diff --git a/tests/techmap/dfflibmap-sim.v b/tests/techmap/dfflibmap-sim.v new file mode 100644 index 00000000000..1788a683bb5 --- /dev/null +++ b/tests/techmap/dfflibmap-sim.v @@ -0,0 +1,22 @@ +module dffn(input CLK, D, output reg Q, output QN); + +always @(negedge CLK) + Q <= D; + +assign QN = ~Q; + +endmodule + +module dffsr(input CLK, D, CLEAR, PRESET, output reg Q, output QN); + +always @(posedge CLK, posedge CLEAR, posedge PRESET) + if (CLEAR) + Q <= 0; + else if (PRESET) + Q <= 1; + else + Q <= D; + +assign QN = ~Q; + +endmodule diff --git a/tests/techmap/dfflibmap.lib b/tests/techmap/dfflibmap.lib new file mode 100644 index 00000000000..ce460877e61 --- /dev/null +++ b/tests/techmap/dfflibmap.lib @@ -0,0 +1,55 @@ +library(test) { + /* D-type flip-flop with asynchronous reset and preset */ + cell (dffn) { + area : 6; + ff("IQ", "IQN") { + next_state : "D"; + clocked_on : "!CLK"; + } + pin(D) { + direction : input; + } + pin(CLK) { + direction : input; + } + pin(Q) { + direction: output; + function : "IQ"; + } + pin(QN) { + direction: output; + function : "IQN"; + } + } + cell (dffsr) { + area : 6; + ff("IQ", "IQN") { + next_state : "D"; + clocked_on : "CLK"; + clear : "CLEAR"; + preset : "PRESET"; + clear_preset_var1 : L; + clear_preset_var2 : L; + } + pin(D) { + direction : input; + } + pin(CLK) { + direction : input; + } + pin(CLEAR) { + direction : input; + } + pin(PRESET) { + direction : input; + } + pin(Q) { + direction: output; + function : "IQ"; + } + pin(QN) { + direction: output; + function : "IQN"; + } + } +} diff --git a/tests/techmap/dfflibmap.ys b/tests/techmap/dfflibmap.ys new file mode 100644 index 00000000000..04477eb1483 --- /dev/null +++ b/tests/techmap/dfflibmap.ys @@ -0,0 +1,58 @@ +read_verilog -icells < Date: Tue, 23 Jun 2020 18:51:51 +0200 Subject: [PATCH 059/287] xilinx: Use dfflegalize. --- techlibs/xilinx/Makefile.inc | 3 +- techlibs/xilinx/cells_map.v | 37 ----- techlibs/xilinx/ff_map.v | 120 +++++++++++++++ techlibs/xilinx/synth_xilinx.cc | 21 ++- techlibs/xilinx/xc6s_ff_map.v | 256 -------------------------------- techlibs/xilinx/xc7_ff_map.v | 178 ---------------------- 6 files changed, 131 insertions(+), 484 deletions(-) create mode 100644 techlibs/xilinx/ff_map.v delete mode 100644 techlibs/xilinx/xc6s_ff_map.v delete mode 100644 techlibs/xilinx/xc7_ff_map.v diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc index d4d8638317a..ba87278de12 100644 --- a/techlibs/xilinx/Makefile.inc +++ b/techlibs/xilinx/Makefile.inc @@ -42,8 +42,7 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut4_lutrams.txt)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut6_lutrams.txt)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v)) -$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_ff_map.v)) -$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_ff_map.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/mux_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc3s_mult_map.v)) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 97f050f7680..ec4635ac69c 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -18,43 +18,6 @@ * */ -// Convert negative-polarity reset to positive-polarity -(* techmap_celltype = "$_DFF_NN0_" *) -module _90_dff_nn0_to_np0 (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule -(* techmap_celltype = "$_DFF_PN0_" *) -module _90_dff_pn0_to_pp0 (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule -(* techmap_celltype = "$_DFF_NN1_" *) -module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule -(* techmap_celltype = "$_DFF_PN1_" *) -module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule - -(* techmap_celltype = "$_DFFE_NN0P_" *) -module _90_dffe_nn0_to_np0 (input D, C, R, E, output Q); \$_DFFE_NP0P_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule -(* techmap_celltype = "$_DFFE_PN0P_" *) -module _90_dffe_pn0_to_pp0 (input D, C, R, E, output Q); \$_DFFE_PP0P_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule -(* techmap_celltype = "$_DFFE_NN1P_" *) -module _90_dffe_nn1_to_np1 (input D, C, R, E, output Q); \$_DFFE_NP1P_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule -(* techmap_celltype = "$_DFFE_PN1P_" *) -module _90_dffe_pn1_to_pp1 (input D, C, R, E, output Q); \$_DFFE_PP1P_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule - -(* techmap_celltype = "$_SDFF_NN0_" *) -module _90_dffs_nn0_to_np0 (input D, C, R, output Q); \$_SDFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule -(* techmap_celltype = "$_SDFF_PN0_" *) -module _90_dffs_pn0_to_pp0 (input D, C, R, output Q); \$_SDFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule -(* techmap_celltype = "$_SDFF_NN1_" *) -module _90_dffs_nn1_to_np1 (input D, C, R, output Q); \$_SDFF_NP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule -(* techmap_celltype = "$_SDFF_PN1_" *) -module _90_dffs_pn1_to_pp1 (input D, C, R, output Q); \$_SDFF_PP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule - -(* techmap_celltype = "$_SDFFE_NN0P_" *) -module _90_dffse_nn0_to_np0 (input D, C, R, E, output Q); \$_SDFFE_NP0P_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule -(* techmap_celltype = "$_SDFFE_PN0P_" *) -module _90_dffse_pn0_to_pp0 (input D, C, R, E, output Q); \$_SDFFE_PP0P_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule -(* techmap_celltype = "$_SDFFE_NN1P_" *) -module _90_dffse_nn1_to_np1 (input D, C, R, E, output Q); \$_SDFFE_NP1P_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule -(* techmap_celltype = "$_SDFFE_PN1P_" *) -module _90_dffse_pn1_to_pp1 (input D, C, R, E, output Q); \$_SDFFE_PP1P_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule - module \$__SHREG_ (input C, input D, input E, output Q); parameter DEPTH = 0; parameter [DEPTH-1:0] INIT = 0; diff --git a/techlibs/xilinx/ff_map.v b/techlibs/xilinx/ff_map.v new file mode 100644 index 00000000000..45d202294e5 --- /dev/null +++ b/techlibs/xilinx/ff_map.v @@ -0,0 +1,120 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +`ifndef _NO_FFS + +// Async reset, enable. + +module \$_DFFE_NP0P_ (input D, C, E, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR(R)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule +module \$_DFFE_PP0P_ (input D, C, E, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR(R)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule + +module \$_DFFE_NP1P_ (input D, C, E, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE(R)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule +module \$_DFFE_PP1P_ (input D, C, E, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE(R)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule + +// Async set and reset, enable. + +module \$_DFFSRE_NPPP_ (input D, C, E, S, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDCPE #(.INIT(_TECHMAP_WIREINIT_Q_), .IS_C_INVERTED(1'b1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR(R), .PRE(S)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule +module \$_DFFSRE_PPPP_ (input D, C, E, S, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDCPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR(R), .PRE(S)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule + +// Sync reset, enable. + +module \$_SDFFE_NP0P_ (input D, C, E, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(R)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule +module \$_SDFFE_PP0P_ (input D, C, E, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(R)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule + +module \$_SDFFE_NP1P_ (input D, C, E, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S(R)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule +module \$_SDFFE_PP1P_ (input D, C, E, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S(R)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule + +// Latches with reset. + +module \$_DLATCH_NP0_ (input E, R, D, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + LDCE #(.INIT(_TECHMAP_WIREINIT_Q_), .IS_G_INVERTED(1'b1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .G(E), .GE(1'b1), .CLR(R)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule +module \$_DLATCH_PP0_ (input E, R, D, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + LDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .G(E), .GE(1'b1), .CLR(R)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule +module \$_DLATCH_NP1_ (input E, R, D, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + LDPE #(.INIT(_TECHMAP_WIREINIT_Q_), .IS_G_INVERTED(1'b1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .G(E), .GE(1'b1), .PRE(R)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule +module \$_DLATCH_PP1_ (input E, R, D, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + LDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .G(E), .GE(1'b1), .PRE(R)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule + +// Latches with set and reset. + +module \$_DLATCH_NPP_ (input E, S, R, D, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + LDCPE #(.INIT(_TECHMAP_WIREINIT_Q_), .IS_G_INVERTED(1'b1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .G(E), .GE(1'b1), .CLR(R), .PRE(S)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule +module \$_DLATCH_PPP_ (input E, S, R, D, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + LDCPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .G(E), .GE(1'b1), .CLR(R), .PRE(S)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule + +`endif + diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index b66dc850dd6..de0de5974af 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -342,13 +342,6 @@ struct SynthXilinxPass : public ScriptPass std::string lut_size_s = std::to_string(lut_size); if (help_mode) lut_size_s = "[46]"; - std::string ff_map_file; - if (help_mode) - ff_map_file = "+/xilinx/{family}_ff_map.v"; - else if (family == "xc6s") - ff_map_file = "+/xilinx/xc6s_ff_map.v"; - else - ff_map_file = "+/xilinx/xc7_ff_map.v"; if (check_label("begin")) { std::string read_args; @@ -595,11 +588,17 @@ struct SynthXilinxPass : public ScriptPass run("clean"); } - if (check_label("map_ffs", "('-abc9' only)")) { + if (check_label("map_ffs")) { + if (family == "xc6s") + run("dfflegalize -cell $_DFFE_?P?P_ r -cell $_SDFFE_?P?P_ r -cell $_DLATCH_?P?_ r", "(for xc6s)"); + else if (family == "xc6v" || family == "xc7" || family == "xcu" || family == "xcup") + run("dfflegalize -cell $_DFFE_?P?P_ 01 -cell $_SDFFE_?P?P_ 01 -cell $_DLATCH_?P?_ 01", "(for xc6v, xc7, xcu, xcup)"); + else + run("dfflegalize -cell $_DFFE_?P?P_ 01 -cell $_DFFSRE_?PPP_ 01 -cell $_SDFFE_?P?P_ 01 -cell $_DLATCH_?P?_ 01 -cell $_DLATCHSR_?PP_ 01", "(for xc5v and older)"); if (abc9 || help_mode) { if (dff || help_mode) - run("zinit -all w:* t:$_DFF_?_ t:$_DFFE_??_ t:$_SDFF*", "('-dff' only)"); - run("techmap -map " + ff_map_file); + run("zinit -all w:* t:$_SDFFE_*", "('-dff' only)"); + run("techmap -map +/xilinx/ff_map.v", "('-abc9' only)"); } } @@ -659,7 +658,7 @@ struct SynthXilinxPass : public ScriptPass run("xilinx_srl -fixed -minlen 3", "(skip if '-nosrl')"); std::string techmap_args = "-map +/xilinx/lut_map.v -map +/xilinx/cells_map.v"; if (help_mode || !abc9) - techmap_args += stringf(" -map %s", ff_map_file.c_str()); + techmap_args += stringf(" -map +/xilinx/ff_map.v"); techmap_args += " -D LUT_WIDTH=" + lut_size_s; run("techmap " + techmap_args); if (help_mode) diff --git a/techlibs/xilinx/xc6s_ff_map.v b/techlibs/xilinx/xc6s_ff_map.v deleted file mode 100644 index a1e4218b911..00000000000 --- a/techlibs/xilinx/xc6s_ff_map.v +++ /dev/null @@ -1,256 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -// ============================================================================ -// FF mapping for Spartan 6. The primitives used are the same as Series 7, -// but with one major difference: the initial value is implied by the -// primitive type used (FFs with reset pin must have INIT set to 0 or x, FFs -// with set pin must have INIT set to 1 or x). For Yosys primitives without -// set/reset, this means we have to pick the primitive type based on the INIT -// value. - -`ifndef _NO_FFS - -// No reset. - -module \$_DFF_N_ (input D, C, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) - FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S(1'b0)); - else - FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_DFF_P_ (input D, C, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) - FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S(1'b0)); - else - FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -// No reset, enable. - -module \$_DFFE_NP_ (input D, C, E, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) - FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S(1'b0)); - else - FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_DFFE_PP_ (input D, C, E, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) - FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S(1'b0)); - else - FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -// Async reset. - -module \$_DFF_NP0_ (input D, C, R, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) - $error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1"); - else - FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_DFF_PP0_ (input D, C, R, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) - $error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1"); - else - FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -module \$_DFF_NP1_ (input D, C, R, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) - $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0"); - else - FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_DFF_PP1_ (input D, C, R, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) - $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0"); - else - FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -// Async reset, enable. - -module \$_DFFE_NP0P_ (input D, C, E, R, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) - $error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1"); - else - FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR( R)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_DFFE_PP0P_ (input D, C, E, R, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) - $error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1"); - else - FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR( R)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -module \$_DFFE_NP1P_ (input D, C, E, R, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) - $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0"); - else - FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE( R)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_DFFE_PP1P_ (input D, C, E, R, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) - $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0"); - else - FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE( R)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -// Sync reset. - -module \$_SDFF_NP0_ (input D, C, R, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) - $error("Spartan 6 doesn't support FFs with reset initialized to 1"); - else - FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R( R)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_SDFF_PP0_ (input D, C, R, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) - $error("Spartan 6 doesn't support FFs with reset initialized to 1"); - else - FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R( R)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -module \$_SDFF_NP1_ (input D, C, R, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) - $error("Spartan 6 doesn't support FFs with set initialized to 0"); - else - FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S( R)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_SDFF_PP1_ (input D, C, R, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) - $error("Spartan 6 doesn't support FFs with set initialized to 0"); - else - FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S( R)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -// Sync reset, enable. - -module \$_SDFFE_NP0P_ (input D, C, E, R, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) - $error("Spartan 6 doesn't support FFs with reset initialized to 1"); - else - FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R( R)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_SDFFE_PP0P_ (input D, C, E, R, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) - $error("Spartan 6 doesn't support FFs with reset initialized to 1"); - else - FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R( R)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -module \$_SDFFE_NP1P_ (input D, C, E, R, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) - $error("Spartan 6 doesn't support FFs with set initialized to 0"); - else - FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S( R)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_SDFFE_PP1P_ (input D, C, E, R, output Q); - parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) - $error("Spartan 6 doesn't support FFs with set initialized to 0"); - else - FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S( R)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -// Latches (no reset). - -module \$_DLATCH_N_ (input E, D, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) - LDPE #(.INIT(_TECHMAP_WIREINIT_Q_), .IS_G_INVERTED(1'b1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .G(E), .GE(1'b1), .PRE(1'b0)); - else - LDCE #(.INIT(_TECHMAP_WIREINIT_Q_), .IS_G_INVERTED(1'b1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .G(E), .GE(1'b1), .CLR(1'b0)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_DLATCH_P_ (input E, D, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) - LDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .G(E), .GE(1'b1), .PRE(1'b0)); - else - LDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .G(E), .GE(1'b1), .CLR(1'b0)); - endgenerate - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -// Latches with reset (TODO). - -`endif - diff --git a/techlibs/xilinx/xc7_ff_map.v b/techlibs/xilinx/xc7_ff_map.v deleted file mode 100644 index 750e8f8eb5d..00000000000 --- a/techlibs/xilinx/xc7_ff_map.v +++ /dev/null @@ -1,178 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -// ============================================================================ -// FF mapping for Virtex 6, Series 7 and Ultrascale. These families support -// the following features: -// -// - a CLB flip-flop can be used as a latch or as a flip-flop -// - a CLB flip-flop has the following pins: -// -// - data input -// - clock (or gate for latches) (with optional inversion) -// - clock enable (or gate enable, which is just ANDed with gate — unused by -// synthesis) -// - either a set or a reset input, which (for FFs) can be either -// synchronous or asynchronous (with optional inversion) -// - data output -// -// - a flip-flop also has an initial value, which is set at device -// initialization (or whenever GSR is asserted) - -`ifndef _NO_FFS - -// No reset. - -module \$_DFF_N_ (input D, C, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_DFF_P_ (input D, C, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -// No reset, enable. - -module \$_DFFE_NP_ (input D, C, E, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_DFFE_PP_ (input D, C, E, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -// Async reset. - -module \$_DFF_NP0_ (input D, C, R, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_DFF_PP0_ (input D, C, R, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -module \$_DFF_NP1_ (input D, C, R, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_DFF_PP1_ (input D, C, R, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -// Async reset, enable. - -module \$_DFFE_NP0P_ (input D, C, E, R, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR( R)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_DFFE_PP0P_ (input D, C, E, R, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR( R)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -module \$_DFFE_NP1P_ (input D, C, E, R, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE( R)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_DFFE_PP1P_ (input D, C, E, R, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE( R)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -// Sync reset. - -module \$_SDFF_NP0_ (input D, C, R, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R( R)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_SDFF_PP0_ (input D, C, R, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R( R)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -module \$_SDFF_NP1_ (input D, C, R, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S( R)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_SDFF_PP1_ (input D, C, R, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S( R)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -// Sync reset, enable. - -module \$_SDFFE_NP0P_ (input D, C, E, R, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R( R)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_SDFFE_PP0P_ (input D, C, E, R, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R( R)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -module \$_SDFFE_NP1P_ (input D, C, E, R, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S( R)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_SDFFE_PP1P_ (input D, C, E, R, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S( R)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -// Latches (no reset). - -module \$_DLATCH_N_ (input E, D, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - LDCE #(.INIT(_TECHMAP_WIREINIT_Q_), .IS_G_INVERTED(1'b1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .G(E), .GE(1'b1), .CLR(1'b0)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule -module \$_DLATCH_P_ (input E, D, output Q); - parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - LDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .G(E), .GE(1'b1), .CLR(1'b0)); - wire _TECHMAP_REMOVEINIT_Q_ = 1; -endmodule - -// Latches with reset (TODO). - -`endif - From ab59e33b2bb690ef02dabfc42fffd752c6a6e864 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 9 Jul 2020 17:52:52 +0000 Subject: [PATCH 060/287] cxxrtl: add missing extern "C". This bug was hidden if a header was generated. --- backends/cxxrtl/cxxrtl_backend.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index 5e5ba5ac0f0..6d3c2f4f9b7 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -1935,6 +1935,7 @@ struct CxxrtlWorker { f << "} // namespace " << design_ns << "\n"; f << "\n"; if (top_module != nullptr && debug_info) { + f << "extern \"C\"\n"; f << "cxxrtl_toplevel " << design_ns << "_create() {\n"; inc_indent(); std::string top_type = design_ns + "::" + mangle(top_module); From 9c120b89ace6c111aa4677616947d18d980b9c1a Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 9 Jul 2020 18:13:04 +0000 Subject: [PATCH 061/287] Revert PRs #2203 and #2244. This reverts commit 7e83a51fc96495c558a31fc3ca6c1a5ba4764f15. This reverts commit b422f2e4d0b8d5bfa97913d6b9dee488b59fc405. This reverts commit 7cb56f34b06de666935fbda315ce7c7bd45048b3. This reverts commit 6f9be939bd7653b0bdcae93a1033a086a4561b68. This reverts commit 76a34dc5f3a60c89efeaa3378ca0e2700a8aebd2. --- frontends/verilog/verilog_parser.y | 29 ++++++++--------------- tests/various/integer_range_bad_syntax.ys | 6 ----- tests/various/integer_real_bad_syntax.ys | 6 ----- tests/various/logic_param_simple.ys | 9 ------- tests/various/signed.ys | 28 ---------------------- 5 files changed, 10 insertions(+), 68 deletions(-) delete mode 100644 tests/various/integer_range_bad_syntax.ys delete mode 100644 tests/various/integer_real_bad_syntax.ys delete mode 100644 tests/various/logic_param_simple.ys delete mode 100644 tests/various/signed.ys diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index dfdb11cf0e6..0fdf2b51604 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -747,7 +747,7 @@ module_body: module_body_stmt: task_func_decl | specify_block | param_decl | localparam_decl | typedef_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt | enum_decl | struct_decl | - always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block | /* empty statement */ ';'; + always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block; checker_decl: TOK_CHECKER TOK_ID ';' { @@ -1331,45 +1331,36 @@ ignspec_id: param_signed: TOK_SIGNED { astbuf1->is_signed = true; - } | TOK_UNSIGNED { - astbuf1->is_signed = false; } | /* empty */; param_integer: TOK_INTEGER { + if (astbuf1->children.size() != 1) + frontend_verilog_yyerror("Internal error in param_integer - should not happen?"); astbuf1->children.push_back(new AstNode(AST_RANGE)); astbuf1->children.back()->children.push_back(AstNode::mkconst_int(31, true)); astbuf1->children.back()->children.push_back(AstNode::mkconst_int(0, true)); astbuf1->is_signed = true; - } + } | /* empty */; param_real: TOK_REAL { + if (astbuf1->children.size() != 1) + frontend_verilog_yyerror("Parameter already declared as integer, cannot set to real."); astbuf1->children.push_back(new AstNode(AST_REALVALUE)); - } - -param_logic: - TOK_LOGIC { - // SV LRM 6.11, Table 6-8: logic -- 4-state, user-defined vector size, unsigned - astbuf1->is_signed = false; - astbuf1->is_logic = true; - } + } | /* empty */; param_range: range { if ($1 != NULL) { + if (astbuf1->children.size() != 1) + frontend_verilog_yyerror("integer/real parameters should not have a range."); astbuf1->children.push_back($1); } }; -param_integer_type: param_integer param_signed -param_range_type: type_vec param_signed param_range -param_implicit_type: param_signed param_range - -param_integer_vector_type: param_logic param_signed param_range - param_type: - param_integer_type | param_integer_vector_type | param_real | param_range_type | param_implicit_type | + param_signed param_integer param_real param_range | hierarchical_type_id { astbuf1->is_custom_type = true; astbuf1->children.push_back(new AstNode(AST_WIRETYPE)); diff --git a/tests/various/integer_range_bad_syntax.ys b/tests/various/integer_range_bad_syntax.ys deleted file mode 100644 index 4f427211f3e..00000000000 --- a/tests/various/integer_range_bad_syntax.ys +++ /dev/null @@ -1,6 +0,0 @@ -logger -expect error "syntax error, unexpected" 1 -read_verilog -sv < Date: Thu, 9 Jul 2020 19:36:39 +0000 Subject: [PATCH 062/287] verilog_parser: turn S/R and R/R conflicts into hard errors. Fixes #2253. --- frontends/verilog/Makefile.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index cf9b9531e49..d5d5edd3d0e 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -6,7 +6,7 @@ GENFILES += frontends/verilog/verilog_lexer.cc frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y $(Q) mkdir -p $(dir $@) - $(P) $(BISON) -o $@ -d -r all -b frontends/verilog/verilog_parser $< + $(P) $(BISON) -Werror=conflicts-sr,error=conflicts-rr -o $@ -d -r all -b frontends/verilog/verilog_parser $< frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc From edbaf2fdf667d2d0d2bd7a5f9a8ae086b13b02ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Thu, 2 Jul 2020 18:22:29 +0200 Subject: [PATCH 063/287] sf2: Use dfflegalize. --- techlibs/sf2/cells_map.v | 56 +++++++++------------------------------ techlibs/sf2/synth_sf2.cc | 1 + 2 files changed, 13 insertions(+), 44 deletions(-) diff --git a/techlibs/sf2/cells_map.v b/techlibs/sf2/cells_map.v index 70f3b3b16e0..88782995e6e 100644 --- a/techlibs/sf2/cells_map.v +++ b/techlibs/sf2/cells_map.v @@ -1,59 +1,27 @@ -module \$_DFF_N_ (input D, C, output Q); - SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(1'b1), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +module \$_DFFE_PN0P_ (input D, C, R, E, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(E), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); endmodule -module \$_DFF_P_ (input D, C, output Q); - SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(1'b1), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +module \$_DFFE_PN1P_ (input D, C, R, E, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(E), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); endmodule -module \$_DFF_NN0_ (input D, C, R, output Q); - SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +module \$_SDFFCE_PN0P_ (input D, C, R, E, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(E), .ALn(1'b1), .ADn(1'b0), .SLn(R), .SD(1'b0), .LAT(1'b0), .Q(Q)); endmodule -module \$_DFF_NN1_ (input D, C, R, output Q); - SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +module \$_SDFFCE_PN1P_ (input D, C, R, E, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(E), .ALn(1'b1), .ADn(1'b0), .SLn(R), .SD(1'b1), .LAT(1'b0), .Q(Q)); endmodule -module \$_DFF_NP0_ (input D, C, R, output Q); - SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(!R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +module \$_DLATCH_PN0_ (input D, R, E, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(E), .EN(1'b1), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b1), .Q(Q)); endmodule -module \$_DFF_NP1_ (input D, C, R, output Q); - SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(!R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +module \$_DLATCH_PN1_ (input D, R, E, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(E), .EN(1'b1), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b1), .Q(Q)); endmodule -module \$_DFF_PN0_ (input D, C, R, output Q); - SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); -endmodule - -module \$_DFF_PN1_ (input D, C, R, output Q); - SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); -endmodule - -module \$_DFF_PP0_ (input D, C, R, output Q); - SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(!R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); -endmodule - -module \$_DFF_PP1_ (input D, C, R, output Q); - SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(!R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); -endmodule - -// module \$_DFFE_NN_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule -// module \$_DFFE_PN_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule -// -// module \$_DFFE_NP_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule -// module \$_DFFE_PP_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule -// -// module \$_DFFE_NN0P_ (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule -// module \$_DFFE_NN1P_ (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule -// module \$_DFFE_PN0P_ (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule -// module \$_DFFE_PN1P_ (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule -// -// module \$_DFFE_NP0P_ (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule -// module \$_DFFE_NP1P_ (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule -// module \$_DFFE_PP0P_ (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule -// module \$_DFFE_PP1P_ (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule - `ifndef NO_LUT module \$lut (A, Y); parameter WIDTH = 0; diff --git a/techlibs/sf2/synth_sf2.cc b/techlibs/sf2/synth_sf2.cc index 6b2a3f9b830..e0c2a64feff 100644 --- a/techlibs/sf2/synth_sf2.cc +++ b/techlibs/sf2/synth_sf2.cc @@ -187,6 +187,7 @@ struct SynthSf2Pass : public ScriptPass if (check_label("map_ffs")) { + run("dfflegalize -cell $_DFFE_PN?P_ x -cell $_SDFFCE_PN?P_ x -cell $_DLATCH_PN?_ x"); run("techmap -D NO_LUT -map +/sf2/cells_map.v"); run("opt_expr -mux_undef"); run("simplemap"); From 7dc0439de426483013a445122643e930b0bd0fa2 Mon Sep 17 00:00:00 2001 From: Dan Ravensloft Date: Sat, 4 Jul 2020 21:20:26 +0100 Subject: [PATCH 064/287] sf2: replace sf2_iobs with {clkbuf,iopad}map --- techlibs/sf2/Makefile.inc | 1 - techlibs/sf2/cells_sim.v | 141 ++++++++++++++++++++++++--- techlibs/sf2/sf2_iobs.cc | 197 -------------------------------------- techlibs/sf2/synth_sf2.cc | 10 +- 4 files changed, 135 insertions(+), 214 deletions(-) delete mode 100644 techlibs/sf2/sf2_iobs.cc diff --git a/techlibs/sf2/Makefile.inc b/techlibs/sf2/Makefile.inc index cc3054aced8..cade49f37dd 100644 --- a/techlibs/sf2/Makefile.inc +++ b/techlibs/sf2/Makefile.inc @@ -1,6 +1,5 @@ OBJS += techlibs/sf2/synth_sf2.o -OBJS += techlibs/sf2/sf2_iobs.o $(eval $(call add_share_file,share/sf2,techlibs/sf2/arith_map.v)) $(eval $(call add_share_file,share/sf2,techlibs/sf2/cells_map.v)) diff --git a/techlibs/sf2/cells_sim.v b/techlibs/sf2/cells_sim.v index c62748b11b7..eff57a65534 100644 --- a/techlibs/sf2/cells_sim.v +++ b/techlibs/sf2/cells_sim.v @@ -1,7 +1,6 @@ // https://coredocs.s3.amazonaws.com/Libero/12_0_0/Tool/sf2_mlg.pdf module ADD2 ( - input A, B, output Y ); @@ -76,6 +75,7 @@ endmodule module CLKINT ( input A, + (* clkbuf_driver *) output Y ); assign Y = A; @@ -83,6 +83,7 @@ endmodule module CLKINT_PRESERVE ( input A, + (* clkbuf_driver *) output Y ); assign Y = A; @@ -90,6 +91,7 @@ endmodule module GCLKINT ( input A, EN, + (* clkbuf_driver *) output Y ); assign Y = A & EN; @@ -97,6 +99,7 @@ endmodule module RCLKINT ( input A, + (* clkbuf_driver *) output Y ); assign Y = A; @@ -104,6 +107,7 @@ endmodule module RGCLKINT ( input A, EN, + (* clkbuf_driver *) output Y ); assign Y = A & EN; @@ -113,6 +117,7 @@ module SLE ( output Q, input ADn, input ALn, + (* clkbuf_sink *) input CLK, input D, input LAT, @@ -155,9 +160,41 @@ endmodule // module SYSRESET // module SYSCTRL_RESET_STATUS // module LIVE_PROBE_FB -// module GCLKBUF -// module GCLKBUF_DIFF -// module GCLKBIBUF + +(* blackbox *) +module GCLKBUF ( + (* iopad_external_pin *) + input PAD, + input EN, + (* clkbuf_driver *) + output Y +); +endmodule + +(* blackbox *) +module GCLKBUF_DIFF ( + (* iopad_external_pin *) + input PADP, + (* iopad_external_pin *) + input PADN, + input EN, + (* clkbuf_driver *) + output Y +); +endmodule + +(* blackbox *) +module GCLKBIBUF ( + input D, + input E, + input EN, + (* iopad_external_pin *) + inout PAD, + (* clkbuf_driver *) + output Y +); +endmodule + // module DFN1 // module DFN1C0 // module DFN1E1 @@ -288,38 +325,118 @@ module XOR8 ( endmodule // module UJTAG -// module BIBUF -// module BIBUF_DIFF -// module CLKBIBUF + +module BIBUF ( + input D, + input E, + (* iopad_external_pin *) + inout PAD, + output Y +); + assign PAD = E ? D : 1'bz; + assign Y = PAD; +endmodule + +(* blackbox *) +module BIBUF_DIFF ( + input D, + input E, + (* iopad_external_pin *) + inout PADP, + (* iopad_external_pin *) + inout PADN, + output Y +); +endmodule + +module CLKBIBUF ( + input D, + input E, + (* iopad_external_pin *) + inout PAD, + (* clkbuf_driver *) + output Y +); + assign PAD = E ? D : 1'bz; + assign Y = PAD; +endmodule module CLKBUF ( + (* iopad_external_pin *) input PAD, + (* clkbuf_driver *) output Y ); assign Y = PAD; endmodule -// module CLKBUF_DIFF +(* blackbox *) +module CLKBUF_DIFF ( + (* iopad_external_pin *) + input PADP, + (* iopad_external_pin *) + input PADN, + (* clkbuf_driver *) + output Y +); +endmodule module INBUF ( + (* iopad_external_pin *) input PAD, output Y ); assign Y = PAD; endmodule -// module INBUF_DIFF +(* blackbox *) +module INBUF_DIFF ( + (* iopad_external_pin *) + input PADP, + (* iopad_external_pin *) + input PADN, + output Y +); +endmodule module OUTBUF ( input D, + (* iopad_external_pin *) output PAD ); assign PAD = D; endmodule -// module OUTBUF_DIFF -// module TRIBUFF -// module TRIBUFF_DIFF +(* blackbox *) +module OUTBUF_DIFF ( + input D, + (* iopad_external_pin *) + output PADP, + (* iopad_external_pin *) + output PADN +); +endmodule + +module TRIBUFF ( + input D, + input E, + (* iopad_external_pin *) + output PAD +); + assign PAD = E ? D : 1'bz; +endmodule + +(* blackbox *) +module TRIBUFF_DIFF ( + input D, + input E, + (* iopad_external_pin *) + output PADP, + (* iopad_external_pin *) + output PADN +); +endmodule + // module DDR_IN // module DDR_OUT // module RAM1K18 diff --git a/techlibs/sf2/sf2_iobs.cc b/techlibs/sf2/sf2_iobs.cc deleted file mode 100644 index 5fd719ce52f..00000000000 --- a/techlibs/sf2/sf2_iobs.cc +++ /dev/null @@ -1,197 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" -#include "kernel/sigtools.h" - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -static void handle_iobufs(Module *module, bool clkbuf_mode) -{ - SigMap sigmap(module); - - pool clk_bits; - pool handled_io_bits; - dict rewrite_bits; - vector> pad_bits; - - for (auto cell : module->cells()) - { - if (clkbuf_mode && cell->type == ID(SLE)) { - for (auto bit : sigmap(cell->getPort(ID::CLK))) - clk_bits.insert(bit); - } - if (cell->type.in(ID(INBUF), ID(OUTBUF), ID(TRIBUFF), ID(BIBUF), ID(CLKBUF), ID(CLKBIBUF), - ID(INBUF_DIFF), ID(OUTBUF_DIFF), ID(BIBUFF_DIFF), ID(TRIBUFF_DIFF), ID(CLKBUF_DIFF), - ID(GCLKBUF), ID(GCLKBUF_DIFF), ID(GCLKBIBUF))) { - for (auto bit : sigmap(cell->getPort(ID(PAD)))) - handled_io_bits.insert(bit); - } - } - - for (auto wire : vector(module->wires())) - { - if (!wire->port_input && !wire->port_output) - continue; - - for (int index = 0; index < GetSize(wire); index++) - { - SigBit bit(wire, index); - SigBit canonical_bit = sigmap(bit); - - if (handled_io_bits.count(canonical_bit)) - continue; - - if (wire->port_input && wire->port_output) - log_error("Failed to add buffer for inout port bit %s.\n", log_signal(bit)); - - IdString buf_type, buf_port; - - if (wire->port_output) { - buf_type = ID(OUTBUF); - buf_port = ID::D; - } else if (clkbuf_mode && clk_bits.count(canonical_bit)) { - buf_type = ID(CLKBUF); - buf_port = ID::Y; - } else { - buf_type = ID(INBUF); - buf_port = ID::Y; - } - - Cell *c = module->addCell(NEW_ID, buf_type); - SigBit new_bit = module->addWire(NEW_ID); - c->setPort(buf_port, new_bit); - pad_bits.push_back(make_pair(c, bit)); - rewrite_bits[canonical_bit] = new_bit; - - log("Added %s cell %s for port bit %s.\n", log_id(c->type), log_id(c), log_signal(bit)); - } - } - - auto rewrite_function = [&](SigSpec &s) { - for (auto &bit : s) { - SigBit canonical_bit = sigmap(bit); - if (rewrite_bits.count(canonical_bit)) - bit = rewrite_bits.at(canonical_bit); - } - }; - - module->rewrite_sigspecs(rewrite_function); - - for (auto &it : pad_bits) - it.first->setPort(ID(PAD), it.second); -} - -static void handle_clkint(Module *module) -{ - SigMap sigmap(module); - - pool clk_bits; - vector handled_clk_bits; - - for (auto cell : module->cells()) - { - if (cell->type == ID(SLE)) { - for (auto bit : sigmap(cell->getPort(ID::CLK))) - clk_bits.insert(bit); - } - if (cell->type.in(ID(CLKBUF), ID(CLKBIBUF), ID(CLKBUF_DIFF), ID(GCLKBUF), ID(GCLKBUF_DIFF), ID(GCLKBIBUF), - ID(CLKINT), ID(CLKINT_PRESERVE), ID(GCLKINT), ID(RCLKINT), ID(RGCLKINT))) { - for (auto bit : sigmap(cell->getPort(ID::Y))) - handled_clk_bits.push_back(bit); - } - } - - for (auto bit : handled_clk_bits) - clk_bits.erase(bit); - - for (auto cell : vector(module->cells())) - for (auto &conn : cell->connections()) - { - if (!cell->output(conn.first)) - continue; - - SigSpec sig = conn.second; - bool did_something = false; - - for (auto &bit : sig) { - SigBit canonical_bit = sigmap(bit); - if (clk_bits.count(canonical_bit)) { - Cell *c = module->addCell(NEW_ID, ID(CLKINT)); - SigBit new_bit = module->addWire(NEW_ID); - c->setPort(ID::A, new_bit); - c->setPort(ID::Y, bit); - log("Added %s cell %s for clock signal %s.\n", log_id(c->type), log_id(c), log_signal(bit)); - clk_bits.erase(canonical_bit); - did_something = true; - bit = new_bit; - } - } - - if (did_something) - cell->setPort(conn.first, sig); - } - - for (auto bit : clk_bits) - log_error("Failed to insert CLKINT for clock signal %s.\n", log_signal(bit)); -} - -struct Sf2IobsPass : public Pass { - Sf2IobsPass() : Pass("sf2_iobs", "SF2: insert IO buffers") { } - void help() override - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" sf2_iobs [options] [selection]\n"); - log("\n"); - log("Add SF2 I/O buffers and global buffers to top module as needed.\n"); - log("\n"); - log(" -clkbuf\n"); - log(" Insert PAD->global_net clock buffers\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) override - { - bool clkbuf_mode = false; - - log_header(design, "Executing sf2_iobs pass (insert IO buffers).\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-clkbuf") { - clkbuf_mode = true; - continue; - } - break; - } - extra_args(args, argidx, design); - - Module *module = design->top_module(); - - if (module == nullptr) - log_cmd_error("No top module found.\n"); - - handle_iobufs(module, clkbuf_mode); - handle_clkint(module); - } -} Sf2IobsPass; - -PRIVATE_NAMESPACE_END diff --git a/techlibs/sf2/synth_sf2.cc b/techlibs/sf2/synth_sf2.cc index 6b2a3f9b830..096450ad3d1 100644 --- a/techlibs/sf2/synth_sf2.cc +++ b/techlibs/sf2/synth_sf2.cc @@ -209,10 +209,12 @@ struct SynthSf2Pass : public ScriptPass if (check_label("map_iobs")) { - if (help_mode) - run("sf2_iobs [-clkbuf]", "(unless -noiobs)"); - else if (iobs) - run(clkbuf ? "sf2_iobs -clkbuf" : "sf2_iobs"); + if (help_mode || iobs) { + if (help_mode || clkbuf) { + run("clkbufmap -buf CLKINT Y:A -inpad CLKBUF Y:PAD", "(if -clkbuf, unless -noiobs)"); + } + run("iopadmap -bits -inpad INBUF Y:PAD -outpad OUTBUF D:PAD -toutpad TRIBUFF E:D:PAD -tinoutpad BIBUF E:Y:D:PAD", "(unless -noiobs"); + } run("clean"); } From de649b91943816149e28a49acb4718e41be2589f Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Fri, 10 Jul 2020 09:59:48 +0200 Subject: [PATCH 065/287] Revert "Revert PRs #2203 and #2244." This reverts commit 9c120b89ace6c111aa4677616947d18d980b9c1a. --- frontends/verilog/verilog_parser.y | 29 +++++++++++++++-------- tests/various/integer_range_bad_syntax.ys | 6 +++++ tests/various/integer_real_bad_syntax.ys | 6 +++++ tests/various/logic_param_simple.ys | 9 +++++++ tests/various/signed.ys | 28 ++++++++++++++++++++++ 5 files changed, 68 insertions(+), 10 deletions(-) create mode 100644 tests/various/integer_range_bad_syntax.ys create mode 100644 tests/various/integer_real_bad_syntax.ys create mode 100644 tests/various/logic_param_simple.ys create mode 100644 tests/various/signed.ys diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 0fdf2b51604..dfdb11cf0e6 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -747,7 +747,7 @@ module_body: module_body_stmt: task_func_decl | specify_block | param_decl | localparam_decl | typedef_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt | enum_decl | struct_decl | - always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block; + always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block | /* empty statement */ ';'; checker_decl: TOK_CHECKER TOK_ID ';' { @@ -1331,36 +1331,45 @@ ignspec_id: param_signed: TOK_SIGNED { astbuf1->is_signed = true; + } | TOK_UNSIGNED { + astbuf1->is_signed = false; } | /* empty */; param_integer: TOK_INTEGER { - if (astbuf1->children.size() != 1) - frontend_verilog_yyerror("Internal error in param_integer - should not happen?"); astbuf1->children.push_back(new AstNode(AST_RANGE)); astbuf1->children.back()->children.push_back(AstNode::mkconst_int(31, true)); astbuf1->children.back()->children.push_back(AstNode::mkconst_int(0, true)); astbuf1->is_signed = true; - } | /* empty */; + } param_real: TOK_REAL { - if (astbuf1->children.size() != 1) - frontend_verilog_yyerror("Parameter already declared as integer, cannot set to real."); astbuf1->children.push_back(new AstNode(AST_REALVALUE)); - } | /* empty */; + } + +param_logic: + TOK_LOGIC { + // SV LRM 6.11, Table 6-8: logic -- 4-state, user-defined vector size, unsigned + astbuf1->is_signed = false; + astbuf1->is_logic = true; + } param_range: range { if ($1 != NULL) { - if (astbuf1->children.size() != 1) - frontend_verilog_yyerror("integer/real parameters should not have a range."); astbuf1->children.push_back($1); } }; +param_integer_type: param_integer param_signed +param_range_type: type_vec param_signed param_range +param_implicit_type: param_signed param_range + +param_integer_vector_type: param_logic param_signed param_range + param_type: - param_signed param_integer param_real param_range | + param_integer_type | param_integer_vector_type | param_real | param_range_type | param_implicit_type | hierarchical_type_id { astbuf1->is_custom_type = true; astbuf1->children.push_back(new AstNode(AST_WIRETYPE)); diff --git a/tests/various/integer_range_bad_syntax.ys b/tests/various/integer_range_bad_syntax.ys new file mode 100644 index 00000000000..4f427211f3e --- /dev/null +++ b/tests/various/integer_range_bad_syntax.ys @@ -0,0 +1,6 @@ +logger -expect error "syntax error, unexpected" 1 +read_verilog -sv < Date: Fri, 10 Jul 2020 10:14:31 +0200 Subject: [PATCH 066/287] Fix R/R conflicts This commit fixes R/R conflicts introduced by commit 7e83a51. Parameter logic is already defined as part of `param_range_type` rule. Signed-off-by: Kamil Rakoczy --- frontends/verilog/verilog_parser.y | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index dfdb11cf0e6..1c86c789571 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -1348,13 +1348,6 @@ param_real: astbuf1->children.push_back(new AstNode(AST_REALVALUE)); } -param_logic: - TOK_LOGIC { - // SV LRM 6.11, Table 6-8: logic -- 4-state, user-defined vector size, unsigned - astbuf1->is_signed = false; - astbuf1->is_logic = true; - } - param_range: range { if ($1 != NULL) { @@ -1366,10 +1359,8 @@ param_integer_type: param_integer param_signed param_range_type: type_vec param_signed param_range param_implicit_type: param_signed param_range -param_integer_vector_type: param_logic param_signed param_range - param_type: - param_integer_type | param_integer_vector_type | param_real | param_range_type | param_implicit_type | + param_integer_type | param_real | param_range_type | param_implicit_type | hierarchical_type_id { astbuf1->is_custom_type = true; astbuf1->children.push_back(new AstNode(AST_WIRETYPE)); From d77b3305d83f6877f2177daecab658067659f4ce Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Fri, 10 Jul 2020 14:56:14 +0200 Subject: [PATCH 067/287] Fix S/R conflicts This commit fixes S/R conflicts introduced by commit 6f9be93. Signed-off-by: Kamil Rakoczy --- frontends/verilog/verilog_parser.y | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 1c86c789571..b9e72141542 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -742,12 +742,13 @@ module_body: module_body module_body_stmt | /* the following line makes the generate..endgenrate keywords optional */ module_body gen_stmt | + module_body ';' | /* empty */; module_body_stmt: task_func_decl | specify_block | param_decl | localparam_decl | typedef_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt | enum_decl | struct_decl | - always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block | /* empty statement */ ';'; + always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block; checker_decl: TOK_CHECKER TOK_ID ';' { From f9ed09423e5fb0b880d895d91ec51c61ffb04213 Mon Sep 17 00:00:00 2001 From: Claire Wolf Date: Fri, 10 Jul 2020 18:41:13 +0200 Subject: [PATCH 068/287] Add AST_EDGE support to AstNode::detect_latch(), fixes #2241 Signed-off-by: Claire Wolf --- frontends/ast/simplify.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index c4df5c0a07f..00f8c8df67c 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -4231,6 +4231,8 @@ bool AstNode::detect_latch(const std::string &var) case AST_POSEDGE: case AST_NEGEDGE: return false; + case AST_EDGE: + break; case AST_BLOCK: if (!c->detect_latch(var)) return false; From 240351c44ecadc3a5c67b298568a04373883eca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Sun, 12 Jul 2020 15:39:40 +0200 Subject: [PATCH 069/287] dfflegalize: Gather init values from all wires. Skipping non-selected wires is unsound in an obvious way. --- passes/techmap/dfflegalize.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/dfflegalize.cc b/passes/techmap/dfflegalize.cc index c0f112836ed..13ce4f49afb 100644 --- a/passes/techmap/dfflegalize.cc +++ b/passes/techmap/dfflegalize.cc @@ -1296,7 +1296,7 @@ flip_dqisr:; sigmap.set(module); initbits.clear(); - for (auto wire : module->selected_wires()) + for (auto wire : module->wires()) { if (wire->attributes.count(ID::init) == 0) continue; From b33744b03ab8c8188e45656722d4a28c173ec67c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Sun, 12 Jul 2020 15:38:51 +0200 Subject: [PATCH 070/287] proc_dlatch: Remove init values for combinatorial processes. Fixes #2258. --- passes/proc/proc_dlatch.cc | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/passes/proc/proc_dlatch.cc b/passes/proc/proc_dlatch.cc index e7c8a80ddce..3ed158f3743 100644 --- a/passes/proc/proc_dlatch.cc +++ b/passes/proc/proc_dlatch.cc @@ -37,6 +37,7 @@ struct proc_dlatch_db_t dict> mux_srcbits; dict> mux_drivers; dict sigusers; + dict> initbits; proc_dlatch_db_t(Module *module) : module(module), sigmap(module) { @@ -69,9 +70,34 @@ struct proc_dlatch_db_t } for (auto wire : module->wires()) + { if (wire->port_input) for (auto bit : sigmap(wire)) sigusers[bit]++; + if (wire->attributes.count(ID::init)) { + SigSpec wirebits = sigmap(wire); + Const initval = wire->attributes.at(ID::init); + + for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) + { + SigBit bit = wirebits[i]; + State val = initval[i]; + + if (val != State::S0 && val != State::S1 && bit.wire != nullptr) + continue; + + if (initbits.count(bit)) { + if (initbits.at(bit).first != val) + log_error("Conflicting init values for signal %s (%s = %s != %s).\n", + log_signal(bit), log_signal(SigBit(wire, i)), + log_signal(val), log_signal(initbits.at(bit).first)); + continue; + } + + initbits[bit] = std::make_pair(val,SigBit(wire,i)); + } + } + } } bool quickcheck(const SigSpec &haystack, const SigSpec &needle) @@ -393,6 +419,13 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc) else log("No latch inferred for signal `%s.%s' from process `%s.%s'.\n", db.module->name.c_str(), log_signal(lhs), db.module->name.c_str(), proc->name.c_str()); + for (auto &bit : lhs) { + auto it = db.initbits.find(bit); + if (it != db.initbits.end()) { + log("Removing init bit %s for non-memory siginal `%s.%s` in process `%s.%s`.\n", log_signal(it->second.first), db.module->name.c_str(), log_signal(bit), db.module->name.c_str(), proc->name.c_str()); + it->second.second.wire->attributes.at(ID::init)[it->second.second.offset] = State::Sx; + } + } db.module->connect(lhs, rhs); offset += chunk.width; } From 347dd01c2f7dff6e8222c5f9d360f84a17c937b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Sun, 12 Jul 2020 17:54:07 +0200 Subject: [PATCH 071/287] xilinx: Fix srl regression. Of standard yosys cells, xilinx_srl only works on $_DFF_?_ and $_DFFE_?P_, which get upgraded to $_SDFFE_?P?P_ by dfflegalize at the point where xilinx_srl is called for non-abc9. Fix this by running ff_map.v first, resulting in FDRE cells, which are handled correctly. --- techlibs/xilinx/synth_xilinx.cc | 4 ++-- tests/arch/xilinx/nosrl.ys | 41 +++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 tests/arch/xilinx/nosrl.ys diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index de0de5974af..421602e626c 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -652,13 +652,13 @@ struct SynthXilinxPass : public ScriptPass } run("clean"); + if (help_mode || !abc9) + run("techmap -map +/xilinx/ff_map.v", "(only if not '-abc9')"); // This shregmap call infers fixed length shift registers after abc // has performed any necessary retiming if (!nosrl || help_mode) run("xilinx_srl -fixed -minlen 3", "(skip if '-nosrl')"); std::string techmap_args = "-map +/xilinx/lut_map.v -map +/xilinx/cells_map.v"; - if (help_mode || !abc9) - techmap_args += stringf(" -map +/xilinx/ff_map.v"); techmap_args += " -D LUT_WIDTH=" + lut_size_s; run("techmap " + techmap_args); if (help_mode) diff --git a/tests/arch/xilinx/nosrl.ys b/tests/arch/xilinx/nosrl.ys new file mode 100644 index 00000000000..31bd5d377ac --- /dev/null +++ b/tests/arch/xilinx/nosrl.ys @@ -0,0 +1,41 @@ +read_verilog < Date: Sun, 12 Jul 2020 23:34:18 +0000 Subject: [PATCH 072/287] cxxrtl: expose eval() and commit() via the C API. --- backends/cxxrtl/cxxrtl_capi.cc | 8 ++++++++ backends/cxxrtl/cxxrtl_capi.h | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/backends/cxxrtl/cxxrtl_capi.cc b/backends/cxxrtl/cxxrtl_capi.cc index e0566e152ae..b77e4c49141 100644 --- a/backends/cxxrtl/cxxrtl_capi.cc +++ b/backends/cxxrtl/cxxrtl_capi.cc @@ -43,6 +43,14 @@ void cxxrtl_destroy(cxxrtl_handle handle) { delete handle; } +int cxxrtl_eval(cxxrtl_handle handle) { + return handle->module->eval(); +} + +int cxxrtl_commit(cxxrtl_handle handle) { + return handle->module->commit(); +} + size_t cxxrtl_step(cxxrtl_handle handle) { return handle->module->step(); } diff --git a/backends/cxxrtl/cxxrtl_capi.h b/backends/cxxrtl/cxxrtl_capi.h index 599284898c0..74257f0daa4 100644 --- a/backends/cxxrtl/cxxrtl_capi.h +++ b/backends/cxxrtl/cxxrtl_capi.h @@ -55,6 +55,18 @@ cxxrtl_handle cxxrtl_create(cxxrtl_toplevel design); // Release all resources used by a design and its handle. void cxxrtl_destroy(cxxrtl_handle handle); +// Evaluate the design, propagating changes on inputs to the `next` value of internal state and +// output wires. +// +// Returns 1 if the design is known to immediately converge, 0 otherwise. +int cxxrtl_eval(cxxrtl_handle handle); + +// Commit the design, replacing the `curr` value of internal state and output wires with the `next` +// value. +// +// Return 1 if any of the `curr` values, 0 otherwise. +int cxxrtl_commit(cxxrtl_handle handle); + // Simulate the design to a fixed point. // // Returns the number of delta cycles. From a3a90f6377f251d3b6c5898eb1543f8832493bb8 Mon Sep 17 00:00:00 2001 From: Lofty Date: Mon, 13 Jul 2020 14:08:52 +0100 Subject: [PATCH 073/287] Revert "intel_alm: direct M10K instantiation" This reverts commit 09ecb9b2cf3ab76841d30712bf70dafc6d47ef67. --- techlibs/intel_alm/Makefile.inc | 6 +-- techlibs/intel_alm/common/bram_m10k.txt | 4 +- techlibs/intel_alm/common/bram_m10k_map.v | 31 ++++++++++++++ techlibs/intel_alm/common/megafunction_bb.v | 37 +---------------- techlibs/intel_alm/common/mem_sim.v | 34 ---------------- techlibs/intel_alm/common/quartus_rename.v | 45 --------------------- techlibs/intel_alm/synth_intel_alm.cc | 3 +- tests/arch/intel_alm/blockram.ys | 6 --- 8 files changed, 38 insertions(+), 128 deletions(-) create mode 100644 techlibs/intel_alm/common/bram_m10k_map.v delete mode 100644 tests/arch/intel_alm/blockram.ys diff --git a/techlibs/intel_alm/Makefile.inc b/techlibs/intel_alm/Makefile.inc index e36c81c0ec4..552f00c658e 100644 --- a/techlibs/intel_alm/Makefile.inc +++ b/techlibs/intel_alm/Makefile.inc @@ -15,9 +15,9 @@ $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/ds $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/mem_sim.v)) # RAM -$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_m10k.txt)) -$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_m20k.txt)) -$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_m20k_map.v)) +bramtypes := m10k m20k +$(foreach bramtype, $(bramtypes), $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_$(bramtype).txt))) +$(foreach bramtype, $(bramtypes), $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_$(bramtype)_map.v))) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/lutram_mlab.txt)) # Miscellaneous diff --git a/techlibs/intel_alm/common/bram_m10k.txt b/techlibs/intel_alm/common/bram_m10k.txt index e9355fe2cc9..837e3a33032 100644 --- a/techlibs/intel_alm/common/bram_m10k.txt +++ b/techlibs/intel_alm/common/bram_m10k.txt @@ -1,4 +1,4 @@ -bram MISTRAL_M10K +bram __MISTRAL_M10K_SDP init 0 # TODO: Re-enable when I figure out how BRAM init works abits 13 @D8192x1 dbits 1 @D8192x1 @@ -27,7 +27,7 @@ bram MISTRAL_M10K endbram -match MISTRAL_M10K +match __MISTRAL_M10K_SDP min efficiency 5 make_transp endmatch diff --git a/techlibs/intel_alm/common/bram_m10k_map.v b/techlibs/intel_alm/common/bram_m10k_map.v new file mode 100644 index 00000000000..061463c3e1d --- /dev/null +++ b/techlibs/intel_alm/common/bram_m10k_map.v @@ -0,0 +1,31 @@ +module __MISTRAL_M10K_SDP(CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); + +parameter CFG_ABITS = 10; +parameter CFG_DBITS = 10; +parameter CFG_ENABLE_A = 1; +parameter CFG_ENABLE_B = 1; + +input CLK1; +input [CFG_ABITS-1:0] A1ADDR, B1ADDR; +input [CFG_DBITS-1:0] A1DATA; +output [CFG_DBITS-1:0] B1DATA; +input [CFG_ENABLE_A-1:0] A1EN, B1EN; + +altsyncram #( + .operation_mode("dual_port"), + .ram_block_type("m10k"), + .widthad_a(CFG_ABITS), + .width_a(CFG_DBITS), + .widthad_b(CFG_ABITS), + .width_b(CFG_DBITS), +) _TECHMAP_REPLACE_ ( + .address_a(A1ADDR), + .data_a(A1DATA), + .wren_a(A1EN), + .address_b(B1ADDR), + .q_b(B1DATA), + .clock0(CLK1), + .clock1(CLK1) +); + +endmodule diff --git a/techlibs/intel_alm/common/megafunction_bb.v b/techlibs/intel_alm/common/megafunction_bb.v index 820b0430e0b..b5a3d889261 100644 --- a/techlibs/intel_alm/common/megafunction_bb.v +++ b/techlibs/intel_alm/common/megafunction_bb.v @@ -156,39 +156,4 @@ input [ax_width-1:0] ax; input [ay_scan_in_width-1:0] ay; output [result_a_width-1:0] resulta; -endmodule - -(* blackbox *) -module cyclonev_ram_block(portaaddr, portadatain, portawe, portbaddr, portbdataout, portbre, clk0); - -parameter operation_mode = "dual_port"; -parameter logical_ram_name = ""; -parameter port_a_address_width = 10; -parameter port_a_data_width = 10; -parameter port_a_logical_ram_depth = 1024; -parameter port_a_logical_ram_width = 10; -parameter port_a_first_address = 0; -parameter port_a_last_address = 1023; -parameter port_a_first_bit_number = 0; -parameter port_b_address_width = 10; -parameter port_b_data_width = 10; -parameter port_b_logical_ram_depth = 1024; -parameter port_b_logical_ram_width = 10; -parameter port_b_first_address = 0; -parameter port_b_last_address = 1023; -parameter port_b_first_bit_number = 0; -parameter port_b_address_clock = "clock0"; -parameter port_b_read_enable_clock = "clock0"; -parameter mem_init0 = ""; -parameter mem_init1 = ""; -parameter mem_init2 = ""; -parameter mem_init3 = ""; -parameter mem_init4 = ""; - -input [port_a_address_width-1:0] portaaddr; -input [port_b_address_width-1:0] portbaddr; -input [port_a_data_width-1:0] portadatain; -output [port_b_data_width-1:0] portbdataout; -input clk0, portawe, portbre; - -endmodule +endmodule \ No newline at end of file diff --git a/techlibs/intel_alm/common/mem_sim.v b/techlibs/intel_alm/common/mem_sim.v index 23ffc6c878d..f6f9ecb02b0 100644 --- a/techlibs/intel_alm/common/mem_sim.v +++ b/techlibs/intel_alm/common/mem_sim.v @@ -68,37 +68,3 @@ always @(posedge CLK1) assign B1DATA = mem[B1ADDR]; endmodule - -// The M10K -// -------- -// TODO - -module MISTRAL_M10K(CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); - -parameter CFG_ABITS = 10; -parameter CFG_DBITS = 10; - -input CLK1; -input [CFG_ABITS-1:0] A1ADDR, B1ADDR; -input [CFG_DBITS-1:0] A1DATA; -input A1EN, B1EN; -output reg [CFG_DBITS-1:0] B1DATA; - -reg [2**CFG_ABITS * CFG_DBITS - 1 : 0] mem = 0; - -specify - $setup(A1ADDR, posedge CLK1, 0); - $setup(A1DATA, posedge CLK1, 0); - - if (B1EN) (posedge CLK1 => (B1DATA : A1DATA)) = 0; -endspecify - -always @(posedge CLK1) begin - if (A1EN) - mem[(A1ADDR + 1) * CFG_DBITS - 1 : A1ADDR * CFG_DBITS] <= A1DATA; - - if (B1EN) - B1DATA <= mem[(B1ADDR + 1) * CFG_DBITS - 1 : B1ADDR * CFG_DBITS]; -end - -endmodule diff --git a/techlibs/intel_alm/common/quartus_rename.v b/techlibs/intel_alm/common/quartus_rename.v index 926d2d64f9f..46ef2aa0dc7 100644 --- a/techlibs/intel_alm/common/quartus_rename.v +++ b/techlibs/intel_alm/common/quartus_rename.v @@ -123,51 +123,6 @@ module MISTRAL_MLAB(input [4:0] A1ADDR, input A1DATA, A1EN, CLK1, input [4:0] B1 endmodule -module MISTRAL_M10K(A1ADDR, A1DATA, A1EN, CLK1, B1ADDR, B1DATA, B1EN); - -parameter CFG_ABITS = 10; -parameter CFG_DBITS = 10; - -input [CFG_ABITS-1:0] A1ADDR, B1ADDR; -input [CFG_DBITS-1:0] A1DATA; -input CLK1, A1EN, B1EN; -output [CFG_DBITS-1:0] B1DATA; - -// Much like the MLAB, the M10K has mem_init[01234] parameters which would let -// you initialise the RAM cell via hex literals. If they were implemented. - -cyclonev_ram_block #( - .operation_mode("dual_port"), - .logical_ram_name("MISTRAL_M10K"), - .port_a_address_width(CFG_ABITS), - .port_a_data_width(CFG_DBITS), - .port_a_logical_ram_depth(2**CFG_ABITS), - .port_a_logical_ram_width(CFG_DBITS), - .port_a_first_address(0), - .port_a_last_address(2**CFG_DBITS - 1), - .port_a_first_bit_number(0), - .port_b_address_width(CFG_ABITS), - .port_b_data_width(CFG_DBITS), - .port_b_logical_ram_depth(2**CFG_ABITS), - .port_b_logical_ram_width(CFG_DBITS), - .port_b_first_address(0), - .port_b_last_address(2**CFG_DBITS - 1), - .port_b_first_bit_number(0), - .port_b_address_clock("clock0"), - .port_b_read_enable_clock("clock0") -) _TECHMAP_REPLACE_ ( - .portaaddr(A1ADDR), - .portadatain(A1DATA), - .portawe(A1EN), - .portbaddr(B1ADDR), - .portbdataout(B1DATA), - .portbre(B1EN), - .clk0(CLK1) -); - -endmodule - - module MISTRAL_MUL27X27(input [26:0] A, B, output [53:0] Y); `MAC #(.ax_width(27), .ay_scan_in_width(27), .result_a_width(54), .operation_mode("M27x27")) _TECHMAP_REPLACE_ (.ax(A), .ay(B), .resulta(Y)); diff --git a/techlibs/intel_alm/synth_intel_alm.cc b/techlibs/intel_alm/synth_intel_alm.cc index 12137cdeae9..b751e8413fc 100644 --- a/techlibs/intel_alm/synth_intel_alm.cc +++ b/techlibs/intel_alm/synth_intel_alm.cc @@ -235,8 +235,7 @@ struct SynthIntelALMPass : public ScriptPass { if (!nobram && check_label("map_bram", "(skip if -nobram)")) { run(stringf("memory_bram -rules +/intel_alm/common/bram_%s.txt", bram_type.c_str())); - if (help_mode || bram_type != "m10k") - run(stringf("techmap -map +/intel_alm/common/bram_%s_map.v", bram_type.c_str())); + run(stringf("techmap -map +/intel_alm/common/bram_%s_map.v", bram_type.c_str())); } if (!nolutram && check_label("map_lutram", "(skip if -nolutram)")) { diff --git a/tests/arch/intel_alm/blockram.ys b/tests/arch/intel_alm/blockram.ys deleted file mode 100644 index 610ae1ffdbd..00000000000 --- a/tests/arch/intel_alm/blockram.ys +++ /dev/null @@ -1,6 +0,0 @@ -read_verilog ../common/blockram.v -chparam -set ADDRESS_WIDTH 10 -set DATA_WIDTH 10 sync_ram_sdp -synth_intel_alm -family cyclonev -cd sync_ram_sdp -select -assert-count 1 t:MISTRAL_M10K -select -assert-none t:MISTRAL_M10K %% t:* %D From 3209c0762a560d68ce7aef00942a8b3e440d5a61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Sun, 5 Jul 2020 04:02:42 +0200 Subject: [PATCH 074/287] intel: Use dfflegalize. --- techlibs/intel/Makefile.inc | 1 + techlibs/intel/common/ff_map.v | 11 ++++++++ techlibs/intel/cyclone10lp/cells_map.v | 35 ------------------------ techlibs/intel/cycloneiv/cells_map.v | 35 ------------------------ techlibs/intel/cycloneive/cells_map.v | 35 ------------------------ techlibs/intel/cyclonev/cells_map.v | 37 -------------------------- techlibs/intel/max10/cells_map.v | 35 ------------------------ techlibs/intel/synth_intel.cc | 6 ++++- 8 files changed, 17 insertions(+), 178 deletions(-) create mode 100644 techlibs/intel/common/ff_map.v diff --git a/techlibs/intel/Makefile.inc b/techlibs/intel/Makefile.inc index f751e341f81..fef6aab779e 100644 --- a/techlibs/intel/Makefile.inc +++ b/techlibs/intel/Makefile.inc @@ -5,6 +5,7 @@ $(eval $(call add_share_file,share/intel/common,techlibs/intel/common/m9k_bb.v)) $(eval $(call add_share_file,share/intel/common,techlibs/intel/common/altpll_bb.v)) $(eval $(call add_share_file,share/intel/common,techlibs/intel/common/brams_m9k.txt)) $(eval $(call add_share_file,share/intel/common,techlibs/intel/common/brams_map_m9k.v)) +$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/ff_map.v)) # Add the cell models and mappings for the VQM backend families := max10 arria10gx cyclonev cyclone10lp cycloneiv cycloneive diff --git a/techlibs/intel/common/ff_map.v b/techlibs/intel/common/ff_map.v new file mode 100644 index 00000000000..e3f92adbb2d --- /dev/null +++ b/techlibs/intel/common/ff_map.v @@ -0,0 +1,11 @@ +// Async Active Low Reset DFF +module \$_DFFE_PN0P_ (input D, C, R, E, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) begin + dffeas #(.is_wysiwyg("TRUE"), .power_up("high")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(E), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); + end else begin + dffeas #(.is_wysiwyg("TRUE"), .power_up("low")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(E), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); + end + endgenerate + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule diff --git a/techlibs/intel/cyclone10lp/cells_map.v b/techlibs/intel/cyclone10lp/cells_map.v index 25d73711c49..22907b14428 100644 --- a/techlibs/intel/cyclone10lp/cells_map.v +++ b/techlibs/intel/cyclone10lp/cells_map.v @@ -19,41 +19,6 @@ // > c60k28 (Viacheslav, VT) [at] yandex [dot] com // > Intel FPGA technology mapping. User must first simulate the generated \ // > netlist before going to test it on board. -// > Changelog: 1) The missing power_up parameter in the techmap introduces a problem in Quartus mapper. Fixed. - -// Normal mode DFF negedge clk, negedge reset -module \$_DFF_N_ (input D, C, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); -endmodule -// Normal mode DFF -module \$_DFF_P_ (input D, C, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); -endmodule - -// Async Active Low Reset DFF -module \$_DFF_PN0_ (input D, C, R, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up("power_up")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); -endmodule -// Async Active High Reset DFF -module \$_DFF_PP0_ (input D, C, R, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - wire R_i = ~ R; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R_i), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); -endmodule - -module \$_DFFE_PP0P_ (input D, C, E, R, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - wire E_i = ~ E; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(E_i), .sload(1'b0)); -endmodule // Input buffer map module \$__inpad (input I, output O); diff --git a/techlibs/intel/cycloneiv/cells_map.v b/techlibs/intel/cycloneiv/cells_map.v index 56d32e58646..41afd94be87 100644 --- a/techlibs/intel/cycloneiv/cells_map.v +++ b/techlibs/intel/cycloneiv/cells_map.v @@ -19,41 +19,6 @@ // > c60k28 (Viacheslav, VT) [at] yandex [dot] com // > Intel FPGA technology mapping. User must first simulate the generated \ // > netlist before going to test it on board. -// > Changelog: 1) The missing power_up parameter in the techmap introduces a problem in Quartus mapper. Fixed. - -// Normal mode DFF negedge clk, negedge reset -module \$_DFF_N_ (input D, C, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); -endmodule -// Normal mode DFF -module \$_DFF_P_ (input D, C, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); -endmodule - -// Async Active Low Reset DFF -module \$_DFF_PN0_ (input D, C, R, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up("power_up")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); -endmodule -// Async Active High Reset DFF -module \$_DFF_PP0_ (input D, C, R, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - wire R_i = ~ R; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R_i), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); -endmodule - -module \$_DFFE_PP0P_ (input D, C, E, R, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - wire E_i = ~ E; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(E_i), .sload(1'b0)); -endmodule // Input buffer map module \$__inpad (input I, output O); diff --git a/techlibs/intel/cycloneive/cells_map.v b/techlibs/intel/cycloneive/cells_map.v index 43a1183dede..6d7f36ec573 100644 --- a/techlibs/intel/cycloneive/cells_map.v +++ b/techlibs/intel/cycloneive/cells_map.v @@ -19,41 +19,6 @@ // > c60k28 (Viacheslav, VT) [at] yandex [dot] com // > Intel FPGA technology mapping. User must first simulate the generated \ // > netlist before going to test it on board. -// > Changelog: 1) The missing power_up parameter in the techmap introduces a problem in Quartus mapper. Fixed. - -// Normal mode DFF negedge clk, negedge reset -module \$_DFF_N_ (input D, C, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); -endmodule -// Normal mode DFF -module \$_DFF_P_ (input D, C, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); -endmodule - -// Async Active Low Reset DFF -module \$_DFF_PN0_ (input D, C, R, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up("power_up")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); -endmodule -// Async Active High Reset DFF -module \$_DFF_PP0_ (input D, C, R, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - wire R_i = ~ R; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R_i), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); -endmodule - -module \$_DFFE_PP0P_ (input D, C, E, R, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - wire E_i = ~ E; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(E_i), .sload(1'b0)); -endmodule // Input buffer map module \$__inpad (input I, output O); diff --git a/techlibs/intel/cyclonev/cells_map.v b/techlibs/intel/cyclonev/cells_map.v index 8223df3c6e0..0041481ab7c 100644 --- a/techlibs/intel/cyclonev/cells_map.v +++ b/techlibs/intel/cyclonev/cells_map.v @@ -19,43 +19,6 @@ // > c60k28 (Viacheslav, VT) [at] yandex [dot] com // > Intel FPGA technology mapping. User must first simulate the generated \ // > netlist before going to test it on board. -// > Changelog: 1) The missing power_up parameter in the techmap introduces a problem in Quartus mapper. Fixed. -// 2) Cyclone V 7-input LUT function was wrong implemented. Removed abc option to map this function \ -// and added the explanation in this file instead. Such function needs to be implemented. - -// Normal mode DFF negedge clk, negedge reset -module \$_DFF_N_ (input D, C, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); -endmodule -// Normal mode DFF -module \$_DFF_P_ (input D, C, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); -endmodule - -// Async Active Low Reset DFF -module \$_DFF_PN0_ (input D, C, R, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up("power_up")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); -endmodule -// Async Active High Reset DFF -module \$_DFF_PP0_ (input D, C, R, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - wire R_i = ~ R; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R_i), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); -endmodule - -module \$_DFFE_PP0P_ (input D, C, E, R, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - wire E_i = ~ E; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(E_i), .sload(1'b0)); -endmodule // Input buffer map module \$__inpad (input I, output O); diff --git a/techlibs/intel/max10/cells_map.v b/techlibs/intel/max10/cells_map.v index 55b39308068..8f198daefa9 100644 --- a/techlibs/intel/max10/cells_map.v +++ b/techlibs/intel/max10/cells_map.v @@ -19,41 +19,6 @@ // > c60k28 (Viacheslav, VT) [at] yandex [dot] com // > Intel FPGA technology mapping. User must first simulate the generated \ // > netlist before going to test it on board. -// > Changelog: 1) The missing power_up parameter in the techmap introduces a problem in Quartus mapper. Fixed. - -// Normal mode DFF negedge clk, negedge reset -module \$_DFF_N_ (input D, C, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); -endmodule -// Normal mode DFF -module \$_DFF_P_ (input D, C, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); -endmodule - -// Async Active Low Reset DFF -module \$_DFF_PN0_ (input D, C, R, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up("power_up")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); -endmodule -// Async Active High Reset DFF -module \$_DFF_PP0_ (input D, C, R, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - wire R_i = ~ R; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R_i), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0)); -endmodule - -module \$_DFFE_PP0P_ (input D, C, E, R, output Q); - parameter WYSIWYG="TRUE"; - parameter power_up=1'bx; - wire E_i = ~ E; - dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(E_i), .sload(1'b0)); -endmodule // Input buffer map module \$__inpad (input I, output O); diff --git a/techlibs/intel/synth_intel.cc b/techlibs/intel/synth_intel.cc index f3709498cb6..1fa98d09842 100644 --- a/techlibs/intel/synth_intel.cc +++ b/techlibs/intel/synth_intel.cc @@ -212,6 +212,11 @@ struct SynthIntelPass : public ScriptPass { run("abc -markgroups -dff -D 1", "(only if -retime)"); } + if (check_label("map_ffs")) { + run("dfflegalize -cell $_DFFE_PN0P_ 01"); + run("techmap -map +/intel/common/ff_map.v"); + } + if (check_label("map_luts")) { if (family_opt == "arria10gx" || family_opt == "cyclonev") run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : "")); @@ -224,7 +229,6 @@ struct SynthIntelPass : public ScriptPass { if (iopads || help_mode) run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(if -iopads)"); run(stringf("techmap -map +/intel/%s/cells_map.v", family_opt.c_str())); - run("dffinit -highlow -ff dffeas q power_up"); run("clean -purge"); } From 3050454d6e80ddb7603f7d5cc117b440a6bd8ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Fri, 3 Jul 2020 00:22:44 +0200 Subject: [PATCH 075/287] anlogic: Use dfflegalize. --- techlibs/anlogic/cells_map.v | 38 +++++++++----------------- techlibs/anlogic/cells_sim.v | 45 +++++++++++++++---------------- techlibs/anlogic/synth_anlogic.cc | 2 +- tests/arch/anlogic/latches.ys | 26 +++++++++--------- 4 files changed, 49 insertions(+), 62 deletions(-) diff --git a/techlibs/anlogic/cells_map.v b/techlibs/anlogic/cells_map.v index 0bcea985657..000256fb9d2 100644 --- a/techlibs/anlogic/cells_map.v +++ b/techlibs/anlogic/cells_map.v @@ -1,31 +1,17 @@ -module \$_DFF_N_ (input D, C, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(1'b0)); endmodule -module \$_DFF_P_ (input D, C, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(1'b0)); endmodule +module \$_DFFE_PN0P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C) ,.ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DFFE_PN1P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DFFE_PP0P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DFFE_PP1P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), . SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_DFFE_NN_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(E), .sr(1'b0)); endmodule -module \$_DFFE_NP_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(E), .sr(1'b0)); endmodule -module \$_DFFE_PN_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(1'b0)); endmodule -module \$_DFFE_PP_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(1'b0)); endmodule +module \$_SDFFE_PN0P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C) ,.ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_SDFFE_PN1P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_SDFFE_PP0P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_SDFFE_PP1P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), . SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_DFF_NN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_NN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_NP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_NP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_PN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C) , .ce(1'b1), .sr(R)); endmodule -module \$_DFF_PN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_PP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_PP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), . SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule - -module \$_DLATCH_N_ (E, D, Q); - wire [1023:0] _TECHMAP_DO_ = "simplemap; opt"; - input E, D; - output Q = !E ? D : Q; -endmodule - -module \$_DLATCH_P_ (E, D, Q); - wire [1023:0] _TECHMAP_DO_ = "simplemap; opt"; - input E, D; - output Q = E ? D : Q; -endmodule +module \$_DLATCH_NN0_ (input D, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("LATCH"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(E) ,.ce(1'b1), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DLATCH_NN1_ (input D, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("LATCH"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(E), .ce(1'b1), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DLATCH_NP0_ (input D, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("LATCH"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(E), .ce(1'b1), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DLATCH_NP1_ (input D, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("LATCH"), .REGSET(1'b1), .SRMUX("SR"), . SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(E), .ce(1'b1), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule `ifndef NO_LUT module \$lut (A, Y); diff --git a/techlibs/anlogic/cells_sim.v b/techlibs/anlogic/cells_sim.v index 0fba4357204..e8ecf4f030f 100644 --- a/techlibs/anlogic/cells_sim.v +++ b/techlibs/anlogic/cells_sim.v @@ -10,9 +10,6 @@ module AL_MAP_SEQ ( parameter SRMUX = "SR"; //SR/INV parameter SRMODE = "SYNC"; //SYNC/ASYNC - wire clk_ce; - assign clk_ce = ce ? clk : 1'b0; - wire srmux; generate case (SRMUX) @@ -20,7 +17,7 @@ module AL_MAP_SEQ ( "INV": assign srmux = ~sr; default: assign srmux = sr; endcase - endgenerate + endgenerate wire regset; generate @@ -34,43 +31,45 @@ module AL_MAP_SEQ ( initial q = regset; generate - if (DFFMODE == "FF") + if (DFFMODE == "FF") begin - if (SRMODE == "ASYNC") + if (SRMODE == "ASYNC") begin - always @(posedge clk_ce, posedge srmux) + always @(posedge clk, posedge srmux) if (srmux) q <= regset; - else - q <= d; - end + else if (ce) + q <= d; + end else begin - always @(posedge clk_ce) + always @(posedge clk) if (srmux) q <= regset; - else - q <= d; + else if (ce) + q <= d; end end else begin // DFFMODE == "LATCH" - if (SRMODE == "ASYNC") + if (SRMODE == "ASYNC") begin - always @(clk_ce, srmux) + always @* if (srmux) q <= regset; - else - q <= d; - end + else if (~clk & ce) + q <= d; + end else begin - always @(clk_ce) - if (srmux) - q <= regset; - else - q <= d; + always @* + if (~clk) begin + if (srmux) + q <= regset; + else if (ce) + q <= d; + end end end endgenerate diff --git a/techlibs/anlogic/synth_anlogic.cc b/techlibs/anlogic/synth_anlogic.cc index d7475df86a0..d953fae5e3f 100644 --- a/techlibs/anlogic/synth_anlogic.cc +++ b/techlibs/anlogic/synth_anlogic.cc @@ -182,8 +182,8 @@ struct SynthAnlogicPass : public ScriptPass if (check_label("map_ffs")) { + run("dfflegalize -cell $_DFFE_P??P_ r -cell $_SDFFE_P??P_ r -cell $_DLATCH_N??_ r"); run("techmap -D NO_LUT -map +/anlogic/cells_map.v"); - run("dffinit -strinit SET RESET -ff AL_MAP_SEQ q REGSET -noreinit"); run("opt_expr -mux_undef"); run("simplemap"); } diff --git a/tests/arch/anlogic/latches.ys b/tests/arch/anlogic/latches.ys index 8d66f77b3c7..34a3b14d069 100644 --- a/tests/arch/anlogic/latches.ys +++ b/tests/arch/anlogic/latches.ys @@ -3,31 +3,33 @@ design -save read hierarchy -top latchp proc -# Can't run any sort of equivalence check because latches are blown to LUTs -synth_anlogic +equiv_opt -assert -multiclock -map +/anlogic/cells_sim.v synth_anlogic +design -load postopt cd latchp # Constrain all select calls below inside the top module -select -assert-count 1 t:AL_MAP_LUT3 -select -assert-none t:AL_MAP_LUT3 %% t:* %D +select -assert-count 1 t:AL_MAP_SEQ +select -assert-count 1 t:AL_MAP_LUT1 +select -assert-none t:AL_MAP_SEQ t:AL_MAP_LUT1 %% t:* %D design -load read hierarchy -top latchn proc -# Can't run any sort of equivalence check because latches are blown to LUTs -synth_anlogic +equiv_opt -assert -multiclock -map +/anlogic/cells_sim.v synth_anlogic +design -load postopt cd latchn # Constrain all select calls below inside the top module -select -assert-count 1 t:AL_MAP_LUT3 -select -assert-none t:AL_MAP_LUT3 %% t:* %D +select -assert-count 1 t:AL_MAP_SEQ +select -assert-none t:AL_MAP_SEQ %% t:* %D design -load read hierarchy -top latchsr proc -# Can't run any sort of equivalence check because latches are blown to LUTs -synth_anlogic +equiv_opt -assert -multiclock -map +/anlogic/cells_sim.v synth_anlogic +design -load postopt cd latchsr # Constrain all select calls below inside the top module -select -assert-count 1 t:AL_MAP_LUT5 -select -assert-none t:AL_MAP_LUT5 %% t:* %D +select -assert-count 1 t:AL_MAP_SEQ +select -assert-count 2 t:AL_MAP_LUT3 +select -assert-none t:AL_MAP_SEQ t:AL_MAP_LUT3 %% t:* %D From a5cf000377269fff41dfd6410fb113fd89373689 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 14 Jul 2020 16:10:30 +0000 Subject: [PATCH 076/287] cxxrtl: fix typo. NFC. --- backends/cxxrtl/cxxrtl_capi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/cxxrtl/cxxrtl_capi.h b/backends/cxxrtl/cxxrtl_capi.h index 74257f0daa4..1f194280342 100644 --- a/backends/cxxrtl/cxxrtl_capi.h +++ b/backends/cxxrtl/cxxrtl_capi.h @@ -64,7 +64,7 @@ int cxxrtl_eval(cxxrtl_handle handle); // Commit the design, replacing the `curr` value of internal state and output wires with the `next` // value. // -// Return 1 if any of the `curr` values, 0 otherwise. +// Return 1 if any of the `curr` values were updated, 0 otherwise. int cxxrtl_commit(cxxrtl_handle handle); // Simulate the design to a fixed point. From a786091b469b1327f9676745370b2e67b1c35023 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Fri, 3 Jul 2020 00:22:28 +0200 Subject: [PATCH 077/287] achronix: Use dfflegalize. --- techlibs/achronix/synth_achronix.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/achronix/synth_achronix.cc b/techlibs/achronix/synth_achronix.cc index ddd9822b9ab..b203828d2c2 100644 --- a/techlibs/achronix/synth_achronix.cc +++ b/techlibs/achronix/synth_achronix.cc @@ -144,12 +144,12 @@ struct SynthAchronixPass : public ScriptPass { run("opt -fast -mux_undef -undriven -fine -full"); run("memory_map"); run("opt -undriven -fine"); - run("dff2dffe -direct-match $_DFF_*"); run("opt -fine"); run("techmap -map +/techmap.v"); run("opt -full"); run("clean -purge"); run("setundef -undriven -zero"); + run("dfflegalize -cell $_DFF_P_ x"); if (retime || help_mode) run("abc -markgroups -dff -D 1", "(only if -retime)"); } From 61a7ec4768a3d0d0c8875bb4d9b6160f8697c0d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Wed, 15 Jul 2020 02:30:25 +0200 Subject: [PATCH 078/287] opt_merge: Dedup one more use of FF cell type list. --- passes/opt/opt_merge.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index f03faa9cf36..9086943dcb4 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -173,9 +173,7 @@ struct OptMergeWorker for (const auto &it : cell1->connections_) { if (cell1->output(it.first)) { - if (it.first == ID::Q && (cell1->type.begins_with("$dff") || cell1->type.begins_with("$dlatch") || - cell1->type.begins_with("$_DFF") || cell1->type.begins_with("$_DLATCH") || cell1->type.begins_with("$_SR_") || - cell1->type.in(ID($adff), ID($sr), ID($ff), ID($_FF_)))) { + if (it.first == ID::Q && RTLIL::builtin_ff_cell_types().count(cell1->type)) { // For the 'Q' output of state elements, // use the (* init *) attribute value auto &sig1 = conn1[it.first]; From 02c071888b4b2a26db5653609bb60e6c3f5c366f Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Wed, 15 Jul 2020 10:15:13 +0200 Subject: [PATCH 079/287] Add missing semicolons Signed-off-by: Kamil Rakoczy --- frontends/verilog/verilog_parser.y | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index b9e72141542..ba2eab3d3a1 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -1342,12 +1342,12 @@ param_integer: astbuf1->children.back()->children.push_back(AstNode::mkconst_int(31, true)); astbuf1->children.back()->children.push_back(AstNode::mkconst_int(0, true)); astbuf1->is_signed = true; - } + }; param_real: TOK_REAL { astbuf1->children.push_back(new AstNode(AST_REALVALUE)); - } + }; param_range: range { @@ -1356,9 +1356,9 @@ param_range: } }; -param_integer_type: param_integer param_signed -param_range_type: type_vec param_signed param_range -param_implicit_type: param_signed param_range +param_integer_type: param_integer param_signed; +param_range_type: type_vec param_signed param_range; +param_implicit_type: param_signed param_range; param_type: param_integer_type | param_real | param_range_type | param_implicit_type | From 1f4e452609690dec76b2d2cb0c2459d6d8ecfe46 Mon Sep 17 00:00:00 2001 From: Claire Wolf Date: Wed, 15 Jul 2020 00:04:04 +0200 Subject: [PATCH 080/287] Run bison with -Wall for verilog front-end Signed-off-by: Claire Wolf --- frontends/verilog/Makefile.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index d5d5edd3d0e..3725b58f656 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -6,7 +6,7 @@ GENFILES += frontends/verilog/verilog_lexer.cc frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y $(Q) mkdir -p $(dir $@) - $(P) $(BISON) -Werror=conflicts-sr,error=conflicts-rr -o $@ -d -r all -b frontends/verilog/verilog_parser $< + $(P) $(BISON) -Wall -Werror=conflicts-sr,error=conflicts-rr -o $@ -d -r all -b frontends/verilog/verilog_parser $< frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc From 24540291c7b3b42518dfbea9ec59c9b681d0e54e Mon Sep 17 00:00:00 2001 From: Claire Wolf Date: Wed, 15 Jul 2020 00:04:23 +0200 Subject: [PATCH 081/287] Fix bison warnings for missing %empty Signed-off-by: Claire Wolf --- frontends/verilog/verilog_parser.y | 111 ++++++++++++++--------------- 1 file changed, 52 insertions(+), 59 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index ba2eab3d3a1..390ef07e9e1 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -333,7 +333,7 @@ design: typedef_decl design | package design | interface design | - /* empty */; + %empty; attr: { @@ -355,7 +355,7 @@ attr_opt: attr_opt ATTR_BEGIN opt_attr_list ATTR_END { SET_RULE_LOC(@$, @2, @$); }| - /* empty */; + %empty; defattr: DEFATTR_BEGIN { @@ -376,7 +376,7 @@ defattr: } DEFATTR_END; opt_attr_list: - attr_list | /* empty */; + attr_list | %empty; attr_list: attr_assign | @@ -449,13 +449,13 @@ module: }; module_para_opt: - '#' '(' { astbuf1 = nullptr; } module_para_list { if (astbuf1) delete astbuf1; } ')' | /* empty */; + '#' '(' { astbuf1 = nullptr; } module_para_list { if (astbuf1) delete astbuf1; } ')' | %empty; module_para_list: single_module_para | module_para_list ',' single_module_para; single_module_para: - /* empty */ | + %empty | attr TOK_PARAMETER { if (astbuf1) delete astbuf1; astbuf1 = new AstNode(AST_PARAMETER); @@ -471,13 +471,13 @@ single_module_para: single_param_decl; module_args_opt: - '(' ')' | /* empty */ | '(' module_args optional_comma ')'; + '(' ')' | %empty | '(' module_args optional_comma ')'; module_args: module_arg | module_args ',' module_arg; optional_comma: - ',' | /* empty */; + ',' | %empty; module_arg_opt_assignment: '=' expr { @@ -497,7 +497,7 @@ module_arg_opt_assignment: } else frontend_verilog_yyerror("SystemVerilog interface in module port list cannot have a default value."); } | - /* empty */; + %empty; module_arg: TOK_ID { @@ -565,15 +565,10 @@ package: }; package_body: - package_body package_body_stmt - | // optional - ; + package_body package_body_stmt | %empty; package_body_stmt: - typedef_decl - | localparam_decl - | param_decl - ; + typedef_decl | localparam_decl | param_decl; interface: TOK_INTERFACE { @@ -599,7 +594,7 @@ interface: }; interface_body: - interface_body interface_body_stmt |; + interface_body interface_body_stmt | %empty; interface_body_stmt: param_decl | localparam_decl | typedef_decl | defparam_decl | wire_decl | always_stmt | assign_stmt | @@ -613,7 +608,7 @@ non_opt_delay: '#' '(' expr ':' expr ':' expr ')' { delete $3; delete $5; delete $7; }; delay: - non_opt_delay | /* empty */; + non_opt_delay | %empty; wire_type: { @@ -725,7 +720,7 @@ range: non_opt_range { $$ = $1; } | - /* empty */ { + %empty { $$ = NULL; }; @@ -743,7 +738,7 @@ module_body: /* the following line makes the generate..endgenrate keywords optional */ module_body gen_stmt | module_body ';' | - /* empty */; + %empty; module_body_stmt: task_func_decl | specify_block | param_decl | localparam_decl | typedef_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt | @@ -843,28 +838,28 @@ dpi_function_arg: opt_dpi_function_args: '(' dpi_function_args ')' | - /* empty */; + %empty; dpi_function_args: dpi_function_args ',' dpi_function_arg | dpi_function_args ',' | dpi_function_arg | - /* empty */; + %empty; opt_automatic: TOK_AUTOMATIC | - /* empty */; + %empty; opt_signed: TOK_SIGNED { $$ = true; } | - /* empty */ { + %empty { $$ = false; }; task_func_args_opt: - '(' ')' | /* empty */ | '(' { + '(' ')' | %empty | '(' { albuf = nullptr; astbuf1 = nullptr; astbuf2 = nullptr; @@ -905,7 +900,7 @@ task_func_port: task_func_body: task_func_body behavioral_stmt | - /* empty */; + %empty; /*************************** specify parser ***************************/ @@ -914,7 +909,7 @@ specify_block: specify_item_list: specify_item specify_item_list | - /* empty */; + %empty; specify_item: specify_if '(' specify_edge expr TOK_SPECIFY_OPER specify_target ')' '=' specify_rise_fall ';' { @@ -1076,7 +1071,7 @@ specify_opt_triple: ',' specify_triple { $$ = $2; } | - /* empty */ { + %empty { $$ = nullptr; }; @@ -1084,7 +1079,7 @@ specify_if: TOK_IF '(' expr ')' { $$ = $3; } | - /* empty */ { + %empty { $$ = nullptr; }; @@ -1092,7 +1087,7 @@ specify_condition: TOK_SPECIFY_AND expr { $$ = $2; } | - /* empty */ { + %empty { $$ = nullptr; }; @@ -1125,7 +1120,7 @@ specify_target: specify_edge: TOK_POSEDGE { $$ = 'p'; } | TOK_NEGEDGE { $$ = 'n'; } | - { $$ = 0; }; + %empty { $$ = 0; }; specify_rise_fall: specify_triple { @@ -1232,7 +1227,7 @@ specparam_assignment: ignspec_id '=' ignspec_expr ; ignspec_opt_cond: - TOK_IF '(' ignspec_expr ')' | /* empty */; + TOK_IF '(' ignspec_expr ')' | %empty; path_declaration : simple_path_declaration ';' @@ -1283,9 +1278,7 @@ list_of_path_outputs : list_of_path_outputs ',' specify_output_terminal_descriptor ; opt_polarity_operator : - '+' - | '-' - | ; + '+' | '-' | %empty; // Good enough for the time being specify_input_terminal_descriptor : @@ -1334,7 +1327,7 @@ param_signed: astbuf1->is_signed = true; } | TOK_UNSIGNED { astbuf1->is_signed = false; - } | /* empty */; + } | %empty; param_integer: TOK_INTEGER { @@ -1451,7 +1444,7 @@ enum_type: TOK_ENUM { enum_base_type: type_atom type_signing | type_vec type_signing range { if ($3) astbuf1->children.push_back($3); } - | /* nothing */ { astbuf1->is_reg = true; addRange(astbuf1); } + | %empty { astbuf1->is_reg = true; addRange(astbuf1); } ; type_atom: TOK_INTEGER { astbuf1->is_reg = true; addRange(astbuf1); } // 4-state signed @@ -1467,7 +1460,7 @@ type_vec: TOK_REG { astbuf1->is_reg = true; } // unsigned type_signing: TOK_SIGNED { astbuf1->is_signed = true; } | TOK_UNSIGNED { astbuf1->is_signed = false; } - | // optional + | %empty ; enum_name_list: enum_name_decl @@ -1491,7 +1484,7 @@ enum_name_decl: opt_enum_init: '=' basic_expr { $$ = $2; } // TODO: restrict this - | /* optional */ { $$ = NULL; } + | %empty { $$ = NULL; } ; enum_var_list: @@ -1532,14 +1525,14 @@ struct_union: struct_body: opt_packed '{' struct_member_list '}' ; -opt_packed: TOK_PACKED opt_signed_struct - | { frontend_verilog_yyerror("Only PACKED supported at this time"); } - ; +opt_packed: + TOK_PACKED opt_signed_struct | + %empty { frontend_verilog_yyerror("Only PACKED supported at this time"); }; opt_signed_struct: TOK_SIGNED { astbuf2->is_signed = true; } | TOK_UNSIGNED { astbuf2->is_signed = false; } - | // default is unsigned + | %empty // default is unsigned ; struct_member_list: struct_member @@ -1646,7 +1639,7 @@ wire_decl: } opt_supply_wires ';'; opt_supply_wires: - /* empty */ | + %empty | opt_supply_wires ',' TOK_ID { AstNode *wire_node = ast_stack.back()->children.at(GetSize(ast_stack.back()->children)-2)->clone(); AstNode *assign_node = ast_stack.back()->children.at(GetSize(ast_stack.back()->children)-1)->clone(); @@ -1877,13 +1870,13 @@ single_prim: } cell_parameter_list_opt: - '#' '(' cell_parameter_list ')' | /* empty */; + '#' '(' cell_parameter_list ')' | %empty; cell_parameter_list: cell_parameter | cell_parameter_list ',' cell_parameter; cell_parameter: - /* empty */ | + %empty | expr { AstNode *node = new AstNode(AST_PARASET); astbuf1->children.push_back(node); @@ -2041,7 +2034,7 @@ always_cond: '@' ATTR_BEGIN ')' | '@' '(' ATTR_END | '@' '*' | - /* empty */; + %empty; always_events: always_event | @@ -2071,7 +2064,7 @@ opt_label: ':' TOK_ID { $$ = $2; } | - /* empty */ { + %empty { $$ = NULL; }; @@ -2079,7 +2072,7 @@ opt_sva_label: TOK_SVA_LABEL ':' { $$ = $1; } | - /* empty */ { + %empty { $$ = NULL; }; @@ -2090,7 +2083,7 @@ opt_property: TOK_FINAL { $$ = false; } | - /* empty */ { + %empty { $$ = false; }; @@ -2501,7 +2494,7 @@ behavioral_stmt: }; unique_case_attr: - /* empty */ { + %empty { $$ = false; } | TOK_PRIORITY case_attr { @@ -2537,11 +2530,11 @@ opt_synopsys_attr: if (ast_stack.back()->attributes.count(ID::parallel_case) == 0) ast_stack.back()->attributes[ID::parallel_case] = AstNode::mkconst_int(1, false); } | - /* empty */; + %empty; behavioral_stmt_list: behavioral_stmt_list behavioral_stmt | - /* empty */; + %empty; optional_else: TOK_ELSE { @@ -2555,11 +2548,11 @@ optional_else: } behavioral_stmt { SET_AST_NODE_LOC(ast_stack.back(), @3, @3); } | - /* empty */ %prec FAKE_THEN; + %empty %prec FAKE_THEN; case_body: case_body case_item | - /* empty */; + %empty; case_item: { @@ -2582,7 +2575,7 @@ case_item: gen_case_body: gen_case_body gen_case_item | - /* empty */; + %empty; gen_case_item: { @@ -2666,11 +2659,11 @@ lvalue_concat_list: opt_arg_list: '(' arg_list optional_comma ')' | - /* empty */; + %empty; arg_list: arg_list2 | - /* empty */; + %empty; arg_list2: single_arg | @@ -2683,7 +2676,7 @@ single_arg: module_gen_body: module_gen_body gen_stmt_or_module_body_stmt | - /* empty */; + %empty; gen_stmt_or_module_body_stmt: gen_stmt | module_body_stmt | @@ -2762,7 +2755,7 @@ gen_stmt_block: }; opt_gen_else: - TOK_ELSE gen_stmt_block | /* empty */ %prec FAKE_THEN; + TOK_ELSE gen_stmt_block | %empty %prec FAKE_THEN; expr: basic_expr { From 7a79843cc394f59bdd40473a823c7f60c87d3fa6 Mon Sep 17 00:00:00 2001 From: Claire Wolf Date: Wed, 15 Jul 2020 11:54:28 +0200 Subject: [PATCH 082/287] Use %precedence in verilog_parser.y Signed-off-by: Claire Wolf --- frontends/verilog/verilog_parser.y | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 390ef07e9e1..63f0341d9bd 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -299,14 +299,14 @@ static void rewriteAsMemoryNode(AstNode *node, AstNode *rangeNode) %left '+' '-' %left '*' '/' '%' %left OP_POW -%left OP_CAST -%right UNARY_OPS +%precedence OP_CAST +%precedence UNARY_OPS %define parse.error verbose %define parse.lac full -%nonassoc FAKE_THEN -%nonassoc TOK_ELSE +%precedence FAKE_THEN +%precedence TOK_ELSE %debug %locations From 51ee0b683fc7064fa5a400d7fa642464fc942ec3 Mon Sep 17 00:00:00 2001 From: Claire Wolf Date: Wed, 15 Jul 2020 11:57:31 +0200 Subject: [PATCH 083/287] Treat all bison warnings as errors in verilog front-end Signed-off-by: Claire Wolf --- frontends/verilog/Makefile.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index 3725b58f656..2c923f0b74a 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -6,7 +6,7 @@ GENFILES += frontends/verilog/verilog_lexer.cc frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y $(Q) mkdir -p $(dir $@) - $(P) $(BISON) -Wall -Werror=conflicts-sr,error=conflicts-rr -o $@ -d -r all -b frontends/verilog/verilog_parser $< + $(P) $(BISON) -Wall -Werror -o $@ -d -r all -b frontends/verilog/verilog_parser $< frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc From d9f680b2363aded426465fd189910e0072228fee Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 16 Jul 2020 10:34:21 +0000 Subject: [PATCH 084/287] verilog_backend: add `-sv` option, make `-o .sv` work. See #2271. --- backends/verilog/verilog_backend.cc | 29 ++++++++++++++++++----------- kernel/yosys.cc | 2 ++ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index cef1dd9df48..e174a6ea498 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -33,7 +33,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, extmem, defparam, decimal, siminit; +bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, extmem, defparam, decimal, siminit, systemverilog; int auto_name_counter, auto_name_offset, auto_name_digits, extmem_counter; std::map auto_name_map; std::set reg_wires, reg_ct; @@ -617,7 +617,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) } dump_attributes(f, indent, cell->attributes); - f << stringf("%s" "always @(%sedge ", indent.c_str(), cell->type[6] == 'P' ? "pos" : "neg"); + f << stringf("%s" "always%s @(%sedge ", indent.c_str(), systemverilog ? "_ff" : "", cell->type[6] == 'P' ? "pos" : "neg"); dump_sigspec(f, cell->getPort(ID::C)); if (cell->type[7] != '_') { f << stringf(" or %sedge ", cell->type[7] == 'P' ? "pos" : "neg"); @@ -660,7 +660,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) } dump_attributes(f, indent, cell->attributes); - f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_c == 'P' ? "pos" : "neg"); + f << stringf("%s" "always%s @(%sedge ", indent.c_str(), systemverilog ? "_ff" : "", pol_c == 'P' ? "pos" : "neg"); dump_sigspec(f, cell->getPort(ID::C)); f << stringf(" or %sedge ", pol_s == 'P' ? "pos" : "neg"); dump_sigspec(f, cell->getPort(ID::S)); @@ -1009,7 +1009,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) } for (int i = 0; i < width; i++) { - f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg"); + f << stringf("%s" "always%s @(%sedge ", indent.c_str(), systemverilog ? "_ff" : "", pol_clk ? "pos" : "neg"); dump_sigspec(f, sig_clk); f << stringf(", %sedge ", pol_set ? "pos" : "neg"); dump_sigspec(f, sig_set); @@ -1067,7 +1067,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) f << ";\n"; } - f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg"); + f << stringf("%s" "always%s @(%sedge ", indent.c_str(), systemverilog ? "_ff" : "", pol_clk ? "pos" : "neg"); dump_sigspec(f, sig_clk); if (cell->type == ID($adff)) { f << stringf(" or %sedge ", pol_arst ? "pos" : "neg"); @@ -1121,7 +1121,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) f << ";\n"; } - f << stringf("%s" "always @*\n", indent.c_str()); + f << stringf("%s" "always%s\n", indent.c_str(), systemverilog ? "_latch" : " @*"); f << stringf("%s" " if (%s", indent.c_str(), pol_en ? "" : "!"); dump_sigspec(f, sig_en); @@ -1392,7 +1392,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) std::vector lof_lines = pair.second; if( clk_domain != "") { - f << stringf("%s" "always @(%s) begin\n", indent.c_str(), clk_domain.c_str()); + f << stringf("%s" "always%s @(%s) begin\n", indent.c_str(), systemverilog ? "_ff" : "", clk_domain.c_str()); for(auto &line : lof_lines) f << stringf("%s%s" "%s", indent.c_str(), indent.c_str(), line.c_str()); f << stringf("%s" "end\n", indent.c_str()); @@ -1410,7 +1410,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) if (cell->type.in(ID($assert), ID($assume), ID($cover))) { - f << stringf("%s" "always @* if (", indent.c_str()); + f << stringf("%s" "always%s if (", indent.c_str(), systemverilog ? "_comb" : " @*"); dump_sigspec(f, cell->getPort(ID::EN)); f << stringf(") %s(", cell->type.c_str()+1); dump_sigspec(f, cell->getPort(ID::A)); @@ -1717,7 +1717,7 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo return; } - f << stringf("%s" "always @* begin\n", indent.c_str()); + f << stringf("%s" "always%s begin\n", indent.c_str(), systemverilog ? "_comb" : " @*"); dump_case_body(f, indent, &proc->root_case, true); std::string backup_indent = indent; @@ -1728,11 +1728,11 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo indent = backup_indent; if (sync->type == RTLIL::STa) { - f << stringf("%s" "always @* begin\n", indent.c_str()); + f << stringf("%s" "always%s begin\n", indent.c_str(), systemverilog ? "_comb" : " @*"); } else if (sync->type == RTLIL::STi) { f << stringf("%s" "initial begin\n", indent.c_str()); } else { - f << stringf("%s" "always @(", indent.c_str()); + f << stringf("%s" "always%s @(", indent.c_str(), systemverilog ? "_ff" : ""); if (sync->type == RTLIL::STp || sync->type == RTLIL::ST1) f << stringf("posedge "); if (sync->type == RTLIL::STn || sync->type == RTLIL::ST0) @@ -1881,6 +1881,9 @@ struct VerilogBackend : public Backend { log("\n"); log("Write the current design to a Verilog file.\n"); log("\n"); + log(" -sv\n"); + log(" with this option, SystemVerilog constructs like always_comb are used\n"); + log("\n"); log(" -norename\n"); log(" without this option all internal object names (the ones with a dollar\n"); log(" instead of a backslash prefix) are changed to short names in the\n"); @@ -2007,6 +2010,10 @@ struct VerilogBackend : public Backend { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; + if (arg == "-sv") { + systemverilog = true; + continue; + } if (arg == "-norename") { norename = true; continue; diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 7e9f320e051..8986c8091ca 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -1050,6 +1050,8 @@ void run_backend(std::string filename, std::string command, RTLIL::Design *desig if (command == "auto") { if (filename.size() > 2 && filename.compare(filename.size()-2, std::string::npos, ".v") == 0) command = "verilog"; + else if (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".sv") == 0) + command = "verilog -sv"; else if (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0) command = "ilang"; else if (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".cc") == 0) From 128522f1737fc45dcc107381a167e59a79a48595 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 16 Jul 2020 11:26:31 +0000 Subject: [PATCH 085/287] verilog_backend: in non-SV mode, add a trigger for `always @*`. This commit only affects translation of RTLIL processes (for which there is limited support). Due to the event-driven nature of Verilog, processes like reg x; always @* x <= 1; may never execute. This can be fixed in SystemVerilog code by using `always_comb` instead of `always @*`, but in Verilog-2001 the options are limited. This commit implements the following workaround: reg init = 0; reg x; always @* begin if (init) begin end x <= 1; end Fixes #2271. --- 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 e174a6ea498..71f71554b07 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -1718,6 +1718,8 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo } f << stringf("%s" "always%s begin\n", indent.c_str(), systemverilog ? "_comb" : " @*"); + if (!systemverilog) + f << indent + " " << "if (" << id("\\initial") << ") begin end\n"; dump_case_body(f, indent, &proc->root_case, true); std::string backup_indent = indent; @@ -1850,6 +1852,9 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) } f << stringf(");\n"); + if (!systemverilog && !module->processes.empty()) + f << indent + " " << "reg " << id("\\initial") << " = 0;\n"; + for (auto w : module->wires()) dump_wire(f, indent + " ", w); From a4f7777e9dd916d5dfb7d76e899916805e0ad334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Fri, 17 Jul 2020 14:03:21 +0200 Subject: [PATCH 086/287] anlogic: Fix FF mapping. --- techlibs/anlogic/cells_map.v | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/techlibs/anlogic/cells_map.v b/techlibs/anlogic/cells_map.v index 000256fb9d2..d9f264ab177 100644 --- a/techlibs/anlogic/cells_map.v +++ b/techlibs/anlogic/cells_map.v @@ -1,17 +1,17 @@ -module \$_DFFE_PN0P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C) ,.ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_DFFE_PN1P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_DFFE_PP0P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_DFFE_PP1P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), . SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DFFE_PN0P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C) ,.ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DFFE_PN1P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("SET"), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DFFE_PP0P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("SR"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DFFE_PP1P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("SET"), .SRMUX("SR"), . SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_SDFFE_PN0P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C) ,.ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_SDFFE_PN1P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_SDFFE_PP0P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_SDFFE_PP1P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), . SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_SDFFE_PN0P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C) ,.ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_SDFFE_PN1P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("SET"), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_SDFFE_PP0P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("RESET"), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_SDFFE_PP1P_ (input D, C, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET("SET"), .SRMUX("SR"), . SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_DLATCH_NN0_ (input D, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("LATCH"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(E) ,.ce(1'b1), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_DLATCH_NN1_ (input D, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("LATCH"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(E), .ce(1'b1), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_DLATCH_NP0_ (input D, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("LATCH"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(E), .ce(1'b1), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$_DLATCH_NP1_ (input D, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("LATCH"), .REGSET(1'b1), .SRMUX("SR"), . SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(E), .ce(1'b1), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DLATCH_NN0_ (input D, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("LATCH"), .REGSET("RESET"), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(E) ,.ce(1'b1), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DLATCH_NN1_ (input D, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("LATCH"), .REGSET("SET"), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(E), .ce(1'b1), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DLATCH_NP0_ (input D, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("LATCH"), .REGSET("RESET"), .SRMUX("SR"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(E), .ce(1'b1), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule +module \$_DLATCH_NP1_ (input D, R, E, output Q); AL_MAP_SEQ #(.DFFMODE("LATCH"), .REGSET("SET"), .SRMUX("SR"), . SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(E), .ce(1'b1), .sr(R)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule `ifndef NO_LUT module \$lut (A, Y); From 1b95b0e570492c9ee9f221ccd362b5846a941749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Fri, 17 Jul 2020 15:01:45 +0200 Subject: [PATCH 087/287] sf2: Emit CLKINT even if -clkbuf not passed This restores pre #2229 behavior. --- techlibs/sf2/synth_sf2.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/techlibs/sf2/synth_sf2.cc b/techlibs/sf2/synth_sf2.cc index cd29a9c21e2..a0061ebd0fe 100644 --- a/techlibs/sf2/synth_sf2.cc +++ b/techlibs/sf2/synth_sf2.cc @@ -211,8 +211,12 @@ struct SynthSf2Pass : public ScriptPass if (check_label("map_iobs")) { if (help_mode || iobs) { - if (help_mode || clkbuf) { - run("clkbufmap -buf CLKINT Y:A -inpad CLKBUF Y:PAD", "(if -clkbuf, unless -noiobs)"); + if (help_mode) { + run("clkbufmap -buf CLKINT Y:A [-inpad CLKBUF Y:PAD]", "(unless -noiobs, -inpad only passed if -clkbuf)"); + } else if (clkbuf) { + run("clkbufmap -buf CLKINT Y:A -inpad CLKBUF Y:PAD"); + } else { + run("clkbufmap -buf CLKINT Y:A"); } run("iopadmap -bits -inpad INBUF Y:PAD -outpad OUTBUF D:PAD -toutpad TRIBUFF E:D:PAD -tinoutpad BIBUF E:Y:D:PAD", "(unless -noiobs"); } From 85a1bb17edca9ab105ae5e11aaa65b5a85c8fe86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Sun, 19 Jul 2020 00:17:02 +0200 Subject: [PATCH 088/287] satgen: Move importCell out of the header. This function has no hope of ever getting inlined anyway, and it speeds up yosys compile time by 7%. --- Makefile | 2 +- kernel/satgen.cc | 1188 ++++++++++++++++++++++++++++++++++++++++++++++ kernel/satgen.h | 1166 +-------------------------------------------- 3 files changed, 1190 insertions(+), 1166 deletions(-) create mode 100644 kernel/satgen.cc diff --git a/Makefile b/Makefile index ec8b38c480c..dfa4fb6a11e 100644 --- a/Makefile +++ b/Makefile @@ -600,7 +600,7 @@ $(eval $(call add_include_file,backends/cxxrtl/cxxrtl_vcd_capi.cc)) $(eval $(call add_include_file,backends/cxxrtl/cxxrtl_vcd_capi.h)) OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o -OBJS += kernel/cellaigs.o kernel/celledges.o +OBJS += kernel/cellaigs.o kernel/celledges.o kernel/satgen.o kernel/log.o: CXXFLAGS += -DYOSYS_SRC='"$(YOSYS_SRC)"' kernel/yosys.o: CXXFLAGS += -DYOSYS_DATDIR='"$(DATDIR)"' -DYOSYS_PROGRAM_PREFIX='"$(PROGRAM_PREFIX)"' diff --git a/kernel/satgen.cc b/kernel/satgen.cc new file mode 100644 index 00000000000..b90b43fb790 --- /dev/null +++ b/kernel/satgen.cc @@ -0,0 +1,1188 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/satgen.h" + +USING_YOSYS_NAMESPACE + +bool SatGen::importCell(RTLIL::Cell *cell, int timestep) +{ + bool arith_undef_handled = false; + bool is_arith_compare = cell->type.in(ID($lt), ID($le), ID($ge), ID($gt)); + + if (model_undef && (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor)) || is_arith_compare)) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + if (is_arith_compare) + extendSignalWidth(undef_a, undef_b, cell, true); + else + extendSignalWidth(undef_a, undef_b, undef_y, cell, true); + + int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); + int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); + int undef_y_bit = ez->OR(undef_any_a, undef_any_b); + + if (cell->type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor))) { + std::vector b = importSigSpec(cell->getPort(ID::B), timestep); + undef_y_bit = ez->OR(undef_y_bit, ez->NOT(ez->expression(ezSAT::OpOr, b))); + } + + if (is_arith_compare) { + for (size_t i = 1; i < undef_y.size(); i++) + ez->SET(ez->CONST_FALSE, undef_y.at(i)); + ez->SET(undef_y_bit, undef_y.at(0)); + } else { + std::vector undef_y_bits(undef_y.size(), undef_y_bit); + ez->assume(ez->vec_eq(undef_y_bits, undef_y)); + } + + arith_undef_handled = true; + } + + if (cell->type.in(ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_), + ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($sub))) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidth(a, b, y, cell); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + + if (cell->type.in(ID($and), ID($_AND_))) + ez->assume(ez->vec_eq(ez->vec_and(a, b), yy)); + if (cell->type == ID($_NAND_)) + ez->assume(ez->vec_eq(ez->vec_not(ez->vec_and(a, b)), yy)); + if (cell->type.in(ID($or), ID($_OR_))) + ez->assume(ez->vec_eq(ez->vec_or(a, b), yy)); + if (cell->type == ID($_NOR_)) + ez->assume(ez->vec_eq(ez->vec_not(ez->vec_or(a, b)), yy)); + if (cell->type.in(ID($xor), ID($_XOR_))) + ez->assume(ez->vec_eq(ez->vec_xor(a, b), yy)); + if (cell->type.in(ID($xnor), ID($_XNOR_))) + ez->assume(ez->vec_eq(ez->vec_not(ez->vec_xor(a, b)), yy)); + if (cell->type == ID($_ANDNOT_)) + ez->assume(ez->vec_eq(ez->vec_and(a, ez->vec_not(b)), yy)); + if (cell->type == ID($_ORNOT_)) + ez->assume(ez->vec_eq(ez->vec_or(a, ez->vec_not(b)), yy)); + if (cell->type == ID($add)) + ez->assume(ez->vec_eq(ez->vec_add(a, b), yy)); + if (cell->type == ID($sub)) + ez->assume(ez->vec_eq(ez->vec_sub(a, b), yy)); + + if (model_undef && !arith_undef_handled) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidth(undef_a, undef_b, undef_y, cell, false); + + if (cell->type.in(ID($and), ID($_AND_), ID($_NAND_))) { + std::vector a0 = ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a)); + std::vector b0 = ez->vec_and(ez->vec_not(b), ez->vec_not(undef_b)); + std::vector yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a0, b0))); + ez->assume(ez->vec_eq(yX, undef_y)); + } + else if (cell->type.in(ID($or), ID($_OR_), ID($_NOR_))) { + std::vector a1 = ez->vec_and(a, ez->vec_not(undef_a)); + std::vector b1 = ez->vec_and(b, ez->vec_not(undef_b)); + std::vector yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a1, b1))); + ez->assume(ez->vec_eq(yX, undef_y)); + } + else if (cell->type.in(ID($xor), ID($xnor), ID($_XOR_), ID($_XNOR_))) { + std::vector yX = ez->vec_or(undef_a, undef_b); + ez->assume(ez->vec_eq(yX, undef_y)); + } + else if (cell->type == ID($_ANDNOT_)) { + std::vector a0 = ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a)); + std::vector b1 = ez->vec_and(b, ez->vec_not(undef_b)); + std::vector yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a0, b1))); + ez->assume(ez->vec_eq(yX, undef_y)); + } + + else if (cell->type == ID($_ORNOT_)) { + std::vector a1 = ez->vec_and(a, ez->vec_not(undef_a)); + std::vector b0 = ez->vec_and(ez->vec_not(b), ez->vec_not(undef_b)); + std::vector yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a1, b0))); + ez->assume(ez->vec_eq(yX, undef_y)); + } + else + log_abort(); + + undefGating(y, yy, undef_y); + } + else if (model_undef) + { + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type.in(ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), ID($_OAI4_))) + { + bool aoi_mode = cell->type.in(ID($_AOI3_), ID($_AOI4_)); + bool three_mode = cell->type.in(ID($_AOI3_), ID($_OAI3_)); + + int a = importDefSigSpec(cell->getPort(ID::A), timestep).at(0); + int b = importDefSigSpec(cell->getPort(ID::B), timestep).at(0); + int c = importDefSigSpec(cell->getPort(ID::C), timestep).at(0); + int d = three_mode ? (aoi_mode ? ez->CONST_TRUE : ez->CONST_FALSE) : importDefSigSpec(cell->getPort(ID::D), timestep).at(0); + int y = importDefSigSpec(cell->getPort(ID::Y), timestep).at(0); + int yy = model_undef ? ez->literal() : y; + + if (cell->type.in(ID($_AOI3_), ID($_AOI4_))) + ez->assume(ez->IFF(ez->NOT(ez->OR(ez->AND(a, b), ez->AND(c, d))), yy)); + else + ez->assume(ez->IFF(ez->NOT(ez->AND(ez->OR(a, b), ez->OR(c, d))), yy)); + + if (model_undef) + { + int undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep).at(0); + int undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep).at(0); + int undef_c = importUndefSigSpec(cell->getPort(ID::C), timestep).at(0); + int undef_d = three_mode ? ez->CONST_FALSE : importUndefSigSpec(cell->getPort(ID::D), timestep).at(0); + int undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep).at(0); + + if (aoi_mode) + { + int a0 = ez->AND(ez->NOT(a), ez->NOT(undef_a)); + int b0 = ez->AND(ez->NOT(b), ez->NOT(undef_b)); + int c0 = ez->AND(ez->NOT(c), ez->NOT(undef_c)); + int d0 = ez->AND(ez->NOT(d), ez->NOT(undef_d)); + + int ab = ez->AND(a, b), cd = ez->AND(c, d); + int undef_ab = ez->AND(ez->OR(undef_a, undef_b), ez->NOT(ez->OR(a0, b0))); + int undef_cd = ez->AND(ez->OR(undef_c, undef_d), ez->NOT(ez->OR(c0, d0))); + + int ab1 = ez->AND(ab, ez->NOT(undef_ab)); + int cd1 = ez->AND(cd, ez->NOT(undef_cd)); + int yX = ez->AND(ez->OR(undef_ab, undef_cd), ez->NOT(ez->OR(ab1, cd1))); + + ez->assume(ez->IFF(yX, undef_y)); + } + else + { + int a1 = ez->AND(a, ez->NOT(undef_a)); + int b1 = ez->AND(b, ez->NOT(undef_b)); + int c1 = ez->AND(c, ez->NOT(undef_c)); + int d1 = ez->AND(d, ez->NOT(undef_d)); + + int ab = ez->OR(a, b), cd = ez->OR(c, d); + int undef_ab = ez->AND(ez->OR(undef_a, undef_b), ez->NOT(ez->OR(a1, b1))); + int undef_cd = ez->AND(ez->OR(undef_c, undef_d), ez->NOT(ez->OR(c1, d1))); + + int ab0 = ez->AND(ez->NOT(ab), ez->NOT(undef_ab)); + int cd0 = ez->AND(ez->NOT(cd), ez->NOT(undef_cd)); + int yX = ez->AND(ez->OR(undef_ab, undef_cd), ez->NOT(ez->OR(ab0, cd0))); + + ez->assume(ez->IFF(yX, undef_y)); + } + + undefGating(y, yy, undef_y); + } + + return true; + } + + if (cell->type.in(ID($_NOT_), ID($not))) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidthUnary(a, y, cell); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + ez->assume(ez->vec_eq(ez->vec_not(a), yy)); + + if (model_undef) { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidthUnary(undef_a, undef_y, cell, false); + ez->assume(ez->vec_eq(undef_a, undef_y)); + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type.in(ID($_MUX_), ID($mux), ID($_NMUX_))) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector s = importDefSigSpec(cell->getPort(ID::S), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + if (cell->type == ID($_NMUX_)) + ez->assume(ez->vec_eq(ez->vec_not(ez->vec_ite(s.at(0), b, a)), yy)); + else + ez->assume(ez->vec_eq(ez->vec_ite(s.at(0), b, a), yy)); + + if (model_undef) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_s = importUndefSigSpec(cell->getPort(ID::S), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + + std::vector unequal_ab = ez->vec_not(ez->vec_iff(a, b)); + std::vector undef_ab = ez->vec_or(unequal_ab, ez->vec_or(undef_a, undef_b)); + std::vector yX = ez->vec_ite(undef_s.at(0), undef_ab, ez->vec_ite(s.at(0), undef_b, undef_a)); + ez->assume(ez->vec_eq(yX, undef_y)); + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type == ID($pmux)) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector s = importDefSigSpec(cell->getPort(ID::S), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + + std::vector tmp = a; + for (size_t i = 0; i < s.size(); i++) { + std::vector part_of_b(b.begin()+i*a.size(), b.begin()+(i+1)*a.size()); + tmp = ez->vec_ite(s.at(i), part_of_b, tmp); + } + ez->assume(ez->vec_eq(tmp, yy)); + + if (model_undef) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_s = importUndefSigSpec(cell->getPort(ID::S), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + + int maybe_a = ez->CONST_TRUE; + + std::vector bits_set = std::vector(undef_y.size(), ez->CONST_FALSE); + std::vector bits_clr = std::vector(undef_y.size(), ez->CONST_FALSE); + + for (size_t i = 0; i < s.size(); i++) + { + std::vector part_of_b(b.begin()+i*a.size(), b.begin()+(i+1)*a.size()); + std::vector part_of_undef_b(undef_b.begin()+i*a.size(), undef_b.begin()+(i+1)*a.size()); + + int maybe_s = ez->OR(s.at(i), undef_s.at(i)); + int sure_s = ez->AND(s.at(i), ez->NOT(undef_s.at(i))); + + maybe_a = ez->AND(maybe_a, ez->NOT(sure_s)); + + bits_set = ez->vec_ite(maybe_s, ez->vec_or(bits_set, ez->vec_or(part_of_b, part_of_undef_b)), bits_set); + bits_clr = ez->vec_ite(maybe_s, ez->vec_or(bits_clr, ez->vec_or(ez->vec_not(part_of_b), part_of_undef_b)), bits_clr); + } + + bits_set = ez->vec_ite(maybe_a, ez->vec_or(bits_set, ez->vec_or(bits_set, ez->vec_or(a, undef_a))), bits_set); + bits_clr = ez->vec_ite(maybe_a, ez->vec_or(bits_clr, ez->vec_or(bits_clr, ez->vec_or(ez->vec_not(a), undef_a))), bits_clr); + + ez->assume(ez->vec_eq(ez->vec_not(ez->vec_xor(bits_set, bits_clr)), undef_y)); + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type.in(ID($pos), ID($neg))) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidthUnary(a, y, cell); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + + if (cell->type == ID($pos)) { + ez->assume(ez->vec_eq(a, yy)); + } else { + std::vector zero(a.size(), ez->CONST_FALSE); + ez->assume(ez->vec_eq(ez->vec_sub(zero, a), yy)); + } + + if (model_undef) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidthUnary(undef_a, undef_y, cell); + + if (cell->type == ID($pos)) { + ez->assume(ez->vec_eq(undef_a, undef_y)); + } else { + int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); + std::vector undef_y_bits(undef_y.size(), undef_any_a); + ez->assume(ez->vec_eq(undef_y_bits, undef_y)); + } + + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($logic_not))) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + + if (cell->type == ID($reduce_and)) + ez->SET(ez->expression(ez->OpAnd, a), yy.at(0)); + if (cell->type.in(ID($reduce_or), ID($reduce_bool))) + ez->SET(ez->expression(ez->OpOr, a), yy.at(0)); + if (cell->type == ID($reduce_xor)) + ez->SET(ez->expression(ez->OpXor, a), yy.at(0)); + if (cell->type == ID($reduce_xnor)) + ez->SET(ez->NOT(ez->expression(ez->OpXor, a)), yy.at(0)); + if (cell->type == ID($logic_not)) + ez->SET(ez->NOT(ez->expression(ez->OpOr, a)), yy.at(0)); + for (size_t i = 1; i < y.size(); i++) + ez->SET(ez->CONST_FALSE, yy.at(i)); + + if (model_undef) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + int aX = ez->expression(ezSAT::OpOr, undef_a); + + if (cell->type == ID($reduce_and)) { + int a0 = ez->expression(ezSAT::OpOr, ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a))); + ez->assume(ez->IFF(ez->AND(ez->NOT(a0), aX), undef_y.at(0))); + } + else if (cell->type.in(ID($reduce_or), ID($reduce_bool), ID($logic_not))) { + int a1 = ez->expression(ezSAT::OpOr, ez->vec_and(a, ez->vec_not(undef_a))); + ez->assume(ez->IFF(ez->AND(ez->NOT(a1), aX), undef_y.at(0))); + } + else if (cell->type.in(ID($reduce_xor), ID($reduce_xnor))) { + ez->assume(ez->IFF(aX, undef_y.at(0))); + } else + log_abort(); + + for (size_t i = 1; i < undef_y.size(); i++) + ez->SET(ez->CONST_FALSE, undef_y.at(i)); + + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type.in(ID($logic_and), ID($logic_or))) + { + std::vector vec_a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector vec_b = importDefSigSpec(cell->getPort(ID::B), timestep); + + int a = ez->expression(ez->OpOr, vec_a); + int b = ez->expression(ez->OpOr, vec_b); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + + if (cell->type == ID($logic_and)) + ez->SET(ez->expression(ez->OpAnd, a, b), yy.at(0)); + else + ez->SET(ez->expression(ez->OpOr, a, b), yy.at(0)); + for (size_t i = 1; i < y.size(); i++) + ez->SET(ez->CONST_FALSE, yy.at(i)); + + if (model_undef) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + + int a0 = ez->NOT(ez->OR(ez->expression(ezSAT::OpOr, vec_a), ez->expression(ezSAT::OpOr, undef_a))); + int b0 = ez->NOT(ez->OR(ez->expression(ezSAT::OpOr, vec_b), ez->expression(ezSAT::OpOr, undef_b))); + int a1 = ez->expression(ezSAT::OpOr, ez->vec_and(vec_a, ez->vec_not(undef_a))); + int b1 = ez->expression(ezSAT::OpOr, ez->vec_and(vec_b, ez->vec_not(undef_b))); + int aX = ez->expression(ezSAT::OpOr, undef_a); + int bX = ez->expression(ezSAT::OpOr, undef_b); + + if (cell->type == ID($logic_and)) + ez->SET(ez->AND(ez->OR(aX, bX), ez->NOT(ez->AND(a1, b1)), ez->NOT(a0), ez->NOT(b0)), undef_y.at(0)); + else if (cell->type == ID($logic_or)) + ez->SET(ez->AND(ez->OR(aX, bX), ez->NOT(ez->AND(a0, b0)), ez->NOT(a1), ez->NOT(b1)), undef_y.at(0)); + else + log_abort(); + + for (size_t i = 1; i < undef_y.size(); i++) + ez->SET(ez->CONST_FALSE, undef_y.at(i)); + + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type.in(ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt))) + { + bool is_signed = cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool(); + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidth(a, b, cell); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + + if (model_undef && cell->type.in(ID($eqx), ID($nex))) { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + extendSignalWidth(undef_a, undef_b, cell, true); + a = ez->vec_or(a, undef_a); + b = ez->vec_or(b, undef_b); + } + + if (cell->type == ID($lt)) + ez->SET(is_signed ? ez->vec_lt_signed(a, b) : ez->vec_lt_unsigned(a, b), yy.at(0)); + if (cell->type == ID($le)) + ez->SET(is_signed ? ez->vec_le_signed(a, b) : ez->vec_le_unsigned(a, b), yy.at(0)); + if (cell->type.in(ID($eq), ID($eqx))) + ez->SET(ez->vec_eq(a, b), yy.at(0)); + if (cell->type.in(ID($ne), ID($nex))) + ez->SET(ez->vec_ne(a, b), yy.at(0)); + if (cell->type == ID($ge)) + ez->SET(is_signed ? ez->vec_ge_signed(a, b) : ez->vec_ge_unsigned(a, b), yy.at(0)); + if (cell->type == ID($gt)) + ez->SET(is_signed ? ez->vec_gt_signed(a, b) : ez->vec_gt_unsigned(a, b), yy.at(0)); + for (size_t i = 1; i < y.size(); i++) + ez->SET(ez->CONST_FALSE, yy.at(i)); + + if (model_undef && cell->type.in(ID($eqx), ID($nex))) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidth(undef_a, undef_b, cell, true); + + if (cell->type == ID($eqx)) + yy.at(0) = ez->AND(yy.at(0), ez->vec_eq(undef_a, undef_b)); + else + yy.at(0) = ez->OR(yy.at(0), ez->vec_ne(undef_a, undef_b)); + + for (size_t i = 0; i < y.size(); i++) + ez->SET(ez->CONST_FALSE, undef_y.at(i)); + + ez->assume(ez->vec_eq(y, yy)); + } + else if (model_undef && cell->type.in(ID($eq), ID($ne))) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidth(undef_a, undef_b, cell, true); + + int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); + int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); + int undef_any = ez->OR(undef_any_a, undef_any_b); + + std::vector masked_a_bits = ez->vec_or(a, ez->vec_or(undef_a, undef_b)); + std::vector masked_b_bits = ez->vec_or(b, ez->vec_or(undef_a, undef_b)); + + int masked_ne = ez->vec_ne(masked_a_bits, masked_b_bits); + int undef_y_bit = ez->AND(undef_any, ez->NOT(masked_ne)); + + for (size_t i = 1; i < undef_y.size(); i++) + ez->SET(ez->CONST_FALSE, undef_y.at(i)); + ez->SET(undef_y_bit, undef_y.at(0)); + + undefGating(y, yy, undef_y); + } + else + { + if (model_undef) { + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + undefGating(y, yy, undef_y); + } + log_assert(!model_undef || arith_undef_handled); + } + return true; + } + + if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + + int extend_bit = ez->CONST_FALSE; + + if (!cell->type.in(ID($shift), ID($shiftx)) && cell->parameters[ID::A_SIGNED].as_bool()) + extend_bit = a.back(); + + while (y.size() < a.size()) + y.push_back(ez->literal()); + while (y.size() > a.size()) + a.push_back(extend_bit); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + std::vector shifted_a; + + if (cell->type.in( ID($shl), ID($sshl))) + shifted_a = ez->vec_shift_left(a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); + + if (cell->type == ID($shr)) + shifted_a = ez->vec_shift_right(a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); + + if (cell->type == ID($sshr)) + shifted_a = ez->vec_shift_right(a, b, false, cell->parameters[ID::A_SIGNED].as_bool() ? a.back() : ez->CONST_FALSE, ez->CONST_FALSE); + + if (cell->type.in(ID($shift), ID($shiftx))) + shifted_a = ez->vec_shift_right(a, b, cell->parameters[ID::B_SIGNED].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE); + + ez->assume(ez->vec_eq(shifted_a, yy)); + + if (model_undef) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + std::vector undef_a_shifted; + + extend_bit = cell->type == ID($shiftx) ? ez->CONST_TRUE : ez->CONST_FALSE; + if (!cell->type.in(ID($shift), ID($shiftx)) && cell->parameters[ID::A_SIGNED].as_bool()) + extend_bit = undef_a.back(); + + while (undef_y.size() < undef_a.size()) + undef_y.push_back(ez->literal()); + while (undef_y.size() > undef_a.size()) + undef_a.push_back(extend_bit); + + if (cell->type.in(ID($shl), ID($sshl))) + undef_a_shifted = ez->vec_shift_left(undef_a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); + + if (cell->type == ID($shr)) + undef_a_shifted = ez->vec_shift_right(undef_a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); + + if (cell->type == ID($sshr)) + undef_a_shifted = ez->vec_shift_right(undef_a, b, false, cell->parameters[ID::A_SIGNED].as_bool() ? undef_a.back() : ez->CONST_FALSE, ez->CONST_FALSE); + + if (cell->type == ID($shift)) + undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters[ID::B_SIGNED].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE); + + if (cell->type == ID($shiftx)) + undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters[ID::B_SIGNED].as_bool(), ez->CONST_TRUE, ez->CONST_TRUE); + + int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); + std::vector undef_all_y_bits(undef_y.size(), undef_any_b); + ez->assume(ez->vec_eq(ez->vec_or(undef_a_shifted, undef_all_y_bits), undef_y)); + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type == ID($mul)) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidth(a, b, y, cell); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + + std::vector tmp(a.size(), ez->CONST_FALSE); + for (int i = 0; i < int(a.size()); i++) + { + std::vector shifted_a(a.size(), ez->CONST_FALSE); + for (int j = i; j < int(a.size()); j++) + shifted_a.at(j) = a.at(j-i); + tmp = ez->vec_ite(b.at(i), ez->vec_add(tmp, shifted_a), tmp); + } + ez->assume(ez->vec_eq(tmp, yy)); + + if (model_undef) { + log_assert(arith_undef_handled); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type == ID($macc)) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + + Macc macc; + macc.from_cell(cell); + + std::vector tmp(GetSize(y), ez->CONST_FALSE); + + for (auto &port : macc.ports) + { + std::vector in_a = importDefSigSpec(port.in_a, timestep); + std::vector in_b = importDefSigSpec(port.in_b, timestep); + + while (GetSize(in_a) < GetSize(y)) + in_a.push_back(port.is_signed && !in_a.empty() ? in_a.back() : ez->CONST_FALSE); + in_a.resize(GetSize(y)); + + if (GetSize(in_b)) + { + while (GetSize(in_b) < GetSize(y)) + in_b.push_back(port.is_signed && !in_b.empty() ? in_b.back() : ez->CONST_FALSE); + in_b.resize(GetSize(y)); + + for (int i = 0; i < GetSize(in_b); i++) { + std::vector shifted_a(in_a.size(), ez->CONST_FALSE); + for (int j = i; j < int(in_a.size()); j++) + shifted_a.at(j) = in_a.at(j-i); + if (port.do_subtract) + tmp = ez->vec_ite(in_b.at(i), ez->vec_sub(tmp, shifted_a), tmp); + else + tmp = ez->vec_ite(in_b.at(i), ez->vec_add(tmp, shifted_a), tmp); + } + } + else + { + if (port.do_subtract) + tmp = ez->vec_sub(tmp, in_a); + else + tmp = ez->vec_add(tmp, in_a); + } + } + + for (int i = 0; i < GetSize(b); i++) { + std::vector val(GetSize(y), ez->CONST_FALSE); + val.at(0) = b.at(i); + tmp = ez->vec_add(tmp, val); + } + + if (model_undef) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + + int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); + int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); + + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + ez->assume(ez->vec_eq(undef_y, std::vector(GetSize(y), ez->OR(undef_any_a, undef_any_b)))); + + undefGating(y, tmp, undef_y); + } + else + ez->assume(ez->vec_eq(y, tmp)); + + return true; + } + + if (cell->type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor))) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidth(a, b, y, cell); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + + std::vector a_u, b_u; + if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) { + a_u = ez->vec_ite(a.back(), ez->vec_neg(a), a); + b_u = ez->vec_ite(b.back(), ez->vec_neg(b), b); + } else { + a_u = a; + b_u = b; + } + + std::vector chain_buf = a_u; + std::vector y_u(a_u.size(), ez->CONST_FALSE); + for (int i = int(a.size())-1; i >= 0; i--) + { + chain_buf.insert(chain_buf.end(), chain_buf.size(), ez->CONST_FALSE); + + std::vector b_shl(i, ez->CONST_FALSE); + b_shl.insert(b_shl.end(), b_u.begin(), b_u.end()); + b_shl.insert(b_shl.end(), chain_buf.size()-b_shl.size(), ez->CONST_FALSE); + + y_u.at(i) = ez->vec_ge_unsigned(chain_buf, b_shl); + chain_buf = ez->vec_ite(y_u.at(i), ez->vec_sub(chain_buf, b_shl), chain_buf); + + chain_buf.erase(chain_buf.begin() + a_u.size(), chain_buf.end()); + } + + std::vector y_tmp = ignore_div_by_zero ? yy : ez->vec_var(y.size()); + + // modulo calculation + std::vector modulo_trunc; + int floored_eq_trunc; + if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) { + modulo_trunc = ez->vec_ite(a.back(), ez->vec_neg(chain_buf), chain_buf); + // floor == trunc when sgn(a) == sgn(b) or trunc == 0 + floored_eq_trunc = ez->OR(ez->IFF(a.back(), b.back()), ez->NOT(ez->expression(ezSAT::OpOr, modulo_trunc))); + } else { + modulo_trunc = chain_buf; + floored_eq_trunc = ez->CONST_TRUE; + } + + if (cell->type == ID($div)) { + if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) + ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(ez->XOR(a.back(), b.back()), ez->vec_neg(y_u), y_u))); + else + ez->assume(ez->vec_eq(y_tmp, y_u)); + } else if (cell->type == ID($mod)) { + ez->assume(ez->vec_eq(y_tmp, modulo_trunc)); + } else if (cell->type == ID($divfloor)) { + if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) + ez->assume(ez->vec_eq(y_tmp, ez->vec_ite( + ez->XOR(a.back(), b.back()), + ez->vec_neg(ez->vec_ite( + ez->vec_reduce_or(modulo_trunc), + ez->vec_add(y_u, ez->vec_const_unsigned(1, y_u.size())), + y_u + )), + y_u + ))); + else + ez->assume(ez->vec_eq(y_tmp, y_u)); + } else if (cell->type == ID($modfloor)) { + ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(floored_eq_trunc, modulo_trunc, ez->vec_add(modulo_trunc, b)))); + } + + if (ignore_div_by_zero) { + ez->assume(ez->expression(ezSAT::OpOr, b)); + } else { + std::vector div_zero_result; + if (cell->type.in(ID($div), ID($divfloor))) { + if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) { + std::vector all_ones(y.size(), ez->CONST_TRUE); + std::vector only_first_one(y.size(), ez->CONST_FALSE); + only_first_one.at(0) = ez->CONST_TRUE; + div_zero_result = ez->vec_ite(a.back(), only_first_one, all_ones); + } else { + div_zero_result.insert(div_zero_result.end(), cell->getPort(ID::A).size(), ez->CONST_TRUE); + div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE); + } + } else if (cell->type.in(ID($mod), ID($modfloor))) { + // a mod 0 = a + int copy_a_bits = min(cell->getPort(ID::A).size(), cell->getPort(ID::B).size()); + div_zero_result.insert(div_zero_result.end(), a.begin(), a.begin() + copy_a_bits); + if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) + div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), div_zero_result.back()); + else + div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE); + } + ez->assume(ez->vec_eq(yy, ez->vec_ite(ez->expression(ezSAT::OpOr, b), y_tmp, div_zero_result))); + } + + if (model_undef) { + log_assert(arith_undef_handled); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type == ID($lut)) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + + std::vector lut; + for (auto bit : cell->getParam(ID::LUT).bits) + lut.push_back(bit == State::S1 ? ez->CONST_TRUE : ez->CONST_FALSE); + while (GetSize(lut) < (1 << GetSize(a))) + lut.push_back(ez->CONST_FALSE); + lut.resize(1 << GetSize(a)); + + if (model_undef) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector t(lut), u(GetSize(t), ez->CONST_FALSE); + + for (int i = GetSize(a)-1; i >= 0; i--) + { + std::vector t0(t.begin(), t.begin() + GetSize(t)/2); + std::vector t1(t.begin() + GetSize(t)/2, t.end()); + + std::vector u0(u.begin(), u.begin() + GetSize(u)/2); + std::vector u1(u.begin() + GetSize(u)/2, u.end()); + + t = ez->vec_ite(a[i], t1, t0); + u = ez->vec_ite(undef_a[i], ez->vec_or(ez->vec_xor(t0, t1), ez->vec_or(u0, u1)), ez->vec_ite(a[i], u1, u0)); + } + + log_assert(GetSize(t) == 1); + log_assert(GetSize(u) == 1); + undefGating(y, t, u); + ez->assume(ez->vec_eq(importUndefSigSpec(cell->getPort(ID::Y), timestep), u)); + } + else + { + std::vector t = lut; + for (int i = GetSize(a)-1; i >= 0; i--) + { + std::vector t0(t.begin(), t.begin() + GetSize(t)/2); + std::vector t1(t.begin() + GetSize(t)/2, t.end()); + t = ez->vec_ite(a[i], t1, t0); + } + + log_assert(GetSize(t) == 1); + ez->assume(ez->vec_eq(y, t)); + } + return true; + } + + if (cell->type == ID($sop)) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + int y = importDefSigSpec(cell->getPort(ID::Y), timestep).at(0); + + int width = cell->getParam(ID::WIDTH).as_int(); + int depth = cell->getParam(ID::DEPTH).as_int(); + + vector table_raw = cell->getParam(ID::TABLE).bits; + while (GetSize(table_raw) < 2*width*depth) + table_raw.push_back(State::S0); + + vector> table(depth); + + for (int i = 0; i < depth; i++) + for (int j = 0; j < width; j++) + { + bool pat0 = (table_raw[2*width*i + 2*j + 0] == State::S1); + bool pat1 = (table_raw[2*width*i + 2*j + 1] == State::S1); + + if (pat0 && !pat1) + table.at(i).push_back(0); + else if (!pat0 && pat1) + table.at(i).push_back(1); + else + table.at(i).push_back(-1); + } + + if (model_undef) + { + std::vector products, undef_products; + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + int undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep).at(0); + + for (int i = 0; i < depth; i++) + { + std::vector cmp_a, cmp_ua, cmp_b; + + for (int j = 0; j < width; j++) + if (table.at(i).at(j) >= 0) { + cmp_a.push_back(a.at(j)); + cmp_ua.push_back(undef_a.at(j)); + cmp_b.push_back(table.at(i).at(j) ? ez->CONST_TRUE : ez->CONST_FALSE); + } + + std::vector masked_a = ez->vec_or(cmp_a, cmp_ua); + std::vector masked_b = ez->vec_or(cmp_b, cmp_ua); + + int masked_eq = ez->vec_eq(masked_a, masked_b); + int any_undef = ez->expression(ezSAT::OpOr, cmp_ua); + + undef_products.push_back(ez->AND(any_undef, masked_eq)); + products.push_back(ez->AND(ez->NOT(any_undef), masked_eq)); + } + + int yy = ez->expression(ezSAT::OpOr, products); + ez->SET(undef_y, ez->AND(ez->NOT(yy), ez->expression(ezSAT::OpOr, undef_products))); + undefGating(y, yy, undef_y); + } + else + { + std::vector products; + + for (int i = 0; i < depth; i++) + { + std::vector cmp_a, cmp_b; + + for (int j = 0; j < width; j++) + if (table.at(i).at(j) >= 0) { + cmp_a.push_back(a.at(j)); + cmp_b.push_back(table.at(i).at(j) ? ez->CONST_TRUE : ez->CONST_FALSE); + } + + products.push_back(ez->vec_eq(cmp_a, cmp_b)); + } + + ez->SET(y, ez->expression(ezSAT::OpOr, products)); + } + + return true; + } + + if (cell->type == ID($fa)) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector c = importDefSigSpec(cell->getPort(ID::C), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + std::vector x = importDefSigSpec(cell->getPort(ID::X), timestep); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + std::vector xx = model_undef ? ez->vec_var(x.size()) : x; + + std::vector t1 = ez->vec_xor(a, b); + ez->assume(ez->vec_eq(yy, ez->vec_xor(t1, c))); + + std::vector t2 = ez->vec_and(a, b); + std::vector t3 = ez->vec_and(c, t1); + ez->assume(ez->vec_eq(xx, ez->vec_or(t2, t3))); + + if (model_undef) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_c = importUndefSigSpec(cell->getPort(ID::C), timestep); + + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + std::vector undef_x = importUndefSigSpec(cell->getPort(ID::X), timestep); + + ez->assume(ez->vec_eq(undef_y, ez->vec_or(ez->vec_or(undef_a, undef_b), undef_c))); + ez->assume(ez->vec_eq(undef_x, undef_y)); + + undefGating(y, yy, undef_y); + undefGating(x, xx, undef_x); + } + return true; + } + + if (cell->type == ID($lcu)) + { + std::vector p = importDefSigSpec(cell->getPort(ID::P), timestep); + std::vector g = importDefSigSpec(cell->getPort(ID::G), timestep); + std::vector ci = importDefSigSpec(cell->getPort(ID::CI), timestep); + std::vector co = importDefSigSpec(cell->getPort(ID::CO), timestep); + + std::vector yy = model_undef ? ez->vec_var(co.size()) : co; + + for (int i = 0; i < GetSize(co); i++) + ez->SET(yy[i], ez->OR(g[i], ez->AND(p[i], i ? yy[i-1] : ci[0]))); + + if (model_undef) + { + std::vector undef_p = importUndefSigSpec(cell->getPort(ID::P), timestep); + std::vector undef_g = importUndefSigSpec(cell->getPort(ID::G), timestep); + std::vector undef_ci = importUndefSigSpec(cell->getPort(ID::CI), timestep); + std::vector undef_co = importUndefSigSpec(cell->getPort(ID::CO), timestep); + + int undef_any_p = ez->expression(ezSAT::OpOr, undef_p); + int undef_any_g = ez->expression(ezSAT::OpOr, undef_g); + int undef_any_ci = ez->expression(ezSAT::OpOr, undef_ci); + int undef_co_bit = ez->OR(undef_any_p, undef_any_g, undef_any_ci); + + std::vector undef_co_bits(undef_co.size(), undef_co_bit); + ez->assume(ez->vec_eq(undef_co_bits, undef_co)); + + undefGating(co, yy, undef_co); + } + return true; + } + + if (cell->type == ID($alu)) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + std::vector x = importDefSigSpec(cell->getPort(ID::X), timestep); + std::vector ci = importDefSigSpec(cell->getPort(ID::CI), timestep); + std::vector bi = importDefSigSpec(cell->getPort(ID::BI), timestep); + std::vector co = importDefSigSpec(cell->getPort(ID::CO), timestep); + + extendSignalWidth(a, b, y, cell); + extendSignalWidth(a, b, x, cell); + extendSignalWidth(a, b, co, cell); + + std::vector def_y = model_undef ? ez->vec_var(y.size()) : y; + std::vector def_x = model_undef ? ez->vec_var(x.size()) : x; + std::vector def_co = model_undef ? ez->vec_var(co.size()) : co; + + log_assert(GetSize(y) == GetSize(x)); + log_assert(GetSize(y) == GetSize(co)); + log_assert(GetSize(ci) == 1); + log_assert(GetSize(bi) == 1); + + for (int i = 0; i < GetSize(y); i++) + { + int s1 = a.at(i), s2 = ez->XOR(b.at(i), bi.at(0)), s3 = i ? co.at(i-1) : ci.at(0); + ez->SET(def_x.at(i), ez->XOR(s1, s2)); + ez->SET(def_y.at(i), ez->XOR(def_x.at(i), s3)); + ez->SET(def_co.at(i), ez->OR(ez->AND(s1, s2), ez->AND(s1, s3), ez->AND(s2, s3))); + } + + if (model_undef) + { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_ci = importUndefSigSpec(cell->getPort(ID::CI), timestep); + std::vector undef_bi = importUndefSigSpec(cell->getPort(ID::BI), timestep); + + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + std::vector undef_x = importUndefSigSpec(cell->getPort(ID::X), timestep); + std::vector undef_co = importUndefSigSpec(cell->getPort(ID::CO), timestep); + + extendSignalWidth(undef_a, undef_b, undef_y, cell); + extendSignalWidth(undef_a, undef_b, undef_x, cell); + extendSignalWidth(undef_a, undef_b, undef_co, cell); + + std::vector all_inputs_undef; + all_inputs_undef.insert(all_inputs_undef.end(), undef_a.begin(), undef_a.end()); + all_inputs_undef.insert(all_inputs_undef.end(), undef_b.begin(), undef_b.end()); + all_inputs_undef.insert(all_inputs_undef.end(), undef_ci.begin(), undef_ci.end()); + all_inputs_undef.insert(all_inputs_undef.end(), undef_bi.begin(), undef_bi.end()); + int undef_any = ez->expression(ezSAT::OpOr, all_inputs_undef); + + for (int i = 0; i < GetSize(undef_y); i++) { + ez->SET(undef_y.at(i), undef_any); + ez->SET(undef_x.at(i), ez->OR(undef_a.at(i), undef_b.at(i), undef_bi.at(0))); + ez->SET(undef_co.at(i), undef_any); + } + + undefGating(y, def_y, undef_y); + undefGating(x, def_x, undef_x); + undefGating(co, def_co, undef_co); + } + return true; + } + + if (cell->type == ID($slice)) + { + RTLIL::SigSpec a = cell->getPort(ID::A); + RTLIL::SigSpec y = cell->getPort(ID::Y); + ez->assume(signals_eq(a.extract(cell->parameters.at(ID::OFFSET).as_int(), y.size()), y, timestep)); + return true; + } + + if (cell->type == ID($concat)) + { + RTLIL::SigSpec a = cell->getPort(ID::A); + RTLIL::SigSpec b = cell->getPort(ID::B); + RTLIL::SigSpec y = cell->getPort(ID::Y); + + RTLIL::SigSpec ab = a; + ab.append(b); + + ez->assume(signals_eq(ab, y, timestep)); + return true; + } + + if (timestep > 0 && cell->type.in(ID($ff), ID($dff), ID($_FF_), ID($_DFF_N_), ID($_DFF_P_))) + { + if (timestep == 1) + { + initial_state.add((*sigmap)(cell->getPort(ID::Q))); + } + else + { + std::vector d = importDefSigSpec(cell->getPort(ID::D), timestep-1); + std::vector q = importDefSigSpec(cell->getPort(ID::Q), timestep); + + std::vector qq = model_undef ? ez->vec_var(q.size()) : q; + ez->assume(ez->vec_eq(d, qq)); + + if (model_undef) + { + std::vector undef_d = importUndefSigSpec(cell->getPort(ID::D), timestep-1); + std::vector undef_q = importUndefSigSpec(cell->getPort(ID::Q), timestep); + + ez->assume(ez->vec_eq(undef_d, undef_q)); + undefGating(q, qq, undef_q); + } + } + return true; + } + + if (cell->type == ID($anyconst)) + { + if (timestep < 2) + return true; + + std::vector d = importDefSigSpec(cell->getPort(ID::Y), timestep-1); + std::vector q = importDefSigSpec(cell->getPort(ID::Y), timestep); + + std::vector qq = model_undef ? ez->vec_var(q.size()) : q; + ez->assume(ez->vec_eq(d, qq)); + + if (model_undef) + { + std::vector undef_d = importUndefSigSpec(cell->getPort(ID::Y), timestep-1); + std::vector undef_q = importUndefSigSpec(cell->getPort(ID::Y), timestep); + + ez->assume(ez->vec_eq(undef_d, undef_q)); + undefGating(q, qq, undef_q); + } + return true; + } + + if (cell->type == ID($anyseq)) + { + return true; + } + + if (cell->type.in(ID($_BUF_), ID($equiv))) + { + std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidthUnary(a, y, cell); + + std::vector yy = model_undef ? ez->vec_var(y.size()) : y; + ez->assume(ez->vec_eq(a, yy)); + + if (model_undef) { + std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + extendSignalWidthUnary(undef_a, undef_y, cell, false); + ez->assume(ez->vec_eq(undef_a, undef_y)); + undefGating(y, yy, undef_y); + } + return true; + } + + if (cell->type == ID($initstate)) + { + auto key = make_pair(prefix, timestep); + if (initstates.count(key) == 0) + initstates[key] = false; + + std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); + log_assert(GetSize(y) == 1); + ez->SET(y[0], initstates[key] ? ez->CONST_TRUE : ez->CONST_FALSE); + + if (model_undef) { + std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + log_assert(GetSize(undef_y) == 1); + ez->SET(undef_y[0], ez->CONST_FALSE); + } + + return true; + } + + if (cell->type == ID($assert)) + { + std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); + asserts_a[pf].append((*sigmap)(cell->getPort(ID::A))); + asserts_en[pf].append((*sigmap)(cell->getPort(ID::EN))); + return true; + } + + if (cell->type == ID($assume)) + { + std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); + assumes_a[pf].append((*sigmap)(cell->getPort(ID::A))); + assumes_en[pf].append((*sigmap)(cell->getPort(ID::EN))); + return true; + } + + // Unsupported internal cell types: $pow $lut + // .. and all sequential cells except $dff and $_DFF_[NP]_ + return false; +} diff --git a/kernel/satgen.h b/kernel/satgen.h index 3929a87081f..bd6259ba145 100644 --- a/kernel/satgen.h +++ b/kernel/satgen.h @@ -274,1171 +274,7 @@ struct SatGen initstates[key] = true; } - bool importCell(RTLIL::Cell *cell, int timestep = -1) - { - bool arith_undef_handled = false; - bool is_arith_compare = cell->type.in(ID($lt), ID($le), ID($ge), ID($gt)); - - if (model_undef && (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor)) || is_arith_compare)) - { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - if (is_arith_compare) - extendSignalWidth(undef_a, undef_b, cell, true); - else - extendSignalWidth(undef_a, undef_b, undef_y, cell, true); - - int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); - int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); - int undef_y_bit = ez->OR(undef_any_a, undef_any_b); - - if (cell->type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor))) { - std::vector b = importSigSpec(cell->getPort(ID::B), timestep); - undef_y_bit = ez->OR(undef_y_bit, ez->NOT(ez->expression(ezSAT::OpOr, b))); - } - - if (is_arith_compare) { - for (size_t i = 1; i < undef_y.size(); i++) - ez->SET(ez->CONST_FALSE, undef_y.at(i)); - ez->SET(undef_y_bit, undef_y.at(0)); - } else { - std::vector undef_y_bits(undef_y.size(), undef_y_bit); - ez->assume(ez->vec_eq(undef_y_bits, undef_y)); - } - - arith_undef_handled = true; - } - - if (cell->type.in(ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_), - ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($sub))) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - extendSignalWidth(a, b, y, cell); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - - if (cell->type.in(ID($and), ID($_AND_))) - ez->assume(ez->vec_eq(ez->vec_and(a, b), yy)); - if (cell->type == ID($_NAND_)) - ez->assume(ez->vec_eq(ez->vec_not(ez->vec_and(a, b)), yy)); - if (cell->type.in(ID($or), ID($_OR_))) - ez->assume(ez->vec_eq(ez->vec_or(a, b), yy)); - if (cell->type == ID($_NOR_)) - ez->assume(ez->vec_eq(ez->vec_not(ez->vec_or(a, b)), yy)); - if (cell->type.in(ID($xor), ID($_XOR_))) - ez->assume(ez->vec_eq(ez->vec_xor(a, b), yy)); - if (cell->type.in(ID($xnor), ID($_XNOR_))) - ez->assume(ez->vec_eq(ez->vec_not(ez->vec_xor(a, b)), yy)); - if (cell->type == ID($_ANDNOT_)) - ez->assume(ez->vec_eq(ez->vec_and(a, ez->vec_not(b)), yy)); - if (cell->type == ID($_ORNOT_)) - ez->assume(ez->vec_eq(ez->vec_or(a, ez->vec_not(b)), yy)); - if (cell->type == ID($add)) - ez->assume(ez->vec_eq(ez->vec_add(a, b), yy)); - if (cell->type == ID($sub)) - ez->assume(ez->vec_eq(ez->vec_sub(a, b), yy)); - - if (model_undef && !arith_undef_handled) - { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - extendSignalWidth(undef_a, undef_b, undef_y, cell, false); - - if (cell->type.in(ID($and), ID($_AND_), ID($_NAND_))) { - std::vector a0 = ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a)); - std::vector b0 = ez->vec_and(ez->vec_not(b), ez->vec_not(undef_b)); - std::vector yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a0, b0))); - ez->assume(ez->vec_eq(yX, undef_y)); - } - else if (cell->type.in(ID($or), ID($_OR_), ID($_NOR_))) { - std::vector a1 = ez->vec_and(a, ez->vec_not(undef_a)); - std::vector b1 = ez->vec_and(b, ez->vec_not(undef_b)); - std::vector yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a1, b1))); - ez->assume(ez->vec_eq(yX, undef_y)); - } - else if (cell->type.in(ID($xor), ID($xnor), ID($_XOR_), ID($_XNOR_))) { - std::vector yX = ez->vec_or(undef_a, undef_b); - ez->assume(ez->vec_eq(yX, undef_y)); - } - else if (cell->type == ID($_ANDNOT_)) { - std::vector a0 = ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a)); - std::vector b1 = ez->vec_and(b, ez->vec_not(undef_b)); - std::vector yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a0, b1))); - ez->assume(ez->vec_eq(yX, undef_y)); - } - - else if (cell->type == ID($_ORNOT_)) { - std::vector a1 = ez->vec_and(a, ez->vec_not(undef_a)); - std::vector b0 = ez->vec_and(ez->vec_not(b), ez->vec_not(undef_b)); - std::vector yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a1, b0))); - ez->assume(ez->vec_eq(yX, undef_y)); - } - else - log_abort(); - - undefGating(y, yy, undef_y); - } - else if (model_undef) - { - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type.in(ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), ID($_OAI4_))) - { - bool aoi_mode = cell->type.in(ID($_AOI3_), ID($_AOI4_)); - bool three_mode = cell->type.in(ID($_AOI3_), ID($_OAI3_)); - - int a = importDefSigSpec(cell->getPort(ID::A), timestep).at(0); - int b = importDefSigSpec(cell->getPort(ID::B), timestep).at(0); - int c = importDefSigSpec(cell->getPort(ID::C), timestep).at(0); - int d = three_mode ? (aoi_mode ? ez->CONST_TRUE : ez->CONST_FALSE) : importDefSigSpec(cell->getPort(ID::D), timestep).at(0); - int y = importDefSigSpec(cell->getPort(ID::Y), timestep).at(0); - int yy = model_undef ? ez->literal() : y; - - if (cell->type.in(ID($_AOI3_), ID($_AOI4_))) - ez->assume(ez->IFF(ez->NOT(ez->OR(ez->AND(a, b), ez->AND(c, d))), yy)); - else - ez->assume(ez->IFF(ez->NOT(ez->AND(ez->OR(a, b), ez->OR(c, d))), yy)); - - if (model_undef) - { - int undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep).at(0); - int undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep).at(0); - int undef_c = importUndefSigSpec(cell->getPort(ID::C), timestep).at(0); - int undef_d = three_mode ? ez->CONST_FALSE : importUndefSigSpec(cell->getPort(ID::D), timestep).at(0); - int undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep).at(0); - - if (aoi_mode) - { - int a0 = ez->AND(ez->NOT(a), ez->NOT(undef_a)); - int b0 = ez->AND(ez->NOT(b), ez->NOT(undef_b)); - int c0 = ez->AND(ez->NOT(c), ez->NOT(undef_c)); - int d0 = ez->AND(ez->NOT(d), ez->NOT(undef_d)); - - int ab = ez->AND(a, b), cd = ez->AND(c, d); - int undef_ab = ez->AND(ez->OR(undef_a, undef_b), ez->NOT(ez->OR(a0, b0))); - int undef_cd = ez->AND(ez->OR(undef_c, undef_d), ez->NOT(ez->OR(c0, d0))); - - int ab1 = ez->AND(ab, ez->NOT(undef_ab)); - int cd1 = ez->AND(cd, ez->NOT(undef_cd)); - int yX = ez->AND(ez->OR(undef_ab, undef_cd), ez->NOT(ez->OR(ab1, cd1))); - - ez->assume(ez->IFF(yX, undef_y)); - } - else - { - int a1 = ez->AND(a, ez->NOT(undef_a)); - int b1 = ez->AND(b, ez->NOT(undef_b)); - int c1 = ez->AND(c, ez->NOT(undef_c)); - int d1 = ez->AND(d, ez->NOT(undef_d)); - - int ab = ez->OR(a, b), cd = ez->OR(c, d); - int undef_ab = ez->AND(ez->OR(undef_a, undef_b), ez->NOT(ez->OR(a1, b1))); - int undef_cd = ez->AND(ez->OR(undef_c, undef_d), ez->NOT(ez->OR(c1, d1))); - - int ab0 = ez->AND(ez->NOT(ab), ez->NOT(undef_ab)); - int cd0 = ez->AND(ez->NOT(cd), ez->NOT(undef_cd)); - int yX = ez->AND(ez->OR(undef_ab, undef_cd), ez->NOT(ez->OR(ab0, cd0))); - - ez->assume(ez->IFF(yX, undef_y)); - } - - undefGating(y, yy, undef_y); - } - - return true; - } - - if (cell->type.in(ID($_NOT_), ID($not))) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - extendSignalWidthUnary(a, y, cell); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - ez->assume(ez->vec_eq(ez->vec_not(a), yy)); - - if (model_undef) { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - extendSignalWidthUnary(undef_a, undef_y, cell, false); - ez->assume(ez->vec_eq(undef_a, undef_y)); - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type.in(ID($_MUX_), ID($mux), ID($_NMUX_))) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); - std::vector s = importDefSigSpec(cell->getPort(ID::S), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - if (cell->type == ID($_NMUX_)) - ez->assume(ez->vec_eq(ez->vec_not(ez->vec_ite(s.at(0), b, a)), yy)); - else - ez->assume(ez->vec_eq(ez->vec_ite(s.at(0), b, a), yy)); - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - std::vector undef_s = importUndefSigSpec(cell->getPort(ID::S), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - - std::vector unequal_ab = ez->vec_not(ez->vec_iff(a, b)); - std::vector undef_ab = ez->vec_or(unequal_ab, ez->vec_or(undef_a, undef_b)); - std::vector yX = ez->vec_ite(undef_s.at(0), undef_ab, ez->vec_ite(s.at(0), undef_b, undef_a)); - ez->assume(ez->vec_eq(yX, undef_y)); - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type == ID($pmux)) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); - std::vector s = importDefSigSpec(cell->getPort(ID::S), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - - std::vector tmp = a; - for (size_t i = 0; i < s.size(); i++) { - std::vector part_of_b(b.begin()+i*a.size(), b.begin()+(i+1)*a.size()); - tmp = ez->vec_ite(s.at(i), part_of_b, tmp); - } - ez->assume(ez->vec_eq(tmp, yy)); - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - std::vector undef_s = importUndefSigSpec(cell->getPort(ID::S), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - - int maybe_a = ez->CONST_TRUE; - - std::vector bits_set = std::vector(undef_y.size(), ez->CONST_FALSE); - std::vector bits_clr = std::vector(undef_y.size(), ez->CONST_FALSE); - - for (size_t i = 0; i < s.size(); i++) - { - std::vector part_of_b(b.begin()+i*a.size(), b.begin()+(i+1)*a.size()); - std::vector part_of_undef_b(undef_b.begin()+i*a.size(), undef_b.begin()+(i+1)*a.size()); - - int maybe_s = ez->OR(s.at(i), undef_s.at(i)); - int sure_s = ez->AND(s.at(i), ez->NOT(undef_s.at(i))); - - maybe_a = ez->AND(maybe_a, ez->NOT(sure_s)); - - bits_set = ez->vec_ite(maybe_s, ez->vec_or(bits_set, ez->vec_or(part_of_b, part_of_undef_b)), bits_set); - bits_clr = ez->vec_ite(maybe_s, ez->vec_or(bits_clr, ez->vec_or(ez->vec_not(part_of_b), part_of_undef_b)), bits_clr); - } - - bits_set = ez->vec_ite(maybe_a, ez->vec_or(bits_set, ez->vec_or(bits_set, ez->vec_or(a, undef_a))), bits_set); - bits_clr = ez->vec_ite(maybe_a, ez->vec_or(bits_clr, ez->vec_or(bits_clr, ez->vec_or(ez->vec_not(a), undef_a))), bits_clr); - - ez->assume(ez->vec_eq(ez->vec_not(ez->vec_xor(bits_set, bits_clr)), undef_y)); - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type.in(ID($pos), ID($neg))) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - extendSignalWidthUnary(a, y, cell); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - - if (cell->type == ID($pos)) { - ez->assume(ez->vec_eq(a, yy)); - } else { - std::vector zero(a.size(), ez->CONST_FALSE); - ez->assume(ez->vec_eq(ez->vec_sub(zero, a), yy)); - } - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - extendSignalWidthUnary(undef_a, undef_y, cell); - - if (cell->type == ID($pos)) { - ez->assume(ez->vec_eq(undef_a, undef_y)); - } else { - int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); - std::vector undef_y_bits(undef_y.size(), undef_any_a); - ez->assume(ez->vec_eq(undef_y_bits, undef_y)); - } - - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($logic_not))) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - - if (cell->type == ID($reduce_and)) - ez->SET(ez->expression(ez->OpAnd, a), yy.at(0)); - if (cell->type.in(ID($reduce_or), ID($reduce_bool))) - ez->SET(ez->expression(ez->OpOr, a), yy.at(0)); - if (cell->type == ID($reduce_xor)) - ez->SET(ez->expression(ez->OpXor, a), yy.at(0)); - if (cell->type == ID($reduce_xnor)) - ez->SET(ez->NOT(ez->expression(ez->OpXor, a)), yy.at(0)); - if (cell->type == ID($logic_not)) - ez->SET(ez->NOT(ez->expression(ez->OpOr, a)), yy.at(0)); - for (size_t i = 1; i < y.size(); i++) - ez->SET(ez->CONST_FALSE, yy.at(i)); - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - int aX = ez->expression(ezSAT::OpOr, undef_a); - - if (cell->type == ID($reduce_and)) { - int a0 = ez->expression(ezSAT::OpOr, ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a))); - ez->assume(ez->IFF(ez->AND(ez->NOT(a0), aX), undef_y.at(0))); - } - else if (cell->type.in(ID($reduce_or), ID($reduce_bool), ID($logic_not))) { - int a1 = ez->expression(ezSAT::OpOr, ez->vec_and(a, ez->vec_not(undef_a))); - ez->assume(ez->IFF(ez->AND(ez->NOT(a1), aX), undef_y.at(0))); - } - else if (cell->type.in(ID($reduce_xor), ID($reduce_xnor))) { - ez->assume(ez->IFF(aX, undef_y.at(0))); - } else - log_abort(); - - for (size_t i = 1; i < undef_y.size(); i++) - ez->SET(ez->CONST_FALSE, undef_y.at(i)); - - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type.in(ID($logic_and), ID($logic_or))) - { - std::vector vec_a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector vec_b = importDefSigSpec(cell->getPort(ID::B), timestep); - - int a = ez->expression(ez->OpOr, vec_a); - int b = ez->expression(ez->OpOr, vec_b); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - - if (cell->type == ID($logic_and)) - ez->SET(ez->expression(ez->OpAnd, a, b), yy.at(0)); - else - ez->SET(ez->expression(ez->OpOr, a, b), yy.at(0)); - for (size_t i = 1; i < y.size(); i++) - ez->SET(ez->CONST_FALSE, yy.at(i)); - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - - int a0 = ez->NOT(ez->OR(ez->expression(ezSAT::OpOr, vec_a), ez->expression(ezSAT::OpOr, undef_a))); - int b0 = ez->NOT(ez->OR(ez->expression(ezSAT::OpOr, vec_b), ez->expression(ezSAT::OpOr, undef_b))); - int a1 = ez->expression(ezSAT::OpOr, ez->vec_and(vec_a, ez->vec_not(undef_a))); - int b1 = ez->expression(ezSAT::OpOr, ez->vec_and(vec_b, ez->vec_not(undef_b))); - int aX = ez->expression(ezSAT::OpOr, undef_a); - int bX = ez->expression(ezSAT::OpOr, undef_b); - - if (cell->type == ID($logic_and)) - ez->SET(ez->AND(ez->OR(aX, bX), ez->NOT(ez->AND(a1, b1)), ez->NOT(a0), ez->NOT(b0)), undef_y.at(0)); - else if (cell->type == ID($logic_or)) - ez->SET(ez->AND(ez->OR(aX, bX), ez->NOT(ez->AND(a0, b0)), ez->NOT(a1), ez->NOT(b1)), undef_y.at(0)); - else - log_abort(); - - for (size_t i = 1; i < undef_y.size(); i++) - ez->SET(ez->CONST_FALSE, undef_y.at(i)); - - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type.in(ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt))) - { - bool is_signed = cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool(); - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - extendSignalWidth(a, b, cell); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - - if (model_undef && cell->type.in(ID($eqx), ID($nex))) { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - extendSignalWidth(undef_a, undef_b, cell, true); - a = ez->vec_or(a, undef_a); - b = ez->vec_or(b, undef_b); - } - - if (cell->type == ID($lt)) - ez->SET(is_signed ? ez->vec_lt_signed(a, b) : ez->vec_lt_unsigned(a, b), yy.at(0)); - if (cell->type == ID($le)) - ez->SET(is_signed ? ez->vec_le_signed(a, b) : ez->vec_le_unsigned(a, b), yy.at(0)); - if (cell->type.in(ID($eq), ID($eqx))) - ez->SET(ez->vec_eq(a, b), yy.at(0)); - if (cell->type.in(ID($ne), ID($nex))) - ez->SET(ez->vec_ne(a, b), yy.at(0)); - if (cell->type == ID($ge)) - ez->SET(is_signed ? ez->vec_ge_signed(a, b) : ez->vec_ge_unsigned(a, b), yy.at(0)); - if (cell->type == ID($gt)) - ez->SET(is_signed ? ez->vec_gt_signed(a, b) : ez->vec_gt_unsigned(a, b), yy.at(0)); - for (size_t i = 1; i < y.size(); i++) - ez->SET(ez->CONST_FALSE, yy.at(i)); - - if (model_undef && cell->type.in(ID($eqx), ID($nex))) - { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - extendSignalWidth(undef_a, undef_b, cell, true); - - if (cell->type == ID($eqx)) - yy.at(0) = ez->AND(yy.at(0), ez->vec_eq(undef_a, undef_b)); - else - yy.at(0) = ez->OR(yy.at(0), ez->vec_ne(undef_a, undef_b)); - - for (size_t i = 0; i < y.size(); i++) - ez->SET(ez->CONST_FALSE, undef_y.at(i)); - - ez->assume(ez->vec_eq(y, yy)); - } - else if (model_undef && cell->type.in(ID($eq), ID($ne))) - { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - extendSignalWidth(undef_a, undef_b, cell, true); - - int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); - int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); - int undef_any = ez->OR(undef_any_a, undef_any_b); - - std::vector masked_a_bits = ez->vec_or(a, ez->vec_or(undef_a, undef_b)); - std::vector masked_b_bits = ez->vec_or(b, ez->vec_or(undef_a, undef_b)); - - int masked_ne = ez->vec_ne(masked_a_bits, masked_b_bits); - int undef_y_bit = ez->AND(undef_any, ez->NOT(masked_ne)); - - for (size_t i = 1; i < undef_y.size(); i++) - ez->SET(ez->CONST_FALSE, undef_y.at(i)); - ez->SET(undef_y_bit, undef_y.at(0)); - - undefGating(y, yy, undef_y); - } - else - { - if (model_undef) { - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - undefGating(y, yy, undef_y); - } - log_assert(!model_undef || arith_undef_handled); - } - return true; - } - - if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - - int extend_bit = ez->CONST_FALSE; - - if (!cell->type.in(ID($shift), ID($shiftx)) && cell->parameters[ID::A_SIGNED].as_bool()) - extend_bit = a.back(); - - while (y.size() < a.size()) - y.push_back(ez->literal()); - while (y.size() > a.size()) - a.push_back(extend_bit); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - std::vector shifted_a; - - if (cell->type.in( ID($shl), ID($sshl))) - shifted_a = ez->vec_shift_left(a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); - - if (cell->type == ID($shr)) - shifted_a = ez->vec_shift_right(a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); - - if (cell->type == ID($sshr)) - shifted_a = ez->vec_shift_right(a, b, false, cell->parameters[ID::A_SIGNED].as_bool() ? a.back() : ez->CONST_FALSE, ez->CONST_FALSE); - - if (cell->type.in(ID($shift), ID($shiftx))) - shifted_a = ez->vec_shift_right(a, b, cell->parameters[ID::B_SIGNED].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE); - - ez->assume(ez->vec_eq(shifted_a, yy)); - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - std::vector undef_a_shifted; - - extend_bit = cell->type == ID($shiftx) ? ez->CONST_TRUE : ez->CONST_FALSE; - if (!cell->type.in(ID($shift), ID($shiftx)) && cell->parameters[ID::A_SIGNED].as_bool()) - extend_bit = undef_a.back(); - - while (undef_y.size() < undef_a.size()) - undef_y.push_back(ez->literal()); - while (undef_y.size() > undef_a.size()) - undef_a.push_back(extend_bit); - - if (cell->type.in(ID($shl), ID($sshl))) - undef_a_shifted = ez->vec_shift_left(undef_a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); - - if (cell->type == ID($shr)) - undef_a_shifted = ez->vec_shift_right(undef_a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); - - if (cell->type == ID($sshr)) - undef_a_shifted = ez->vec_shift_right(undef_a, b, false, cell->parameters[ID::A_SIGNED].as_bool() ? undef_a.back() : ez->CONST_FALSE, ez->CONST_FALSE); - - if (cell->type == ID($shift)) - undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters[ID::B_SIGNED].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE); - - if (cell->type == ID($shiftx)) - undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters[ID::B_SIGNED].as_bool(), ez->CONST_TRUE, ez->CONST_TRUE); - - int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); - std::vector undef_all_y_bits(undef_y.size(), undef_any_b); - ez->assume(ez->vec_eq(ez->vec_or(undef_a_shifted, undef_all_y_bits), undef_y)); - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type == ID($mul)) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - extendSignalWidth(a, b, y, cell); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - - std::vector tmp(a.size(), ez->CONST_FALSE); - for (int i = 0; i < int(a.size()); i++) - { - std::vector shifted_a(a.size(), ez->CONST_FALSE); - for (int j = i; j < int(a.size()); j++) - shifted_a.at(j) = a.at(j-i); - tmp = ez->vec_ite(b.at(i), ez->vec_add(tmp, shifted_a), tmp); - } - ez->assume(ez->vec_eq(tmp, yy)); - - if (model_undef) { - log_assert(arith_undef_handled); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type == ID($macc)) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - - Macc macc; - macc.from_cell(cell); - - std::vector tmp(GetSize(y), ez->CONST_FALSE); - - for (auto &port : macc.ports) - { - std::vector in_a = importDefSigSpec(port.in_a, timestep); - std::vector in_b = importDefSigSpec(port.in_b, timestep); - - while (GetSize(in_a) < GetSize(y)) - in_a.push_back(port.is_signed && !in_a.empty() ? in_a.back() : ez->CONST_FALSE); - in_a.resize(GetSize(y)); - - if (GetSize(in_b)) - { - while (GetSize(in_b) < GetSize(y)) - in_b.push_back(port.is_signed && !in_b.empty() ? in_b.back() : ez->CONST_FALSE); - in_b.resize(GetSize(y)); - - for (int i = 0; i < GetSize(in_b); i++) { - std::vector shifted_a(in_a.size(), ez->CONST_FALSE); - for (int j = i; j < int(in_a.size()); j++) - shifted_a.at(j) = in_a.at(j-i); - if (port.do_subtract) - tmp = ez->vec_ite(in_b.at(i), ez->vec_sub(tmp, shifted_a), tmp); - else - tmp = ez->vec_ite(in_b.at(i), ez->vec_add(tmp, shifted_a), tmp); - } - } - else - { - if (port.do_subtract) - tmp = ez->vec_sub(tmp, in_a); - else - tmp = ez->vec_add(tmp, in_a); - } - } - - for (int i = 0; i < GetSize(b); i++) { - std::vector val(GetSize(y), ez->CONST_FALSE); - val.at(0) = b.at(i); - tmp = ez->vec_add(tmp, val); - } - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - - int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); - int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); - - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - ez->assume(ez->vec_eq(undef_y, std::vector(GetSize(y), ez->OR(undef_any_a, undef_any_b)))); - - undefGating(y, tmp, undef_y); - } - else - ez->assume(ez->vec_eq(y, tmp)); - - return true; - } - - if (cell->type.in(ID($div), ID($mod), ID($divfloor), ID($modfloor))) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - extendSignalWidth(a, b, y, cell); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - - std::vector a_u, b_u; - if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) { - a_u = ez->vec_ite(a.back(), ez->vec_neg(a), a); - b_u = ez->vec_ite(b.back(), ez->vec_neg(b), b); - } else { - a_u = a; - b_u = b; - } - - std::vector chain_buf = a_u; - std::vector y_u(a_u.size(), ez->CONST_FALSE); - for (int i = int(a.size())-1; i >= 0; i--) - { - chain_buf.insert(chain_buf.end(), chain_buf.size(), ez->CONST_FALSE); - - std::vector b_shl(i, ez->CONST_FALSE); - b_shl.insert(b_shl.end(), b_u.begin(), b_u.end()); - b_shl.insert(b_shl.end(), chain_buf.size()-b_shl.size(), ez->CONST_FALSE); - - y_u.at(i) = ez->vec_ge_unsigned(chain_buf, b_shl); - chain_buf = ez->vec_ite(y_u.at(i), ez->vec_sub(chain_buf, b_shl), chain_buf); - - chain_buf.erase(chain_buf.begin() + a_u.size(), chain_buf.end()); - } - - std::vector y_tmp = ignore_div_by_zero ? yy : ez->vec_var(y.size()); - - // modulo calculation - std::vector modulo_trunc; - int floored_eq_trunc; - if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) { - modulo_trunc = ez->vec_ite(a.back(), ez->vec_neg(chain_buf), chain_buf); - // floor == trunc when sgn(a) == sgn(b) or trunc == 0 - floored_eq_trunc = ez->OR(ez->IFF(a.back(), b.back()), ez->NOT(ez->expression(ezSAT::OpOr, modulo_trunc))); - } else { - modulo_trunc = chain_buf; - floored_eq_trunc = ez->CONST_TRUE; - } - - if (cell->type == ID($div)) { - if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) - ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(ez->XOR(a.back(), b.back()), ez->vec_neg(y_u), y_u))); - else - ez->assume(ez->vec_eq(y_tmp, y_u)); - } else if (cell->type == ID($mod)) { - ez->assume(ez->vec_eq(y_tmp, modulo_trunc)); - } else if (cell->type == ID($divfloor)) { - if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) - ez->assume(ez->vec_eq(y_tmp, ez->vec_ite( - ez->XOR(a.back(), b.back()), - ez->vec_neg(ez->vec_ite( - ez->vec_reduce_or(modulo_trunc), - ez->vec_add(y_u, ez->vec_const_unsigned(1, y_u.size())), - y_u - )), - y_u - ))); - else - ez->assume(ez->vec_eq(y_tmp, y_u)); - } else if (cell->type == ID($modfloor)) { - ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(floored_eq_trunc, modulo_trunc, ez->vec_add(modulo_trunc, b)))); - } - - if (ignore_div_by_zero) { - ez->assume(ez->expression(ezSAT::OpOr, b)); - } else { - std::vector div_zero_result; - if (cell->type.in(ID($div), ID($divfloor))) { - if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) { - std::vector all_ones(y.size(), ez->CONST_TRUE); - std::vector only_first_one(y.size(), ez->CONST_FALSE); - only_first_one.at(0) = ez->CONST_TRUE; - div_zero_result = ez->vec_ite(a.back(), only_first_one, all_ones); - } else { - div_zero_result.insert(div_zero_result.end(), cell->getPort(ID::A).size(), ez->CONST_TRUE); - div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE); - } - } else if (cell->type.in(ID($mod), ID($modfloor))) { - // a mod 0 = a - int copy_a_bits = min(cell->getPort(ID::A).size(), cell->getPort(ID::B).size()); - div_zero_result.insert(div_zero_result.end(), a.begin(), a.begin() + copy_a_bits); - if (cell->parameters[ID::A_SIGNED].as_bool() && cell->parameters[ID::B_SIGNED].as_bool()) - div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), div_zero_result.back()); - else - div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE); - } - ez->assume(ez->vec_eq(yy, ez->vec_ite(ez->expression(ezSAT::OpOr, b), y_tmp, div_zero_result))); - } - - if (model_undef) { - log_assert(arith_undef_handled); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type == ID($lut)) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - - std::vector lut; - for (auto bit : cell->getParam(ID::LUT).bits) - lut.push_back(bit == State::S1 ? ez->CONST_TRUE : ez->CONST_FALSE); - while (GetSize(lut) < (1 << GetSize(a))) - lut.push_back(ez->CONST_FALSE); - lut.resize(1 << GetSize(a)); - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector t(lut), u(GetSize(t), ez->CONST_FALSE); - - for (int i = GetSize(a)-1; i >= 0; i--) - { - std::vector t0(t.begin(), t.begin() + GetSize(t)/2); - std::vector t1(t.begin() + GetSize(t)/2, t.end()); - - std::vector u0(u.begin(), u.begin() + GetSize(u)/2); - std::vector u1(u.begin() + GetSize(u)/2, u.end()); - - t = ez->vec_ite(a[i], t1, t0); - u = ez->vec_ite(undef_a[i], ez->vec_or(ez->vec_xor(t0, t1), ez->vec_or(u0, u1)), ez->vec_ite(a[i], u1, u0)); - } - - log_assert(GetSize(t) == 1); - log_assert(GetSize(u) == 1); - undefGating(y, t, u); - ez->assume(ez->vec_eq(importUndefSigSpec(cell->getPort(ID::Y), timestep), u)); - } - else - { - std::vector t = lut; - for (int i = GetSize(a)-1; i >= 0; i--) - { - std::vector t0(t.begin(), t.begin() + GetSize(t)/2); - std::vector t1(t.begin() + GetSize(t)/2, t.end()); - t = ez->vec_ite(a[i], t1, t0); - } - - log_assert(GetSize(t) == 1); - ez->assume(ez->vec_eq(y, t)); - } - return true; - } - - if (cell->type == ID($sop)) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - int y = importDefSigSpec(cell->getPort(ID::Y), timestep).at(0); - - int width = cell->getParam(ID::WIDTH).as_int(); - int depth = cell->getParam(ID::DEPTH).as_int(); - - vector table_raw = cell->getParam(ID::TABLE).bits; - while (GetSize(table_raw) < 2*width*depth) - table_raw.push_back(State::S0); - - vector> table(depth); - - for (int i = 0; i < depth; i++) - for (int j = 0; j < width; j++) - { - bool pat0 = (table_raw[2*width*i + 2*j + 0] == State::S1); - bool pat1 = (table_raw[2*width*i + 2*j + 1] == State::S1); - - if (pat0 && !pat1) - table.at(i).push_back(0); - else if (!pat0 && pat1) - table.at(i).push_back(1); - else - table.at(i).push_back(-1); - } - - if (model_undef) - { - std::vector products, undef_products; - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - int undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep).at(0); - - for (int i = 0; i < depth; i++) - { - std::vector cmp_a, cmp_ua, cmp_b; - - for (int j = 0; j < width; j++) - if (table.at(i).at(j) >= 0) { - cmp_a.push_back(a.at(j)); - cmp_ua.push_back(undef_a.at(j)); - cmp_b.push_back(table.at(i).at(j) ? ez->CONST_TRUE : ez->CONST_FALSE); - } - - std::vector masked_a = ez->vec_or(cmp_a, cmp_ua); - std::vector masked_b = ez->vec_or(cmp_b, cmp_ua); - - int masked_eq = ez->vec_eq(masked_a, masked_b); - int any_undef = ez->expression(ezSAT::OpOr, cmp_ua); - - undef_products.push_back(ez->AND(any_undef, masked_eq)); - products.push_back(ez->AND(ez->NOT(any_undef), masked_eq)); - } - - int yy = ez->expression(ezSAT::OpOr, products); - ez->SET(undef_y, ez->AND(ez->NOT(yy), ez->expression(ezSAT::OpOr, undef_products))); - undefGating(y, yy, undef_y); - } - else - { - std::vector products; - - for (int i = 0; i < depth; i++) - { - std::vector cmp_a, cmp_b; - - for (int j = 0; j < width; j++) - if (table.at(i).at(j) >= 0) { - cmp_a.push_back(a.at(j)); - cmp_b.push_back(table.at(i).at(j) ? ez->CONST_TRUE : ez->CONST_FALSE); - } - - products.push_back(ez->vec_eq(cmp_a, cmp_b)); - } - - ez->SET(y, ez->expression(ezSAT::OpOr, products)); - } - - return true; - } - - if (cell->type == ID($fa)) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); - std::vector c = importDefSigSpec(cell->getPort(ID::C), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - std::vector x = importDefSigSpec(cell->getPort(ID::X), timestep); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - std::vector xx = model_undef ? ez->vec_var(x.size()) : x; - - std::vector t1 = ez->vec_xor(a, b); - ez->assume(ez->vec_eq(yy, ez->vec_xor(t1, c))); - - std::vector t2 = ez->vec_and(a, b); - std::vector t3 = ez->vec_and(c, t1); - ez->assume(ez->vec_eq(xx, ez->vec_or(t2, t3))); - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - std::vector undef_c = importUndefSigSpec(cell->getPort(ID::C), timestep); - - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - std::vector undef_x = importUndefSigSpec(cell->getPort(ID::X), timestep); - - ez->assume(ez->vec_eq(undef_y, ez->vec_or(ez->vec_or(undef_a, undef_b), undef_c))); - ez->assume(ez->vec_eq(undef_x, undef_y)); - - undefGating(y, yy, undef_y); - undefGating(x, xx, undef_x); - } - return true; - } - - if (cell->type == ID($lcu)) - { - std::vector p = importDefSigSpec(cell->getPort(ID::P), timestep); - std::vector g = importDefSigSpec(cell->getPort(ID::G), timestep); - std::vector ci = importDefSigSpec(cell->getPort(ID::CI), timestep); - std::vector co = importDefSigSpec(cell->getPort(ID::CO), timestep); - - std::vector yy = model_undef ? ez->vec_var(co.size()) : co; - - for (int i = 0; i < GetSize(co); i++) - ez->SET(yy[i], ez->OR(g[i], ez->AND(p[i], i ? yy[i-1] : ci[0]))); - - if (model_undef) - { - std::vector undef_p = importUndefSigSpec(cell->getPort(ID::P), timestep); - std::vector undef_g = importUndefSigSpec(cell->getPort(ID::G), timestep); - std::vector undef_ci = importUndefSigSpec(cell->getPort(ID::CI), timestep); - std::vector undef_co = importUndefSigSpec(cell->getPort(ID::CO), timestep); - - int undef_any_p = ez->expression(ezSAT::OpOr, undef_p); - int undef_any_g = ez->expression(ezSAT::OpOr, undef_g); - int undef_any_ci = ez->expression(ezSAT::OpOr, undef_ci); - int undef_co_bit = ez->OR(undef_any_p, undef_any_g, undef_any_ci); - - std::vector undef_co_bits(undef_co.size(), undef_co_bit); - ez->assume(ez->vec_eq(undef_co_bits, undef_co)); - - undefGating(co, yy, undef_co); - } - return true; - } - - if (cell->type == ID($alu)) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector b = importDefSigSpec(cell->getPort(ID::B), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - std::vector x = importDefSigSpec(cell->getPort(ID::X), timestep); - std::vector ci = importDefSigSpec(cell->getPort(ID::CI), timestep); - std::vector bi = importDefSigSpec(cell->getPort(ID::BI), timestep); - std::vector co = importDefSigSpec(cell->getPort(ID::CO), timestep); - - extendSignalWidth(a, b, y, cell); - extendSignalWidth(a, b, x, cell); - extendSignalWidth(a, b, co, cell); - - std::vector def_y = model_undef ? ez->vec_var(y.size()) : y; - std::vector def_x = model_undef ? ez->vec_var(x.size()) : x; - std::vector def_co = model_undef ? ez->vec_var(co.size()) : co; - - log_assert(GetSize(y) == GetSize(x)); - log_assert(GetSize(y) == GetSize(co)); - log_assert(GetSize(ci) == 1); - log_assert(GetSize(bi) == 1); - - for (int i = 0; i < GetSize(y); i++) - { - int s1 = a.at(i), s2 = ez->XOR(b.at(i), bi.at(0)), s3 = i ? co.at(i-1) : ci.at(0); - ez->SET(def_x.at(i), ez->XOR(s1, s2)); - ez->SET(def_y.at(i), ez->XOR(def_x.at(i), s3)); - ez->SET(def_co.at(i), ez->OR(ez->AND(s1, s2), ez->AND(s1, s3), ez->AND(s2, s3))); - } - - if (model_undef) - { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); - std::vector undef_ci = importUndefSigSpec(cell->getPort(ID::CI), timestep); - std::vector undef_bi = importUndefSigSpec(cell->getPort(ID::BI), timestep); - - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - std::vector undef_x = importUndefSigSpec(cell->getPort(ID::X), timestep); - std::vector undef_co = importUndefSigSpec(cell->getPort(ID::CO), timestep); - - extendSignalWidth(undef_a, undef_b, undef_y, cell); - extendSignalWidth(undef_a, undef_b, undef_x, cell); - extendSignalWidth(undef_a, undef_b, undef_co, cell); - - std::vector all_inputs_undef; - all_inputs_undef.insert(all_inputs_undef.end(), undef_a.begin(), undef_a.end()); - all_inputs_undef.insert(all_inputs_undef.end(), undef_b.begin(), undef_b.end()); - all_inputs_undef.insert(all_inputs_undef.end(), undef_ci.begin(), undef_ci.end()); - all_inputs_undef.insert(all_inputs_undef.end(), undef_bi.begin(), undef_bi.end()); - int undef_any = ez->expression(ezSAT::OpOr, all_inputs_undef); - - for (int i = 0; i < GetSize(undef_y); i++) { - ez->SET(undef_y.at(i), undef_any); - ez->SET(undef_x.at(i), ez->OR(undef_a.at(i), undef_b.at(i), undef_bi.at(0))); - ez->SET(undef_co.at(i), undef_any); - } - - undefGating(y, def_y, undef_y); - undefGating(x, def_x, undef_x); - undefGating(co, def_co, undef_co); - } - return true; - } - - if (cell->type == ID($slice)) - { - RTLIL::SigSpec a = cell->getPort(ID::A); - RTLIL::SigSpec y = cell->getPort(ID::Y); - ez->assume(signals_eq(a.extract(cell->parameters.at(ID::OFFSET).as_int(), y.size()), y, timestep)); - return true; - } - - if (cell->type == ID($concat)) - { - RTLIL::SigSpec a = cell->getPort(ID::A); - RTLIL::SigSpec b = cell->getPort(ID::B); - RTLIL::SigSpec y = cell->getPort(ID::Y); - - RTLIL::SigSpec ab = a; - ab.append(b); - - ez->assume(signals_eq(ab, y, timestep)); - return true; - } - - if (timestep > 0 && cell->type.in(ID($ff), ID($dff), ID($_FF_), ID($_DFF_N_), ID($_DFF_P_))) - { - if (timestep == 1) - { - initial_state.add((*sigmap)(cell->getPort(ID::Q))); - } - else - { - std::vector d = importDefSigSpec(cell->getPort(ID::D), timestep-1); - std::vector q = importDefSigSpec(cell->getPort(ID::Q), timestep); - - std::vector qq = model_undef ? ez->vec_var(q.size()) : q; - ez->assume(ez->vec_eq(d, qq)); - - if (model_undef) - { - std::vector undef_d = importUndefSigSpec(cell->getPort(ID::D), timestep-1); - std::vector undef_q = importUndefSigSpec(cell->getPort(ID::Q), timestep); - - ez->assume(ez->vec_eq(undef_d, undef_q)); - undefGating(q, qq, undef_q); - } - } - return true; - } - - if (cell->type == ID($anyconst)) - { - if (timestep < 2) - return true; - - std::vector d = importDefSigSpec(cell->getPort(ID::Y), timestep-1); - std::vector q = importDefSigSpec(cell->getPort(ID::Y), timestep); - - std::vector qq = model_undef ? ez->vec_var(q.size()) : q; - ez->assume(ez->vec_eq(d, qq)); - - if (model_undef) - { - std::vector undef_d = importUndefSigSpec(cell->getPort(ID::Y), timestep-1); - std::vector undef_q = importUndefSigSpec(cell->getPort(ID::Y), timestep); - - ez->assume(ez->vec_eq(undef_d, undef_q)); - undefGating(q, qq, undef_q); - } - return true; - } - - if (cell->type == ID($anyseq)) - { - return true; - } - - if (cell->type.in(ID($_BUF_), ID($equiv))) - { - std::vector a = importDefSigSpec(cell->getPort(ID::A), timestep); - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - extendSignalWidthUnary(a, y, cell); - - std::vector yy = model_undef ? ez->vec_var(y.size()) : y; - ez->assume(ez->vec_eq(a, yy)); - - if (model_undef) { - std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - extendSignalWidthUnary(undef_a, undef_y, cell, false); - ez->assume(ez->vec_eq(undef_a, undef_y)); - undefGating(y, yy, undef_y); - } - return true; - } - - if (cell->type == ID($initstate)) - { - auto key = make_pair(prefix, timestep); - if (initstates.count(key) == 0) - initstates[key] = false; - - std::vector y = importDefSigSpec(cell->getPort(ID::Y), timestep); - log_assert(GetSize(y) == 1); - ez->SET(y[0], initstates[key] ? ez->CONST_TRUE : ez->CONST_FALSE); - - if (model_undef) { - std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - log_assert(GetSize(undef_y) == 1); - ez->SET(undef_y[0], ez->CONST_FALSE); - } - - return true; - } - - if (cell->type == ID($assert)) - { - std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); - asserts_a[pf].append((*sigmap)(cell->getPort(ID::A))); - asserts_en[pf].append((*sigmap)(cell->getPort(ID::EN))); - return true; - } - - if (cell->type == ID($assume)) - { - std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); - assumes_a[pf].append((*sigmap)(cell->getPort(ID::A))); - assumes_en[pf].append((*sigmap)(cell->getPort(ID::EN))); - return true; - } - - // Unsupported internal cell types: $pow $lut - // .. and all sequential cells except $dff and $_DFF_[NP]_ - return false; - } + bool importCell(RTLIL::Cell *cell, int timestep = -1); }; YOSYS_NAMESPACE_END From f285f7b76916420b5d55a83d53a371ebe257cfb2 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Sun, 19 Jul 2020 20:27:09 -0600 Subject: [PATCH 089/287] Allow reals as constant function parameters --- frontends/ast/simplify.cc | 14 +++++++++++--- tests/various/const_func.v | 12 ++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 00f8c8df67c..fda064237e6 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -3029,7 +3029,7 @@ skip_dynamic_range_lvalue_expansion:; bool all_args_const = true; for (auto child : children) { while (child->simplify(true, false, false, 1, -1, false, true)) { } - if (child->type != AST_CONSTANT) + if (child->type != AST_CONSTANT && child->type != AST_REALVALUE) all_args_const = false; } @@ -4349,8 +4349,16 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) variables[child->str].val = RTLIL::Const(RTLIL::State::Sx, abs(child->range_left - child->range_right)+1); variables[child->str].offset = min(child->range_left, child->range_right); variables[child->str].is_signed = child->is_signed; - if (child->is_input && argidx < fcall->children.size()) - variables[child->str].val = fcall->children.at(argidx++)->bitsAsConst(variables[child->str].val.bits.size()); + if (child->is_input && argidx < fcall->children.size()) { + int width = variables[child->str].val.bits.size(); + auto* arg_node = fcall->children.at(argidx++); + if (arg_node->type == AST_CONSTANT) { + variables[child->str].val = arg_node->bitsAsConst(width); + } else { + log_assert(arg_node->type == AST_REALVALUE); + variables[child->str].val = arg_node->realAsConst(width); + } + } backup_scope[child->str] = current_scope[child->str]; current_scope[child->str] = child; continue; diff --git a/tests/various/const_func.v b/tests/various/const_func.v index 76cdc385dfb..541e63b1924 100644 --- a/tests/various/const_func.v +++ b/tests/various/const_func.v @@ -53,6 +53,15 @@ module top(out); c1, c2, c3, c4, d1, d2, d3, d4}; + function signed [31:0] negate; + input integer inp; + negate = ~inp; + endfunction + parameter W = 10; + parameter X = 3; + localparam signed Y = $floor(W / X); + localparam signed Z = negate($floor(W / X)); + // `define VERIFY `ifdef VERIFY assert property (a1 == 0); @@ -71,5 +80,8 @@ module top(out); assert property (d2 == 0); assert property (d3 == 1); assert property (d4 == 1); + + assert property (Y == 3); + assert property (Z == ~3); `endif endmodule From a207cb362cc4b682a37060f380362b23c927805e Mon Sep 17 00:00:00 2001 From: Claire Wolf Date: Mon, 20 Jul 2020 19:35:32 +0200 Subject: [PATCH 090/287] Only allow "sat" and "unsat" smt solver responses in yosys-smtbmc Signed-off-by: Claire Wolf --- backends/smt2/smtbmc.py | 4 ++-- backends/smt2/smtio.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py index 03f001bfd09..69dab559037 100644 --- a/backends/smt2/smtbmc.py +++ b/backends/smt2/smtbmc.py @@ -1275,10 +1275,10 @@ def smt_pop(): asserts_consequent_cache.pop() smt.write("(pop 1)") -def smt_check_sat(): +def smt_check_sat(expected=["sat", "unsat"]): if asserts_cache_dirty: smt_forall_assert() - return smt.check_sat() + return smt.check_sat(expected=expected) if tempind: retstatus = "FAILED" diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py index 72ab39d396f..4ac437c36a9 100644 --- a/backends/smt2/smtio.py +++ b/backends/smt2/smtio.py @@ -653,7 +653,7 @@ def read(self): return stmt - def check_sat(self): + def check_sat(self, expected=["sat", "unsat", "unknown", "timeout", "interrupted"]): if self.debug_print: print("> (check-sat)") if self.debug_file and not self.nocomments: @@ -740,7 +740,7 @@ def check_sat(self): print("(check-sat)", file=self.debug_file) self.debug_file.flush() - if result not in ["sat", "unsat", "unknown", "timeout", "interrupted"]: + if result not in expected: if result == "": print("%s Unexpected EOF response from solver." % (self.timestamp()), flush=True) else: From 3cb401db8c77035e88163b0d5d46f51a9510db77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Mon, 20 Jul 2020 21:43:05 +0200 Subject: [PATCH 091/287] celltypes: Fix EN port name for some FF types. --- kernel/celltypes.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 12dea93b8bf..944cb301ab2 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -139,12 +139,12 @@ struct CellTypes setup_type(ID($dff), {ID::CLK, ID::D}, {ID::Q}); setup_type(ID($dffe), {ID::CLK, ID::EN, ID::D}, {ID::Q}); setup_type(ID($dffsr), {ID::CLK, ID::SET, ID::CLR, ID::D}, {ID::Q}); - setup_type(ID($dffsre), {ID::CLK, ID::SET, ID::CLR, ID::D, ID::E}, {ID::Q}); + setup_type(ID($dffsre), {ID::CLK, ID::SET, ID::CLR, ID::D, ID::EN}, {ID::Q}); setup_type(ID($adff), {ID::CLK, ID::ARST, ID::D}, {ID::Q}); - setup_type(ID($adffe), {ID::CLK, ID::ARST, ID::D, ID::E}, {ID::Q}); + setup_type(ID($adffe), {ID::CLK, ID::ARST, ID::D, ID::EN}, {ID::Q}); setup_type(ID($sdff), {ID::CLK, ID::SRST, ID::D}, {ID::Q}); - setup_type(ID($sdffe), {ID::CLK, ID::SRST, ID::D, ID::E}, {ID::Q}); - setup_type(ID($sdffce), {ID::CLK, ID::SRST, ID::D, ID::E}, {ID::Q}); + setup_type(ID($sdffe), {ID::CLK, ID::SRST, ID::D, ID::EN}, {ID::Q}); + setup_type(ID($sdffce), {ID::CLK, ID::SRST, ID::D, ID::EN}, {ID::Q}); setup_type(ID($dlatch), {ID::EN, ID::D}, {ID::Q}); setup_type(ID($adlatch), {ID::EN, ID::D, ID::ARST}, {ID::Q}); setup_type(ID($dlatchsr), {ID::EN, ID::SET, ID::CLR, ID::D}, {ID::Q}); From f0379853371bfcf9217c3c0de15b3927b6f09e44 Mon Sep 17 00:00:00 2001 From: Alberto Gonzalez Date: Wed, 1 Jul 2020 20:51:14 +0000 Subject: [PATCH 092/287] smt2: Add `-solver-option` option. --- backends/smt2/smt2.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index 526b36352cb..a79c0bd990c 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -1387,6 +1387,10 @@ struct Smt2Backend : public Backend { log(" use the given template file. the line containing only the token '%%%%'\n"); log(" is replaced with the regular output of this command.\n"); log("\n"); + log(" -solver-option