Add $specrule cells for $setup/$hold/$skew specify rules
authorClifford Wolf <clifford@clifford.at>
Tue, 23 Apr 2019 13:46:40 +0000 (15:46 +0200)
committerClifford Wolf <clifford@clifford.at>
Tue, 23 Apr 2019 19:36:59 +0000 (21:36 +0200)
Signed-off-by: Clifford Wolf <clifford@clifford.at>
frontends/ast/ast.cc
frontends/ast/genrtlil.cc
frontends/verilog/verilog_lexer.l
frontends/verilog/verilog_parser.y
kernel/celltypes.h
kernel/rtlil.cc
manual/CHAPTER_CellLib.tex
passes/opt/opt_clean.cc
techlibs/common/simlib.v

index 6b3604ee531610925706908c1c3f2e8376822219..5623541b2a68f9a6917912818c9cd2bd5f194d8a 100644 (file)
@@ -952,7 +952,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
                                if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
                                        continue;
                                if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
-                                               (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3"))
+                                               (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule"))
                                        continue;
                                blackbox_module = false;
                                break;
@@ -1039,7 +1039,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
                                        child->children.push_back(AstNode::mkconst_int(0, false, 0));
                                        new_children.push_back(child);
                                } else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
-                                               (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3")) {
+                                               (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) {
                                        new_children.push_back(child);
                                } else {
                                        delete child;
index b2a22b49ab6abc191b7cf976e35ad39cbe3ade45..48bd466e67a14f7500b19e7799a0d739d6166081 100644 (file)
@@ -1538,6 +1538,12 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
                                cell->setParam("\\SRC_WIDTH", Const(src_width));
                                cell->setParam("\\DST_WIDTH", Const(dst_width));
                        }
+                       if (cell->type == "$specrule") {
+                               int src_width = GetSize(cell->getPort("\\SRC"));
+                               int dst_width = GetSize(cell->getPort("\\DST"));
+                               cell->setParam("\\SRC_WIDTH", Const(src_width));
+                               cell->setParam("\\DST_WIDTH", Const(dst_width));
+                       }
                }
                break;
 
index f49f9d3a29605041d28996e489b8bdf194e4fa75..cd96236a1e4b362dd1660ae01f338a93d40a6c90 100644 (file)
@@ -301,6 +301,12 @@ supply1 { return TOK_SUPPLY1; }
        return TOK_ID;
 }
 
+"$"(setup|hold|skew) {
+       if (!specify_mode) REJECT;
+       frontend_verilog_yylval.string = new std::string(yytext);
+       return TOK_ID;
+}
+
 "$signed"   { return TOK_TO_SIGNED; }
 "$unsigned" { return TOK_TO_UNSIGNED; }
 
@@ -417,6 +423,11 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
        return TOK_SPECIFY_OPER;
 }
 
+"&&&" {
+       if (!specify_mode) REJECT;
+       return TOK_SPECIFY_AND;
+}
+
 "/*" { BEGIN(COMMENT); }
 <COMMENT>.    /* ignore comment body */
 <COMMENT>\n   /* ignore comment body */
index 218d6f73872a221aead7faff0c3eda808f1be442..0a41ba58168bd69bd1444935d0ae875e2aa2ec60 100644 (file)
@@ -136,7 +136,7 @@ struct specify_rise_fall {
 %token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC
 %token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT
 %token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY
-%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM
+%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND
 %token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
 %token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
 %token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
@@ -153,7 +153,7 @@ struct specify_rise_fall {
 %type <specify_target_ptr> specify_target
 %type <specify_triple_ptr> specify_triple
 %type <specify_rise_fall_ptr> specify_rise_fall
-%type <ast> specify_if
+%type <ast> specify_if specify_condition
 %type <ch> specify_edge
 
 // operator precedence from low to high
@@ -815,6 +815,63 @@ specify_item:
                delete oper;
                delete target;
                delete timing;
+       } |
+       TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' expr ')' ';' {
+               bool limit_gt = false;
+               if (*$1 == "$setup" || *$1 == "$hold")
+                       limit_gt = true;
+               else if (*$1 == "$skew")
+                       limit_gt = false;
+               else
+                       frontend_verilog_yyerror("Unsupported specify rule type: %s\n", $1->c_str());
+
+               AstNode *src_pen = AstNode::mkconst_int($3 != 0, false, 1);
+               AstNode *src_pol = AstNode::mkconst_int($3 == 'p', false, 1);
+               AstNode *src_expr = $4, *src_en = $5 ? $5 : AstNode::mkconst_int(1, false, 1);
+
+               AstNode *dst_pen = AstNode::mkconst_int($7 != 0, false, 1);
+               AstNode *dst_pol = AstNode::mkconst_int($7 == 'p', false, 1);
+               AstNode *dst_expr = $8, *dst_en = $9 ? $9 : AstNode::mkconst_int(1, false, 1);
+
+               AstNode *limit = $11;
+
+               AstNode *cell = new AstNode(AST_CELL);
+               ast_stack.back()->children.push_back(cell);
+               cell->str = stringf("$specify$%d", autoidx++);
+               cell->children.push_back(new AstNode(AST_CELLTYPE));
+               cell->children.back()->str = "$specrule";
+
+               cell->children.push_back(new AstNode(AST_ARGUMENT, src_en));
+               cell->children.back()->str = "\\SRC_EN";
+
+               cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr));
+               cell->children.back()->str = "\\SRC";
+
+               cell->children.push_back(new AstNode(AST_PARASET, src_pen));
+               cell->children.back()->str = "\\SRC_PEN";
+
+               cell->children.push_back(new AstNode(AST_PARASET, src_pol));
+               cell->children.back()->str = "\\SRC_POL";
+
+               cell->children.push_back(new AstNode(AST_ARGUMENT, dst_en));
+               cell->children.back()->str = "\\DST_EN";
+
+               cell->children.push_back(new AstNode(AST_ARGUMENT, dst_expr));
+               cell->children.back()->str = "\\DST";
+
+               cell->children.push_back(new AstNode(AST_PARASET, dst_pen));
+               cell->children.back()->str = "\\DST_PEN";
+
+               cell->children.push_back(new AstNode(AST_PARASET, dst_pol));
+               cell->children.back()->str = "\\DST_POL";
+
+               cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(limit_gt, false, 1)));
+               cell->children.back()->str = "\\LIMIT_GT";
+
+               cell->children.push_back(new AstNode(AST_PARASET, limit));
+               cell->children.back()->str = "\\T_LIMIT";
+
+               delete $1;
        };
 
 specify_if:
