Add specify parser
authorClifford Wolf <clifford@clifford.at>
Sun, 21 Apr 2019 19:58:57 +0000 (21:58 +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/verilog/verilog_frontend.cc
frontends/verilog/verilog_frontend.h
frontends/verilog/verilog_lexer.l
frontends/verilog/verilog_parser.y
kernel/rtlil.cc

index ed6ce2ecb80075ed5c19eb1eeb8eb7fccd0f3939..8202ab9d75b91f5fe3d7de5e016aede4a758cf92 100644 (file)
@@ -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<std::string, std::string> defines_map;
                std::list<std::string> include_dirs;
                std::list<std::string> 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;
index ca40946cbdaade7003dee91f8ff93494f1028642..a7c9b2fe6ab71303f037d7c0ee5dfb2896766d76 100644 (file)
@@ -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;
index 6ef38252a1f03beeee65e0fa3fb6da9f300cf3b9..b73ccf5c1f19d30499fdc20d6d9a9e569ae72cbe 100644 (file)
@@ -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); }
 <COMMENT>.    /* ignore comment body */
 <COMMENT>\n   /* ignore comment body */
index 40968d17a12bcaf7052b00b0ca53b62e1b1a3b89..2e6863302ddf238cd68f3f74fadb2846a8286ba0 100644 (file)
@@ -59,7 +59,7 @@ namespace VERILOG_FRONTEND {
        std::vector<char> 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<std::string, AstNode*> *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<std::string, AstNode*> *al)
        std::string *string;
        struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast;
        std::map<std::string, YOSYS_NAMESPACE_PREFIX AST::AstNode*> *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 <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL
+%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
+%token <string> 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<std::string, AstNode*> *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<std::string, AstNode*> *al)
 %type <boolean> opt_signed opt_property unique_case_attr
 %type <al> attr case_attr
 
+%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 <ch> 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 {
index 7e1159cacd7cab59caf26b706d61aaba1638c85c..7d5334eb15d0c7c9f44509ab678e851235082db3 100644 (file)
@@ -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; }