From c2feeb03df0a7ed91059e178f6dcef53dcb54311 Mon Sep 17 00:00:00 2001 From: Sreeraj R Date: Sat, 20 Jun 2009 09:28:46 +0530 Subject: [PATCH] System Verilog timeunit and timeprecision addition This patch adds timeunit and timeprecision keywords.Use -gsystem-verilog generation flag to use this feature --- compiler.h | 2 + lexor.lex | 21 ++++++ lexor_keyword.gperf | 2 + parse.y | 71 ++++++++++++++++++- pform.cc | 168 ++++++++++++++++++++++++++++++++++++++++++++ pform.h | 6 ++ 6 files changed, 267 insertions(+), 3 deletions(-) diff --git a/compiler.h b/compiler.h index 934344b74..1dcc050a7 100644 --- a/compiler.h +++ b/compiler.h @@ -134,6 +134,8 @@ extern bool gn_specify_blocks_flag; /* If this flag is true, then support/elaborate Verilog-AMS. */ extern bool gn_verilog_ams_flag; +extern bool gn_system_verilog_flag; + /* If this flag is false a warning is printed when the port declaration is scalar and the net/register definition is vectored. */ extern bool gn_io_range_error_flag; diff --git a/lexor.lex b/lexor.lex index c3937fc64..0ca016179 100644 --- a/lexor.lex +++ b/lexor.lex @@ -107,6 +107,8 @@ W [ \t\b\f\r]+ S [afpnumkKMGT] +TU [munpf] + %% /* Recognize the various line directives. */ @@ -323,6 +325,25 @@ S [afpnumkKMGT] based_size = yylval.number->as_ulong(); return DEC_NUMBER; } +[0-9]+{TU}?s { + if(gn_system_verilog_flag) + { + yylval.text = strdupnew(yytext); + return TIME_LITERAL; + } + else + REJECT; + } + +[0-9]*\.[0-9]+{TU}?s { + if(gn_system_verilog_flag) + { + yylval.text = strdupnew(yytext); + return TIME_LITERAL; + } + else + REJECT; + } /* These rules handle the scaled real literals from Verilog-AMS. The value is a number with a single letter scale factor. If verilog-ams is not enabled, then reject this rule. If it is diff --git a/lexor_keyword.gperf b/lexor_keyword.gperf index 5ba577a71..e07c0bdc5 100644 --- a/lexor_keyword.gperf +++ b/lexor_keyword.gperf @@ -162,6 +162,8 @@ tan, GN_KEYWORDS_VAMS_2_3, K_tan tanh, GN_KEYWORDS_VAMS_2_3, K_tanh task, GN_KEYWORDS_1364_1995, K_task time, GN_KEYWORDS_1364_1995, K_time +timeprecision, GN_KEYWORDS_1800_2005, K_timeprecision +timeunit, GN_KEYWORDS_1800_2005, K_timeunit tran, GN_KEYWORDS_1364_1995, K_tran tranif0, GN_KEYWORDS_1364_1995, K_tranif0 tranif1, GN_KEYWORDS_1364_1995, K_tranif1 diff --git a/parse.y b/parse.y index 44f09da35..eb32ddd55 100644 --- a/parse.y +++ b/parse.y @@ -218,7 +218,7 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2) list *dimensions; }; -%token IDENTIFIER SYSTEM_IDENTIFIER STRING +%token IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL %token DISCIPLINE_IDENTIFIER %token PATHPULSE_IDENTIFIER %token BASED_NUMBER DEC_NUMBER @@ -269,7 +269,8 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2) %token K_wone K_uwire /* The new tokens from 1800-2005. */ -%token K_always_comb K_always_ff K_always_latch K_assert +%token K_always_comb K_always_ff K_always_latch K_assert +%token K_timeprecision K_timeunit /* The new tokens for Verilog-AMS 2.3. */ %token K_abs K_abstol K_access K_acos K_acosh K_analog K_asin K_asinh @@ -728,6 +729,7 @@ description delete[] $3; delete[] $5; } + | timeunits_declaration ; /* The discipline and nature declarations used to take no ';' after @@ -736,6 +738,67 @@ description choose to make the ';' optional in this context. */ optional_semicolon : ';' | ; +timeunits_declaration_opt + :local_timeunits_declaration + | + ; + +timeunits_declaration + : K_timeprecision TIME_LITERAL ';' + K_timeunit TIME_LITERAL ';' + { + pform_set_timeprecision($2,false,false); + pform_set_timeunit($5,false,false); + } + | K_timeunit TIME_LITERAL ';' + K_timeprecision TIME_LITERAL ';' + { + pform_set_timeunit($2,false,false); + pform_set_timeprecision($5,false,false); + } + | K_timeunit TIME_LITERAL ';' + { + pform_set_timeunit($2,false,false); + } + | K_timeprecision TIME_LITERAL ';' + { + pform_set_timeprecision($2,false,false); + } + + ; + +local_timeunits_declaration + : K_timeprecision TIME_LITERAL ';' + K_timeunit TIME_LITERAL ';' + { + pform_set_timeprecision($2,true,false); + pform_set_timeunit($5,true,false); + } + | K_timeunit TIME_LITERAL ';' + K_timeprecision TIME_LITERAL ';' + { + pform_set_timeunit($2,true,false); + pform_set_timeprecision($5,true,false); + } + | K_timeunit TIME_LITERAL ';' + { + pform_set_timeunit($2,true,false); + } + | K_timeprecision TIME_LITERAL ';' + { + pform_set_timeprecision($2,true,false); + } + +timeunits_declaration_check + : K_timeunit TIME_LITERAL ';' + { + pform_set_timeunit($2,true,true); + } + | K_timeprecision TIME_LITERAL ';' + { + pform_set_timeprecision($2,true,true); + } + ; discipline_declaration : K_discipline IDENTIFIER optional_semicolon { pform_start_discipline($2); } @@ -1986,6 +2049,7 @@ module : attribute_list_opt module_start IDENTIFIER module_port_list_opt module_attribute_foreign ';' { pform_module_set_ports($6); } + timeunits_declaration_opt module_item_list_opt K_endmodule { Module::UCDriveType ucd; @@ -2463,7 +2527,8 @@ module_item } | KK_attribute '(' error ')' ';' { yyerror(@1, "error: Malformed $attribute parameter list."); } - ; + | timeunits_declaration_check + ; automatic_opt : K_automatic { $$ = true; } diff --git a/pform.cc b/pform.cc index 1e881c80f..f824fb0ec 100644 --- a/pform.cc +++ b/pform.cc @@ -73,6 +73,19 @@ static NetNet::Type pform_default_nettype = NetNet::WIRE; static int pform_time_unit; static int pform_time_prec; +/* These two flags check the initial timeprecison and timeunit + * declaration inside a module + */ +static bool tp_decl_flag = false; +static bool tu_decl_flag = false; + +/* + * Flags used to set time_from_timescale based on timeunit and + * timeprecision + */ +static bool tu_valid_flag = false; +static bool tp_valid_flag = false; + static char*pform_timescale_file = 0; static unsigned pform_timescale_line; @@ -339,6 +352,156 @@ void pform_set_timescale(int unit, int prec, } } +void pform_set_timeunit(const char*txt,bool in_module,bool only_check) +{ + unsigned num; + const char*cp = txt + strspn(txt, " \t"); + char*tmp; + const char*ctmp; + + int val = 0; + num = strtoul(cp, &tmp, 10); + if (num == 0) { + VLerror(yylloc, "Invalid timeunit string."); + return; + } + + while (num >= 10) { + val += 1; + num /= 10; + } + if (num != 1) { + VLerror(yylloc, "Invalid timeunit number."); + return; + } + + cp = tmp; + cp += strspn(cp, " \t"); + ctmp = cp + strcspn(cp, " \t/"); + + if (strncmp("s", cp, ctmp-cp) == 0) { + val -= 0; + + } else if (strncmp("ms", cp, ctmp-cp) == 0) { + val -= 3; + + } else if (strncmp("us", cp, ctmp-cp) == 0) { + val -= 6; + + } else if (strncmp("ns", cp, ctmp-cp) == 0) { + val -= 9; + + } else if (strncmp("ps", cp, ctmp-cp) == 0) { + val -= 12; + + } else if (strncmp("fs", cp, ctmp-cp) == 0) { + val -= 15; + + } else { + VLerror(yylloc, "Invalid unit of measurement"); + return; + } + if(in_module ) + { + if(!only_check) + { + pform_cur_module->time_unit = val; + tu_decl_flag=true; + tu_valid_flag=true; + } + else if (!tu_decl_flag) + { + VLerror(yylloc, "Timeunit declaration not found after module declaration"); + return; + } + else if(pform_cur_module->time_unit!= val) + { + VLerror(yylloc, "Timeliteral do not match the initial timeunit declaration"); + return; + } + + } + else + { + tu_valid_flag=true; + pform_time_unit = val; + } +} + +void pform_set_timeprecision(const char*txt,bool in_module,bool only_check) +{ + unsigned num; + const char*cp = txt + strspn(txt, " \t"); + char*tmp; + const char*ctmp; + + int val = 0; + num = strtoul(cp, &tmp, 10); + if (num == 0) { + VLerror(yylloc, "Invalid timeprecision string."); + return; + } + + while (num >= 10) { + val += 1; + num /= 10; + } + if (num != 1) { + VLerror(yylloc, "Invalid timeprecision number."); + return; + } + + cp = tmp; + cp += strspn(cp, " \t"); + ctmp = cp + strcspn(cp, " \t/"); + + if (strncmp("s", cp, ctmp-cp) == 0) { + val -= 0; + + } else if (strncmp("ms", cp, ctmp-cp) == 0) { + val -= 3; + + } else if (strncmp("us", cp, ctmp-cp) == 0) { + val -= 6; + + } else if (strncmp("ns", cp, ctmp-cp) == 0) { + val -= 9; + + } else if (strncmp("ps", cp, ctmp-cp) == 0) { + val -= 12; + + } else if (strncmp("fs", cp, ctmp-cp) == 0) { + val -= 15; + + } else { + VLerror(yylloc, "Invalid unit of measurement"); + return; + } + if(in_module) + { + if(!only_check) + { + pform_cur_module->time_precision = val; + tp_decl_flag=true; + tp_valid_flag=true; + } + else if (!tp_decl_flag) + { + VLerror(yylloc, "Timeprecision declaration not found after module declaration"); + return; + } + else if(pform_cur_module->time_precision!= val) + { + VLerror(yylloc, "Timeliteral do not match the initial timeprecision declaration"); + return; + } + } + else + { + pform_time_prec = val; + tp_valid_flag=true; + } +} verinum* pform_verinum_with_size(verinum*siz, verinum*val, const char*file, unsigned lineno) @@ -471,6 +634,7 @@ void pform_endmodule(const char*name, bool in_celldefine, Module::UCDriveType uc_drive) { assert(pform_cur_module); + pform_cur_module->time_from_timescale = (tp_valid_flag && tu_valid_flag)|| pform_timescale_file != 0; perm_string mod_name = pform_cur_module->mod_name(); assert(strcmp(name, mod_name) == 0); pform_cur_module->is_cell = in_celldefine; @@ -495,6 +659,10 @@ void pform_endmodule(const char*name, bool in_celldefine, ivl_assert(*pform_cur_module, lexical_scope == 0); pform_cur_module = 0; + tp_decl_flag=false; + tu_decl_flag=false; + tu_valid_flag=false; + tp_valid_flag=false; } void pform_genvars(const struct vlltype&li, list*names) diff --git a/pform.h b/pform.h index 53e56f38e..13e93bb83 100644 --- a/pform.h +++ b/pform.h @@ -409,4 +409,10 @@ extern PExpr* pform_make_branch_probe_expression(const struct vlltype&loc, extern PExpr* pform_make_branch_probe_expression(const struct vlltype&loc, char*name, char*branch); +/* + * Timeunit and precision setting function + */ +extern void pform_set_timeunit(const char*txt,bool in_module,bool only_check); +extern void pform_set_timeprecision(const char*txt,bool in_module,bool only_check); + #endif