From 3cc95fb4be27a3e130563db102ed268876027288 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 21 Apr 2019 21:58:57 +0200 Subject: [PATCH] Add specify parser Signed-off-by: Clifford Wolf --- frontends/verilog/verilog_frontend.cc | 18 +- frontends/verilog/verilog_frontend.h | 7 +- frontends/verilog/verilog_lexer.l | 7 +- frontends/verilog/verilog_parser.y | 244 +++++++++++++++++++++++--- kernel/rtlil.cc | 10 ++ 5 files changed, 253 insertions(+), 33 deletions(-) diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index ed6ce2ecb..8202ab9d7 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -158,6 +158,9 @@ struct VerilogFrontend : public Frontend { log(" delete (* whitebox *) and (* lib_whitebox *) attributes from\n"); log(" all modules.\n"); log("\n"); + log(" -specify\n"); + log(" parse and import specify blocks\n"); + log("\n"); log(" -noopt\n"); log(" don't perform basic optimizations (such as const folding) in the\n"); log(" high-level front-end.\n"); @@ -228,6 +231,8 @@ struct VerilogFrontend : public Frontend { bool flag_nooverwrite = false; bool flag_overwrite = false; bool flag_defer = false; + bool flag_noblackbox = false; + bool flag_nowb = false; std::map defines_map; std::list include_dirs; std::list attributes; @@ -237,9 +242,8 @@ struct VerilogFrontend : public Frontend { formal_mode = false; norestrict_mode = false; assume_asserts_mode = false; - noblackbox_mode = false; lib_mode = false; - nowb_mode = false; + specify_mode = false; default_nettype_wire = true; log_header(design, "Executing Verilog-2005 frontend.\n"); @@ -342,7 +346,7 @@ struct VerilogFrontend : public Frontend { continue; } if (arg == "-noblackbox") { - noblackbox_mode = true; + flag_noblackbox = true; continue; } if (arg == "-lib") { @@ -351,7 +355,11 @@ struct VerilogFrontend : public Frontend { continue; } if (arg == "-nowb") { - nowb_mode = true; + flag_nowb = true; + continue; + } + if (arg == "-specify") { + specify_mode = true; continue; } if (arg == "-noopt") { @@ -450,7 +458,7 @@ struct VerilogFrontend : public Frontend { error_on_dpi_function(current_ast); AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, - flag_nomeminit, flag_nomem2reg, flag_mem2reg, noblackbox_mode, lib_mode, nowb_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); + flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); if (!flag_nopp) delete lexin; diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index ca40946cb..a7c9b2fe6 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -69,14 +69,11 @@ namespace VERILOG_FRONTEND // running in -assert-assumes mode extern bool assert_assumes_mode; - // running in -noblackbox mode - extern bool noblackbox_mode; - // running in -lib mode extern bool lib_mode; - // running in -nowb mode - extern bool nowb_mode; + // running in -specify mode + extern bool specify_mode; // lexer input stream extern std::istream *lexin; diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 6ef38252a..b73ccf5c1 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -148,7 +148,7 @@ YOSYS_NAMESPACE_END "endfunction" { return TOK_ENDFUNCTION; } "task" { return TOK_TASK; } "endtask" { return TOK_ENDTASK; } -"specify" { return TOK_SPECIFY; } +"specify" { return specify_mode ? TOK_SPECIFY : TOK_IGNORED_SPECIFY; } "endspecify" { return TOK_ENDSPECIFY; } "specparam" { return TOK_SPECPARAM; } "package" { SV_KEYWORD(TOK_PACKAGE); } @@ -411,6 +411,11 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { "+:" { return TOK_POS_INDEXED; } "-:" { return TOK_NEG_INDEXED; } +[-+]?[=*]> { + frontend_verilog_yylval.string = new std::string(yytext); + return TOK_SPECIFY_OPER; +} + "/*" { BEGIN(COMMENT); } . /* ignore comment body */ \n /* ignore comment body */ diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 40968d17a..2e6863302 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -59,7 +59,7 @@ namespace VERILOG_FRONTEND { std::vector case_type_stack; bool do_not_require_port_stubs; bool default_nettype_wire; - bool sv_mode, formal_mode, noblackbox_mode, lib_mode, nowb_mode; + bool sv_mode, formal_mode, lib_mode, specify_mode; bool noassert_mode, noassume_mode, norestrict_mode; bool assume_asserts_mode, assert_assumes_mode; bool current_wire_rand, current_wire_const; @@ -94,6 +94,20 @@ static void free_attr(std::map *al) delete al; } +struct specify_target { + char polarity_op; + AstNode *dst, *dat; +}; + +struct specify_triple { + AstNode *t_min, *t_avg, *t_max; +}; + +struct specify_rise_fall { + specify_triple rise; + specify_triple fall; +}; + %} %name-prefix "frontend_verilog_yy" @@ -102,10 +116,15 @@ static void free_attr(std::map *al) std::string *string; struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast; std::map *al; + struct specify_target *specify_target_ptr; + struct specify_triple *specify_triple_ptr; + struct specify_rise_fall *specify_rise_fall_ptr; bool boolean; + char ch; } -%token TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL +%token TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE +%token TOK_SVA_LABEL TOK_SPECIFY_OPER %token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM @@ -116,7 +135,8 @@ static void free_attr(std::map *al) %token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT %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 TOK_ENDSPECIFY TOK_SPECPARAM +%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY +%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM %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 @@ -130,6 +150,12 @@ static void free_attr(std::map *al) %type opt_signed opt_property unique_case_attr %type attr case_attr +%type specify_target +%type specify_triple +%type specify_rise_fall +%type specify_if +%type specify_edge + // operator precedence from low to high %left OP_LOR %left OP_LAND @@ -539,7 +565,7 @@ module_body: module_body_stmt: task_func_decl | specify_block |param_decl | localparam_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt | - always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl; + always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block; checker_decl: TOK_CHECKER TOK_ID ';' { @@ -697,15 +723,181 @@ task_func_body: task_func_body behavioral_stmt | /* empty */; +/*************************** specify parser ***************************/ + specify_block: - TOK_SPECIFY specify_item_opt TOK_ENDSPECIFY | - TOK_SPECIFY TOK_ENDSPECIFY ; + TOK_SPECIFY specify_item_list TOK_ENDSPECIFY; -specify_item_opt: - specify_item_opt specify_item | - specify_item ; +specify_item_list: + specify_item specify_item_list | + /* empty */; specify_item: + specify_if '(' specify_edge expr TOK_SPECIFY_OPER specify_target ')' '=' specify_rise_fall ';' { + AstNode *en_expr = $1; + char specify_edge = $3; + AstNode *src_expr = $4; + string *oper = $5; + specify_target *target = $6; + specify_rise_fall *timing = $9; + + if (specify_edge != 0 && target->dat == nullptr) + frontend_verilog_yyerror("Found specify edge but no data spec.\n"); + + 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 = target->dat ? "$specify3" : "$specify2"; + + char oper_polarity = 0; + char oper_type = oper->at(0); + + if (oper->size() == 3) { + oper_polarity = oper->at(0); + oper_type = oper->at(1); + } + + cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_type == '*', false, 1))); + cell->children.back()->str = "\\FULL"; + + cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity != 0, false, 1))); + cell->children.back()->str = "\\SRC_DST_PEN"; + + cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity == '+', false, 1))); + cell->children.back()->str = "\\SRC_DST_POL"; + + cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_min)); + cell->children.back()->str = "\\T_RISE_MIN"; + + cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_avg)); + cell->children.back()->str = "\\T_RISE_AVG"; + + cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_max)); + cell->children.back()->str = "\\T_RISE_MAX"; + + cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_min)); + cell->children.back()->str = "\\T_FALL_MIN"; + + cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_avg)); + cell->children.back()->str = "\\T_FALL_AVG"; + + cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_max)); + cell->children.back()->str = "\\T_FALL_MAX"; + + cell->children.push_back(new AstNode(AST_ARGUMENT, en_expr ? en_expr : AstNode::mkconst_int(1, false, 1))); + cell->children.back()->str = "\\EN"; + + cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr)); + cell->children.back()->str = "\\SRC"; + + cell->children.push_back(new AstNode(AST_ARGUMENT, target->dst)); + cell->children.back()->str = "\\DST"; + + if (target->dat) + { + cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge != 0, false, 1))); + cell->children.back()->str = "\\EDGE_EN"; + + cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge == 'p', false, 1))); + cell->children.back()->str = "\\EDGE_POL"; + + cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op != 0, false, 1))); + cell->children.back()->str = "\\DAT_DST_PEN"; + + cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op == '+', false, 1))); + cell->children.back()->str = "\\DAT_DST_POL"; + + cell->children.push_back(new AstNode(AST_ARGUMENT, target->dat)); + cell->children.back()->str = "\\DAT"; + } + + delete oper; + delete target; + delete timing; + }; + +specify_if: + TOK_IF '(' expr ')' { + $$ = $3; + } | + /* empty */ { + $$ = nullptr; + }; + +specify_target: + expr { + $$ = new specify_target; + $$->polarity_op = 0; + $$->dst = $1; + $$->dat = nullptr; + } | + '(' expr ':' expr ')'{ + $$ = new specify_target; + $$->polarity_op = 0; + $$->dst = $2; + $$->dat = $4; + } | + '(' expr TOK_NEG_INDEXED expr ')'{ + $$ = new specify_target; + $$->polarity_op = '-'; + $$->dst = $2; + $$->dat = $4; + } | + '(' expr TOK_POS_INDEXED expr ')'{ + $$ = new specify_target; + $$->polarity_op = '+'; + $$->dst = $2; + $$->dat = $4; + }; + +specify_edge: + TOK_POSEDGE { $$ = 'p'; } | + TOK_NEGEDGE { $$ = 'n'; } | + { $$ = 0; }; + +specify_rise_fall: + specify_triple { + $$ = new specify_rise_fall; + $$->rise = *$1; + $$->fall.t_min = $1->t_min->clone(); + $$->fall.t_avg = $1->t_avg->clone(); + $$->fall.t_max = $1->t_max->clone(); + delete $1; + } | + '(' specify_triple ',' specify_triple ')' { + $$ = new specify_rise_fall; + $$->rise = *$2; + $$->fall = *$4; + delete $2; + delete $4; + }; + +specify_triple: + expr { + $$ = new specify_triple; + $$->t_min = $1; + $$->t_avg = $1->clone(); + $$->t_max = $1->clone(); + } | + expr ':' expr ':' expr { + $$ = new specify_triple; + $$->t_min = $1; + $$->t_avg = $3; + $$->t_max = $5; + }; + +/******************** ignored specify parser **************************/ + +ignored_specify_block: + TOK_IGNORED_SPECIFY ignored_specify_item_opt TOK_ENDSPECIFY | + TOK_IGNORED_SPECIFY TOK_ENDSPECIFY ; + +ignored_specify_item_opt: + ignored_specify_item_opt ignored_specify_item | + ignored_specify_item ; + +ignored_specify_item: specparam_declaration // | pulsestyle_declaration // | showcancelled_declaration @@ -721,13 +913,13 @@ specparam_declaration: // and the 'non_opt_range' rule allows index ranges not allowed by 1364-2005 // exxxxtending this for SV specparam would change this anyhow specparam_range: - '[' constant_expression ':' constant_expression ']' ; + '[' ignspec_constant_expression ':' ignspec_constant_expression ']' ; list_of_specparam_assignments: specparam_assignment | list_of_specparam_assignments ',' specparam_assignment; specparam_assignment: - TOK_ID '=' constant_mintypmax_expression ; + ignspec_id '=' constant_mintypmax_expression ; /* pulsestyle_declaration : @@ -802,19 +994,19 @@ opt_polarity_operator : // Good enough for the time being specify_input_terminal_descriptor : - TOK_ID ; + ignspec_id ; // Good enough for the time being specify_output_terminal_descriptor : - TOK_ID ; + ignspec_id ; system_timing_declaration : - TOK_ID '(' system_timing_args ')' ';' ; + ignspec_id '(' system_timing_args ')' ';' ; system_timing_arg : - TOK_POSEDGE TOK_ID | - TOK_NEGEDGE TOK_ID | - expr ; + TOK_POSEDGE ignspec_id | + TOK_NEGEDGE ignspec_id | + ignspec_expr ; system_timing_args : system_timing_arg | @@ -871,19 +1063,27 @@ tzx_path_delay_expression : */ path_delay_expression : - constant_expression; + ignspec_constant_expression; constant_mintypmax_expression : - constant_expression - | constant_expression ':' constant_expression ':' constant_expression + ignspec_constant_expression + | ignspec_constant_expression ':' ignspec_constant_expression ':' ignspec_constant_expression ; // for the time being this is OK, but we may write our own expr here. // as I'm not sure it is legal to use a full expr here (probably not) // On the other hand, other rules requiring constant expressions also use 'expr' // (such as param assignment), so we may leave this as-is, perhaps adding runtime checks for constant-ness -constant_expression: - expr ; +ignspec_constant_expression: + expr { delete $1; }; + +ignspec_expr: + expr { delete $1; }; + +ignspec_id: + TOK_ID { delete $1; }; + +/**********************************************************************/ param_signed: TOK_SIGNED { diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 7e1159cac..7d5334eb1 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -1194,6 +1194,16 @@ namespace { return; } + if (cell->type == "$specify2") { + // FIXME + return; + } + + if (cell->type == "$specify3") { + // FIXME + 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; } -- 2.30.2