@@ -825,6 +882,14 @@ specify_if:
                $$ = nullptr;
        };
 
+specify_condition:
+       TOK_SPECIFY_AND expr {
+               $$ = $2;
+       } |
+       /* empty */ {
+               $$ = nullptr;
+       };
+
 specify_target:
        expr {
                $$ = new specify_target;
index f8c73ed83204254b6377b87b9ebe2700c151dc8a..4e91edddac7c6d2911257692ed022e7df20e662a 100644 (file)
@@ -86,6 +86,7 @@ struct CellTypes
 
                IdString A = "\\A", B = "\\B", EN = "\\EN", Y = "\\Y";
                IdString SRC = "\\SRC", DST = "\\DST", DAT = "\\DAT";
+               IdString EN_SRC = "\\EN_SRC", EN_DST = "\\EN_DST";
 
                setup_type("$tribuf", {A, EN}, {Y}, true);
 
@@ -102,6 +103,7 @@ struct CellTypes
                setup_type("$equiv", {A, B}, {Y}, true);
                setup_type("$specify2", {EN, SRC, DST}, pool<RTLIL::IdString>(), true);
                setup_type("$specify3", {EN, SRC, DST, DAT}, pool<RTLIL::IdString>(), true);
+               setup_type("$specrule", {EN_SRC, EN_DST, SRC, DST}, pool<RTLIL::IdString>(), true);
        }
 
        void setup_internals_eval()
index 4522b0a085bbf2fc7d04e9b91b8ba54510360c0b..dae3698a997fb7b7e85bbb2fc492151b84a045b1 100644 (file)
@@ -1218,6 +1218,21 @@ namespace {
                                return;
                        }
 
+                       if (cell->type == "$specrule") {
+                               param_bool("\\SRC_PEN");
+                               param_bool("\\SRC_POL");
+                               param_bool("\\DST_PEN");
+                               param_bool("\\DST_POL");
+                               param_bool("\\LIMIT_GT");
+                               param("\\T_LIMIT");
+                               port("\\SRC_EN", 1);
+                               port("\\DST_EN", 1);
+                               port("\\SRC", param("\\SRC_WIDTH"));
+                               port("\\DST", param("\\DST_WIDTH"));
+                               check_expected();
+                               return;
+                       }
+
                        if (cell->type == "$_BUF_")    { check_gate("AY"); return; }
                        if (cell->type == "$_NOT_")    { check_gate("AY"); return; }
                        if (cell->type == "$_AND_")    { check_gate("ABY"); return; }
index 96a30955258230e1571119be8e26f1655445a928..cb1bcf1be25885ad5e50f6017e1f8ca9f282aea0 100644 (file)
@@ -466,7 +466,7 @@ Add information about {\tt \$assert}, {\tt \$assume}, {\tt \$live}, {\tt \$fair}
 \end{fixme}
 
 \begin{fixme}
-Add information about {\tt \$specify2} and {\tt \$specify3} cells.
+Add information about {\tt \$specify2}, {\tt \$specify3}, and {\tt \$specrule} cells.
 \end{fixme}
 
 \begin{fixme}
index 3f38dd58003acefa6e6ee0a1f980ee47ed66ac8f..3e131d2af0e09c714fa3bc277e772b83467ec571 100644 (file)
@@ -64,7 +64,7 @@ struct keep_cache_t
 
        bool query(Cell *cell)
        {
-               if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover", "$specify2", "$specify3"))
+               if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover", "$specify2", "$specify3", "$specrule"))
                        return true;
 
                if (cell->has_keep_attr())
index f9e45df674ba55e4b91bd73261625f036a14855e..facecd9a440155bcc76c284f97401011f867eb02 100644 (file)
@@ -1417,6 +1417,34 @@ endmodule
 
 // --------------------------------------------------------
 
+module \$specrule (EN_SRC, EN_DST, SRC, DST);
+
+parameter SRC_WIDTH = 1;
+parameter DST_WIDTH = 1;
+
+parameter SRC_PEN = 0;
+parameter SRC_POL = 0;
+
+parameter DST_PEN = 0;
+parameter DST_POL = 0;
+
+parameter LIMIT_GT = 0;
+parameter T_LIMIT = 0;
+
+input EN_SRC, EN_DST;
+input [SRC_WIDTH-1:0] SRC;
+input [DST_WIDTH-1:0] DST;
+
+`ifdef SIMLIB_SPECIFY
+specify
+       // TBD
+endspecify
+`endif
+
+endmodule
+
+// --------------------------------------------------------
+
 module \$assert (A, EN);
 
 input A, EN;