From 71c38d9de527e1a8b55ba295df459fbcf2a0fe47 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 23 Apr 2019 15:46:40 +0200 Subject: [PATCH] Add $specrule cells for $setup/$hold/$skew specify rules Signed-off-by: Clifford Wolf --- frontends/ast/ast.cc | 4 +- frontends/ast/genrtlil.cc | 6 +++ frontends/verilog/verilog_lexer.l | 11 +++++ frontends/verilog/verilog_parser.y | 69 +++++++++++++++++++++++++++++- kernel/celltypes.h | 2 + kernel/rtlil.cc | 15 +++++++ manual/CHAPTER_CellLib.tex | 2 +- passes/opt/opt_clean.cc | 2 +- techlibs/common/simlib.v | 28 ++++++++++++ 9 files changed, 133 insertions(+), 6 deletions(-) diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 6b3604ee5..5623541b2 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -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; diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index b2a22b49a..48bd466e6 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -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; diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index f49f9d3a2..cd96236a1 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -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); } . /* ignore comment body */ \n /* ignore comment body */ diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 218d6f738..0a41ba581 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -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 %type specify_triple %type specify_rise_fall -%type specify_if +%type specify_if specify_condition %type 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; diff --git a/kernel/celltypes.h b/kernel/celltypes.h index f8c73ed83..4e91eddda 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -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(), true); setup_type("$specify3", {EN, SRC, DST, DAT}, pool(), true); + setup_type("$specrule", {EN_SRC, EN_DST, SRC, DST}, pool(), true); } void setup_internals_eval() diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 4522b0a08..dae3698a9 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -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; } diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex index 96a309552..cb1bcf1be 100644 --- a/manual/CHAPTER_CellLib.tex +++ b/manual/CHAPTER_CellLib.tex @@ -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} diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index 3f38dd580..3e131d2af 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -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()) diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index f9e45df67..facecd9a4 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -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; -- 2.30.2