diff --git a/PExpr.cc b/PExpr.cc index bce998419..b358542b5 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -126,9 +126,8 @@ PEBinary::~PEBinary() void PEBinary::declare_implicit_nets(LexicalScope*scope, NetNet::Type type) { - assert(left_ && right_); - left_->declare_implicit_nets(scope, type); - right_->declare_implicit_nets(scope, type); + if (left_) left_->declare_implicit_nets(scope, type); + if (right_) right_->declare_implicit_nets(scope, type); } bool PEBinary::has_aa_term(Design*des, NetScope*scope) const diff --git a/Statement.cc b/Statement.cc index e5f5f169e..e200f7734 100644 --- a/Statement.cc +++ b/Statement.cc @@ -206,8 +206,8 @@ const pform_name_t& PCallTask::path() const return path_; } -PCase::PCase(NetCase::TYPE t, PExpr*ex, svector*l) -: type_(t), expr_(ex), items_(l) +PCase::PCase(ivl_case_quality_t q, NetCase::TYPE t, PExpr*ex, svector*l) +: quality_(q), type_(t), expr_(ex), items_(l) { } diff --git a/Statement.h b/Statement.h index ae5e162b6..92791d9d2 100644 --- a/Statement.h +++ b/Statement.h @@ -254,7 +254,7 @@ class PCase : public Statement { Statement*stat; }; - PCase(NetCase::TYPE, PExpr*ex, svector*); + PCase(ivl_case_quality_t, NetCase::TYPE, PExpr*ex, svector*); ~PCase(); virtual NetProc* elaborate(Design*des, NetScope*scope) const; @@ -263,6 +263,7 @@ class PCase : public Statement { virtual void dump(ostream&out, unsigned ind) const; private: + ivl_case_quality_t quality_; NetCase::TYPE type_; PExpr*expr_; diff --git a/compiler.h b/compiler.h index 6eccc8743..fd50cd52f 100644 --- a/compiler.h +++ b/compiler.h @@ -1,7 +1,7 @@ #ifndef IVL_compiler_H #define IVL_compiler_H /* - * Copyright (c) 1999-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2019 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -177,9 +177,12 @@ extern bool gn_icarus_misc_flag; is false, then skip elaboration of specify behavior. */ extern bool gn_specify_blocks_flag; -/* If this flag is true, then elaborate assertions. If this flag is - false, then stub out assertion statements. */ -extern bool gn_assertions_flag; +/* If this flag is true, then elaborate supported assertion statements. If + this flag is false, then stub out supported assertion statements. */ +extern bool gn_supported_assertions_flag; +/* If this flag is true, then error on unsupported assertion statements. If + this flag is false, then stub out unsupported assertion statements. */ +extern bool gn_unsupported_assertions_flag; /* If this flag is true, then support/elaborate Verilog-AMS. */ extern bool gn_verilog_ams_flag; diff --git a/design_dump.cc b/design_dump.cc index 88cf88bea..cf8c1d4f3 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1150,15 +1150,29 @@ void NetBlock::dump(ostream&o, unsigned ind) const void NetCase::dump(ostream&o, unsigned ind) const { + o << setw(ind) << ""; + switch (quality_) { + case IVL_CASE_QUALITY_BASIC: + break; + case IVL_CASE_QUALITY_UNIQUE: + o << "unique "; + break; + case IVL_CASE_QUALITY_UNIQUE0: + o << "unique0 "; + break; + case IVL_CASE_QUALITY_PRIORITY: + o << "priority "; + break; + } switch (type_) { case EQ: - o << setw(ind) << "" << "case (" << *expr_ << ")" << endl; + o << "case (" << *expr_ << ")" << endl; break; case EQX: - o << setw(ind) << "" << "casex (" << *expr_ << ")" << endl; + o << "casex (" << *expr_ << ")" << endl; break; case EQZ: - o << setw(ind) << "" << "casez (" << *expr_ << ")" << endl; + o << "casez (" << *expr_ << ")" << endl; break; } diff --git a/driver/iverilog.man.in b/driver/iverilog.man.in index 2578969da..0f49fea4f 100644 --- a/driver/iverilog.man.in +++ b/driver/iverilog.man.in @@ -1,4 +1,4 @@ -.TH iverilog 1 "Sep 20th, 2019" "" "Version %M.%n%E" +.TH iverilog 1 "Oct 5th, 2019" "" "Version %M.%n%E" .SH NAME iverilog - Icarus Verilog compiler @@ -80,10 +80,11 @@ use any of the new \fIIEEE1800\fP keywords. Enable or disable (default) support for Verilog\-AMS. Very little Verilog\-AMS specific functionality is currently supported. .TP 8 -.B -gassertions\fI|\fP-gno-assertions +.B -gassertions\fI|\fP-gsupported-assertions\fI|\fP-gno-assertions Enable (default) or disable SystemVerilog assertions. When enabled, assertion statements are elaborated. When disabled, assertion statements -are parsed but ignored. +are parsed but ignored. The \fB\-gsupported-assertions\fP option only +enables assertions that are currently supported by the compiler. .TP 8 .B -gspecify\fI|\fP-gno-specify Enable or disable (default) specify block support. When enabled, @@ -129,7 +130,7 @@ default, parts of the expression that do not depend on the changed input value(s) are not re-evaluated. If an expression contains a call to a function that doesn't depend solely on its input values or that has side effects, the resulting behavior will differ from that -required by the standard. Using \fI\-gstrict\-ca\-eval\fP will force +required by the standard. Using \fB\-gstrict\-ca\-eval\fP will force standard compliant behavior (with some loss in performance). .TP 8 .B -gstrict-expr-width\fI|\fP-gno-strict-expr-width diff --git a/driver/main.c b/driver/main.c index b723d7ff3..56228637a 100644 --- a/driver/main.c +++ b/driver/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2019 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -748,6 +748,9 @@ static int process_generation(const char*name) else if (strcmp(name,"assertions") == 0) gen_assertions = "assertions"; + else if (strcmp(name,"supported-assertions") == 0) + gen_assertions = "supported-assertions"; + else if (strcmp(name,"no-assertions") == 0) gen_assertions = "no-assertions"; @@ -804,6 +807,7 @@ static int process_generation(const char*name) " 2009 -- IEEE1800-2009\n" " 2012 -- IEEE1800-2012\n" "Other generation flags:\n" + " assertions | supported-assertions | no-assertions\n" " specify | no-specify\n" " verilog-ams | no-verilog-ams\n" " std-include | no-std-include\n" @@ -1176,7 +1180,7 @@ int main(int argc, char **argv) if (version_flag || verbose_flag) { printf("Icarus Verilog version " VERSION " (" VERSION_TAG ")\n\n"); - printf("Copyright 1998-2017 Stephen Williams\n\n"); + printf("Copyright 1998-2019 Stephen Williams\n\n"); puts(NOTICE); } diff --git a/elaborate.cc b/elaborate.cc index 0875929f3..5af51cc64 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -2321,8 +2321,6 @@ NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope, if (!is_constant_ || !rv) return rv; - if (dynamic_cast(rv)) return rv; - cerr << get_fileline() << ": error: " "The RHS expression must be constant." << endl; cerr << get_fileline() << " : " @@ -3129,7 +3127,7 @@ NetProc* PCase::elaborate(Design*des, NetScope*scope) const icount += cur->expr.size(); } - NetCase*res = new NetCase(type_, expr, icount); + NetCase*res = new NetCase(quality_, type_, expr, icount); res->set_line(*this); /* Iterate over all the case items (guard/statement pairs) diff --git a/ivl_target.h b/ivl_target.h index 30ae0194f..f0ee992e9 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -434,6 +434,14 @@ typedef enum ivl_statement_type_e { IVL_ST_WHILE = 23 } ivl_statement_type_t; +/* Case statements can be tagged as unique/unique0/priority. */ +typedef enum ivl_case_quality_t { + IVL_CASE_QUALITY_BASIC = 0, /* no quality flags */ + IVL_CASE_QUALITY_UNIQUE = 1, + IVL_CASE_QUALITY_UNIQUE0 = 2, + IVL_CASE_QUALITY_PRIORITY = 3 +} ivl_case_quality_t; + /* SystemVerilog allows a system function to be called as a task. */ typedef enum ivl_sfunc_as_task_e { IVL_SFUNC_AS_TASK_ERROR = 0, @@ -2222,6 +2230,8 @@ extern ivl_scope_t ivl_stmt_call(ivl_statement_t net); extern unsigned ivl_stmt_case_count(ivl_statement_t net); /* IVL_ST_CASE,IVL_ST_CASER,IVL_ST_CASEX,IVL_ST_CASEZ */ extern ivl_expr_t ivl_stmt_case_expr(ivl_statement_t net, unsigned i); + /* IVL+ST_CASE,IVL_ST_CASER,IVL_ST_CASEX,IVL_ST_CASEZ */ +extern ivl_case_quality_t ivl_stmt_case_quality(ivl_statement_t net); /* IVL_ST_CASE,IVL_ST_CASER,IVL_ST_CASEX,IVL_ST_CASEZ */ extern ivl_statement_t ivl_stmt_case_stmt(ivl_statement_t net, unsigned i); /* IVL_ST_CONDIT IVL_ST_CASE IVL_ST_REPEAT IVL_ST_WHILE */ diff --git a/main.cc b/main.cc index 938100cca..60ec62e7e 100644 --- a/main.cc +++ b/main.cc @@ -1,5 +1,5 @@ const char COPYRIGHT[] = - "Copyright (c) 1998-2017 Stephen Williams (steve@icarus.com)"; + "Copyright (c) 1998-2019 Stephen Williams (steve@icarus.com)"; /* * This source code is free software; you can redistribute it @@ -104,7 +104,8 @@ generation_t generation_flag = GN_DEFAULT; bool gn_icarus_misc_flag = true; bool gn_cadence_types_flag = true; bool gn_specify_blocks_flag = true; -bool gn_assertions_flag = true; +bool gn_supported_assertions_flag = true; +bool gn_unsupported_assertions_flag = true; bool gn_io_range_error_flag = true; bool gn_strict_ca_eval_flag = false; bool gn_strict_expr_width_flag = false; @@ -331,10 +332,16 @@ static void process_generation_flag(const char*gen) gn_specify_blocks_flag = false; } else if (strcmp(gen,"assertions") == 0) { - gn_assertions_flag = true; + gn_supported_assertions_flag = true; + gn_unsupported_assertions_flag = true; + + } else if (strcmp(gen,"supported-assertions") == 0) { + gn_supported_assertions_flag = true; + gn_unsupported_assertions_flag = false; } else if (strcmp(gen,"no-assertions") == 0) { - gn_assertions_flag = false; + gn_supported_assertions_flag = false; + gn_unsupported_assertions_flag = false; } else if (strcmp(gen,"verilog-ams") == 0) { gn_verilog_ams_flag = true; diff --git a/net_proc.cc b/net_proc.cc index 68127445f..b82abe8f1 100644 --- a/net_proc.cc +++ b/net_proc.cc @@ -83,8 +83,8 @@ const NetProc* NetBlock::proc_next(const NetProc*cur) const return cur->next_; } -NetCase::NetCase(NetCase::TYPE c, NetExpr*ex, unsigned cnt) -: type_(c), expr_(ex), items_(cnt) +NetCase::NetCase(ivl_case_quality_t q, NetCase::TYPE c, NetExpr*ex, unsigned cnt) +: quality_(q), type_(c), expr_(ex), items_(cnt) { ivl_assert(*this, expr_); } diff --git a/netlist.h b/netlist.h index 6b85a5a2a..37ed539b7 100644 --- a/netlist.h +++ b/netlist.h @@ -3050,6 +3050,9 @@ class NetBlock : public NetProc { * way the comparisons are performed. Also, it is likely that the * target may be able to optimize differently. * + * Case statements can have unique, unique0, or priority attached to + * them. If not otherwise adorned, it is QBASIC. + * * Case can be one of three types: * EQ -- All bits must exactly match * EQZ -- z bits are don't care @@ -3059,13 +3062,15 @@ class NetCase : public NetProc { public: enum TYPE { EQ, EQX, EQZ }; - NetCase(TYPE c, NetExpr*ex, unsigned cnt); + + NetCase(ivl_case_quality_t q, TYPE c, NetExpr*ex, unsigned cnt); ~NetCase(); void set_case(unsigned idx, NetExpr*ex, NetProc*st); void prune(); + inline ivl_case_quality_t case_quality() const { return quality_; } TYPE type() const; const NetExpr*expr() const { return expr_; } inline unsigned nitems() const { return items_.size(); } @@ -3097,6 +3102,7 @@ class NetCase : public NetProc { NexusSet&nex_map, NetBus&nex_out, NetBus&enables, vector&bitmasks); + ivl_case_quality_t quality_; TYPE type_; struct Item { diff --git a/parse.y b/parse.y index eb10d6b72..e0152f763 100644 --- a/parse.y +++ b/parse.y @@ -408,6 +408,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector svector*event_expr; + ivl_case_quality_t case_quality; NetNet::Type nettype; PGBuiltin::Type gatetype; NetNet::PortType porttype; @@ -575,6 +576,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type udp_initial_expr_opt %type register_variable net_variable event_variable endlabel_opt class_declaration_endlabel_opt +%type block_identifier_opt %type register_variable_list net_variable_list event_variable_list %type list_of_identifiers loop_variables %type list_of_port_identifiers list_of_variable_port_identifiers @@ -652,6 +654,9 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type statement statement_item statement_or_null %type compressed_statement %type loop_statement for_step jump_statement +%type concurrent_assertion_statement +%type deferred_immediate_assertion_statement +%type simple_immediate_assertion_statement %type procedural_assertion_statement %type statement_or_null_list statement_or_null_list_opt @@ -667,11 +672,14 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type non_integer_type %type assert_or_assume +%type deferred_mode %type atom2_type %type module_start module_end %type lifetime lifetime_opt +%type unique_priority + %token K_TAND %right K_PLUS_EQ K_MINUS_EQ K_MUL_EQ K_DIV_EQ K_MOD_EQ K_AND_EQ K_OR_EQ %right K_XOR_EQ K_LS_EQ K_RS_EQ K_RSS_EQ @@ -724,6 +732,7 @@ assert_or_assume assertion_item /* IEEE1800-2012: A.6.10 */ : concurrent_assertion_item + | deferred_immediate_assertion_item ; assignment_pattern /* IEEE1800-2005: A.6.7.1 */ @@ -744,7 +753,9 @@ assignment_pattern /* IEEE1800-2005: A.6.7.1 */ implements it in a LALR way. */ block_identifier_opt /* */ : IDENTIFIER ':' + { $$ = $1; } | + { $$ = 0; } ; class_declaration /* IEEE1800-2005: A.1.2 */ @@ -988,16 +999,98 @@ class_new /* IEEE1800-2005 A.2.4 */ concurrent_assertion_statement and checker_instantiation rules. */ concurrent_assertion_item /* IEEE1800-2012 A.2.10 */ - : block_identifier_opt K_assert K_property '(' property_spec ')' statement_or_null - { /* */ - if (gn_assertions_flag) { - yyerror(@2, "sorry: concurrent_assertion_item not supported." - " Try -gno-assertion to turn this message off."); - } + : block_identifier_opt concurrent_assertion_statement + { delete $1; + delete $2; } - | block_identifier_opt K_assert K_property '(' error ')' statement_or_null + ; + +concurrent_assertion_statement /* IEEE1800-2012 A.2.10 */ + : assert_or_assume K_property '(' property_spec ')' statement_or_null %prec less_than_K_else + { /* */ + if (gn_unsupported_assertions_flag) { + yyerror(@1, "sorry: concurrent_assertion_item not supported." + " Try -gno-assertions or -gsupported-assertions" + " to turn this message off."); + } + $$ = 0; + } + | assert_or_assume K_property '(' property_spec ')' K_else statement_or_null + { /* */ + if (gn_unsupported_assertions_flag) { + yyerror(@1, "sorry: concurrent_assertion_item not supported." + " Try -gno-assertions or -gsupported-assertions" + " to turn this message off."); + } + $$ = 0; + } + | assert_or_assume K_property '(' property_spec ')' statement_or_null K_else statement_or_null + { /* */ + if (gn_unsupported_assertions_flag) { + yyerror(@1, "sorry: concurrent_assertion_item not supported." + " Try -gno-assertions or -gsupported-assertions" + " to turn this message off."); + } + $$ = 0; + } + | K_cover K_property '(' property_spec ')' statement_or_null + { /* */ + if (gn_unsupported_assertions_flag) { + yyerror(@1, "sorry: concurrent_assertion_item not supported." + " Try -gno-assertions or -gsupported-assertions" + " to turn this message off."); + } + $$ = 0; + } + /* For now, cheat, and use property_spec for the sequence specification. + They are syntactically identical. */ + | K_cover K_sequence '(' property_spec ')' statement_or_null + { /* */ + if (gn_unsupported_assertions_flag) { + yyerror(@1, "sorry: concurrent_assertion_item not supported." + " Try -gno-assertions or -gsupported-assertions" + " to turn this message off."); + } + $$ = 0; + } + | K_restrict K_property '(' property_spec ')' ';' + { /* */ + if (gn_unsupported_assertions_flag) { + yyerror(@2, "sorry: concurrent_assertion_item not supported." + " Try -gno-assertions or -gsupported-assertions" + " to turn this message off."); + } + $$ = 0; + } + | assert_or_assume K_property '(' error ')' statement_or_null %prec less_than_K_else { yyerrok; yyerror(@2, "error: Error in property_spec of concurrent assertion item."); + $$ = 0; + } + | assert_or_assume K_property '(' error ')' K_else statement_or_null + { yyerrok; + yyerror(@2, "error: Error in property_spec of concurrent assertion item."); + $$ = 0; + } + | assert_or_assume K_property '(' error ')' statement_or_null K_else statement_or_null + { yyerrok; + yyerror(@2, "error: Error in property_spec of concurrent assertion item."); + $$ = 0; + } + | K_cover K_property '(' error ')' statement_or_null + { yyerrok; + yyerror(@2, "error: Error in property_spec of concurrent assertion item."); + $$ = 0; + } + | K_cover K_sequence '(' error ')' statement_or_null + { yyerrok; + yyerror(@2, "error: Error in property_spec of concurrent assertion item."); + $$ = 0; + } + | K_restrict K_property '(' error ')' ';' + { yyerrok; + yyerror(@2, "error: Error in property_spec of concurrent assertion item."); + $$ = 0; } ; @@ -1061,6 +1154,7 @@ data_declaration /* IEEE1800-2005: A.2.1.3 */ | attribute_list_opt K_event event_variable_list ';' { if ($3) pform_make_events($3, @2.text, @2.first_line); } + | attribute_list_opt package_import_declaration ; data_type /* IEEE1800-2005: A.2.2.1 */ @@ -1166,6 +1260,84 @@ data_type_or_implicit_or_void } ; +deferred_immediate_assertion_item /* IEEE1800-2012: A.6.10 */ + : block_identifier_opt deferred_immediate_assertion_statement + { delete $1; + delete $2; + } + ; + +deferred_immediate_assertion_statement /* IEEE1800-2012 A.6.10 */ + : assert_or_assume deferred_mode '(' expression ')' statement_or_null %prec less_than_K_else + { + if (gn_unsupported_assertions_flag) { + yyerror(@1, "sorry: Deferred assertions are not supported." + " Try -gno-assertions or -gsupported-assertions" + " to turn this message off."); + } + delete $4; + delete $6; + $$ = 0; + } + | assert_or_assume deferred_mode '(' expression ')' K_else statement_or_null + { + if (gn_unsupported_assertions_flag) { + yyerror(@1, "sorry: Deferred assertions are not supported." + " Try -gno-assertions or -gsupported-assertions" + " to turn this message off."); + } + delete $4; + delete $7; + $$ = 0; + } + | assert_or_assume deferred_mode '(' expression ')' statement_or_null K_else statement_or_null + { + if (gn_unsupported_assertions_flag) { + yyerror(@1, "sorry: Deferred assertions are not supported." + " Try -gno-assertions or -gsupported-assertions" + " to turn this message off."); + } + delete $4; + delete $6; + delete $8; + $$ = 0; + } + | K_cover deferred_mode '(' expression ')' statement_or_null + { + /* Coverage collection is not currently supported. */ + delete $4; + delete $6; + $$ = 0; + } + | assert_or_assume deferred_mode '(' error ')' statement_or_null %prec less_than_K_else + { yyerror(@1, "error: Malformed conditional expression."); + $$ = $6; + } + | assert_or_assume deferred_mode '(' error ')' K_else statement_or_null + { yyerror(@1, "error: Malformed conditional expression."); + $$ = $7; + } + | assert_or_assume deferred_mode '(' error ')' statement_or_null K_else statement_or_null + { yyerror(@1, "error: Malformed conditional expression."); + $$ = $6; + } + | K_cover deferred_mode '(' error ')' statement_or_null + { yyerror(@1, "error: Malformed conditional expression."); + $$ = $6; + } + ; + +deferred_mode + : '#' DEC_NUMBER + { if (!$2->is_zero()) { + yyerror(@2, "error: Delay value must be zero for deferred assertion."); + } + delete $2; + $$ = 0; } + | K_final + { $$ = 1; } + ; + /* NOTE: The "module" rule of the description combines the module_declaration, program_declaration, and interface_declaration rules from the standard description. */ @@ -1574,12 +1746,10 @@ variable_decl_assignment /* IEEE1800-2005 A.2.3 */ delete[]$1; $$ = tmp; } - | IDENTIFIER '=' K_new '(' ')' + | IDENTIFIER '=' class_new { decl_assignment_t*tmp = new decl_assignment_t; tmp->name = lex_strings.make($1); - PENewClass*expr = new PENewClass; - FILE_NAME(expr, @3); - tmp->expr .reset(expr); + tmp->expr .reset($3); delete[]$1; $$ = tmp; } @@ -1845,65 +2015,17 @@ port_direction_opt | { $$ = NetNet::PIMPLICIT; } ; -property_expr /* IEEE1800-2012 A.2.10 */ - : expression +procedural_assertion_statement /* IEEE1800-2012 A.6.10 */ + : concurrent_assertion_statement + { $$ = $1; } + | simple_immediate_assertion_statement + { $$ = $1; } + | deferred_immediate_assertion_statement + { $$ = $1; } ; -procedural_assertion_statement /* IEEE1800-2012 A.6.10 */ - // $assertcontrol is not yet supported. - : assert_or_assume '(' expression ')' statement_or_null %prec less_than_K_else - { - if (gn_assertions_flag) { - listarg_list; - PCallTask*tmp1 = new PCallTask(lex_strings.make("$error"), arg_list); - FILE_NAME(tmp1, @1); - PCondit*tmp2 = new PCondit($3, $5, tmp1); - FILE_NAME(tmp2, @1); - $$ = tmp2; - } else { - $$ = 0; - } - } - | assert_or_assume '(' expression ')' K_else statement_or_null - { - if (gn_assertions_flag) { - PCondit*tmp = new PCondit($3, 0, $6); - FILE_NAME(tmp, @1); - $$ = tmp; - } else { - $$ = 0; - } - } - | assert_or_assume '(' expression ')' statement_or_null K_else statement_or_null - { - if (gn_assertions_flag) { - PCondit*tmp = new PCondit($3, $5, $7); - FILE_NAME(tmp, @1); - $$ = tmp; - } else { - $$ = 0; - } - } - | K_cover '(' expression ')' statement_or_null - // Coverage collection is not currently supported. - { $$ = 0; } - - | assert_or_assume '(' error ')' statement_or_null %prec less_than_K_else - { yyerror(@1, "error: Malformed conditional expression."); - $$ = $5; - } - | assert_or_assume '(' error ')' K_else statement_or_null - { yyerror(@1, "error: Malformed conditional expression."); - $$ = $6; - } - | assert_or_assume '(' error ')' statement_or_null K_else statement_or_null - { yyerror(@1, "error: Malformed conditional expression."); - $$ = $5; - } - | K_cover '(' error ')' statement_or_null - { yyerror(@1, "error: Malformed conditional expression."); - $$ = $5; - } +property_expr /* IEEE1800-2012 A.2.10 */ + : expression ; /* The property_qualifier rule is as literally described in the LRM, @@ -1956,6 +2078,72 @@ signing /* IEEE1800-2005: A.2.2.1 */ | K_unsigned { $$ = false; } ; +simple_immediate_assertion_statement /* IEEE1800-2012 A.6.10 */ + : assert_or_assume '(' expression ')' statement_or_null %prec less_than_K_else + { + if (gn_supported_assertions_flag) { + listarg_list; + PCallTask*tmp1 = new PCallTask(lex_strings.make("$error"), arg_list); + FILE_NAME(tmp1, @1); + PCondit*tmp2 = new PCondit($3, $5, tmp1); + FILE_NAME(tmp2, @1); + $$ = tmp2; + } else { + delete $3; + delete $5; + $$ = 0; + } + } + | assert_or_assume '(' expression ')' K_else statement_or_null + { + if (gn_supported_assertions_flag) { + PCondit*tmp = new PCondit($3, 0, $6); + FILE_NAME(tmp, @1); + $$ = tmp; + } else { + delete $3; + delete $6; + $$ = 0; + } + } + | assert_or_assume '(' expression ')' statement_or_null K_else statement_or_null + { + if (gn_supported_assertions_flag) { + PCondit*tmp = new PCondit($3, $5, $7); + FILE_NAME(tmp, @1); + $$ = tmp; + } else { + delete $3; + delete $5; + delete $7; + $$ = 0; + } + } + | K_cover '(' expression ')' statement_or_null + { + /* Coverage collection is not currently supported. */ + delete $3; + delete $5; + $$ = 0; + } + | assert_or_assume '(' error ')' statement_or_null %prec less_than_K_else + { yyerror(@1, "error: Malformed conditional expression."); + $$ = $5; + } + | assert_or_assume '(' error ')' K_else statement_or_null + { yyerror(@1, "error: Malformed conditional expression."); + $$ = $6; + } + | assert_or_assume '(' error ')' statement_or_null K_else statement_or_null + { yyerror(@1, "error: Malformed conditional expression."); + $$ = $5; + } + | K_cover '(' error ')' statement_or_null + { yyerror(@1, "error: Malformed conditional expression."); + $$ = $5; + } + ; + simple_type_or_string /* IEEE1800-2005: A.2.2.1 */ : integer_vector_type { ivl_variable_type_t use_vtype = $1; @@ -6433,27 +6621,28 @@ statement_item /* This is roughly statement_item in the LRM */ | jump_statement { $$ = $1; } - | K_case '(' expression ')' case_items K_endcase - { PCase*tmp = new PCase(NetCase::EQ, $3, $5); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | K_casex '(' expression ')' case_items K_endcase - { PCase*tmp = new PCase(NetCase::EQX, $3, $5); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | K_casez '(' expression ')' case_items K_endcase - { PCase*tmp = new PCase(NetCase::EQZ, $3, $5); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | K_case '(' expression ')' error K_endcase - { yyerrok; } - | K_casex '(' expression ')' error K_endcase - { yyerrok; } - | K_casez '(' expression ')' error K_endcase - { yyerrok; } + | unique_priority K_case '(' expression ')' case_items K_endcase + { PCase*tmp = new PCase($1, NetCase::EQ, $4, $6); + FILE_NAME(tmp, @2); + $$ = tmp; + } + | unique_priority K_casex '(' expression ')' case_items K_endcase + { PCase*tmp = new PCase($1, NetCase::EQX, $4, $6); + FILE_NAME(tmp, @2); + $$ = tmp; + } + | unique_priority K_casez '(' expression ')' case_items K_endcase + { PCase*tmp = new PCase($1, NetCase::EQZ, $4, $6); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | unique_priority K_case '(' expression ')' error K_endcase + { yyerrok; } + | unique_priority K_casex '(' expression ')' error K_endcase + { yyerrok; } + | unique_priority K_casez '(' expression ')' error K_endcase + { yyerrok; } + | K_if '(' expression ')' statement_or_null %prec less_than_K_else { PCondit*tmp = new PCondit($3, $5, 0); FILE_NAME(tmp, @1); @@ -7108,6 +7297,13 @@ udp_primitive } ; +unique_priority + : { $$ = IVL_CASE_QUALITY_BASIC; } + | K_unique { $$ = IVL_CASE_QUALITY_UNIQUE; } + | K_unique0 { $$ = IVL_CASE_QUALITY_UNIQUE0; } + | K_priority { $$ = IVL_CASE_QUALITY_PRIORITY; } + ; + /* Many keywords can be optional in the syntax, although their presence is significant. This is a fairly common pattern so collect those rules here. */ diff --git a/pform.cc b/pform.cc index c8a42bb17..18b391f50 100644 --- a/pform.cc +++ b/pform.cc @@ -2356,7 +2356,22 @@ void pform_make_modgates(const struct vlltype&loc, svector*gates, std::list*attr) { + // The grammer should not allow module gates to happen outside + // an active module. But if really bad input errors combine in + // an ugly way with error recovery, then catch this + // implausible situation and return an error. + if (pform_cur_module.empty()) { + cerr << loc << ": internal error: " + << "Module instantiations outside module scope are not possible." + << endl; + error_count += 1; + delete gates; + return; + } assert(! pform_cur_module.empty()); + + // Detect some more realistic errors. + if (pform_cur_module.front()->program_block) { cerr << loc << ": error: Module instantiations are not allowed in " << "program blocks." << endl; @@ -2492,7 +2507,7 @@ void pform_make_var_init(const struct vlltype&li, PEIdent*lval = new PEIdent(name); FILE_NAME(lval, li); - PAssign*ass = new PAssign(lval, expr, true); + PAssign*ass = new PAssign(lval, expr, !gn_system_verilog()); FILE_NAME(ass, li); lexical_scope->var_inits.push_back(ass); diff --git a/pform_dump.cc b/pform_dump.cc index 97a6f13af..099271d0c 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -840,6 +840,19 @@ void PCallTask::dump(ostream&out, unsigned ind) const void PCase::dump(ostream&out, unsigned ind) const { out << setw(ind) << ""; + switch (quality_) { + case IVL_CASE_QUALITY_BASIC: + break; + case IVL_CASE_QUALITY_UNIQUE: + out << "unique "; + break; + case IVL_CASE_QUALITY_UNIQUE0: + out << "unique0 "; + break; + case IVL_CASE_QUALITY_PRIORITY: + out << "priority "; + break; + } switch (type_) { case NetCase::EQ: out << "case"; diff --git a/t-dll-api.cc b/t-dll-api.cc index 89b0a5aa2..12b829cca 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -2728,6 +2728,22 @@ extern "C" ivl_expr_t ivl_stmt_case_expr(ivl_statement_t net, unsigned idx) } } +extern "C" ivl_case_quality_t ivl_stmt_case_quality(ivl_statement_t net) +{ + assert(net); + switch (net->type_) { + case IVL_ST_CASE: + case IVL_ST_CASER: + case IVL_ST_CASEX: + case IVL_ST_CASEZ: + return net->u_.case_.quality; + + default: + assert(0); + return IVL_CASE_QUALITY_BASIC; + } +} + extern "C" ivl_statement_t ivl_stmt_case_stmt(ivl_statement_t net, unsigned idx) { assert(net); diff --git a/t-dll-proc.cc b/t-dll-proc.cc index ba0d4b1a0..ca61064e3 100644 --- a/t-dll-proc.cc +++ b/t-dll-proc.cc @@ -497,6 +497,7 @@ void dll_target::proc_case(const NetCase*net) } assert(stmt_cur_->type_ != IVL_ST_NONE); + stmt_cur_->u_.case_.quality = net->case_quality(); assert(expr_ == 0); assert(net->expr()); net->expr()->expr_scan(this); diff --git a/t-dll.h b/t-dll.h index 879a5c966..98d041e00 100644 --- a/t-dll.h +++ b/t-dll.h @@ -810,6 +810,7 @@ struct ivl_statement_s { } block_; struct { /* IVL_ST_CASE, IVL_ST_CASEX, IVL_ST_CASEZ */ + ivl_case_quality_t quality; ivl_expr_t cond; unsigned ncase; ivl_expr_t*case_ex; diff --git a/tgt-stub/statement.c b/tgt-stub/statement.c index 4eb8037a2..d52d8db4d 100644 --- a/tgt-stub/statement.c +++ b/tgt-stub/statement.c @@ -375,8 +375,24 @@ void show_statement(ivl_statement_t net, unsigned ind) case IVL_ST_CASEZ: case IVL_ST_CASER: case IVL_ST_CASE: { + ivl_case_quality_t qual = ivl_stmt_case_quality(net); unsigned cnt = ivl_stmt_case_count(net); - fprintf(out, "%*scase (...) <%u cases>\n", ind, "", cnt); + const char*qual_txt = ""; + switch (qual) { + case IVL_CASE_QUALITY_BASIC: + qual_txt = "basic"; + break; + case IVL_CASE_QUALITY_UNIQUE: + qual_txt = "unique"; + break; + case IVL_CASE_QUALITY_UNIQUE0: + qual_txt = "unique0"; + break; + case IVL_CASE_QUALITY_PRIORITY: + qual_txt = "priority"; + break; + } + fprintf(out, "%*scase (...) <%u cases, %s>\n", ind, "", cnt, qual_txt); show_expression(ivl_stmt_cond_expr(net), ind+4); for (idx = 0 ; idx < cnt ; idx += 1) { diff --git a/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index 889371ee7..b99bd6797 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -1084,8 +1084,9 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net) ivl_type_t prop_type = ivl_type_prop_type(sig_type, prop_idx); if (ivl_type_base(prop_type) == IVL_VT_BOOL) { - assert(ivl_type_packed_dimensions(prop_type) == 1); - assert(ivl_type_packed_msb(prop_type,0) >= ivl_type_packed_lsb(prop_type, 0)); + assert(ivl_type_packed_dimensions(prop_type) == 0 || + (ivl_type_packed_dimensions(prop_type) == 1 && + ivl_type_packed_msb(prop_type,0) >= ivl_type_packed_lsb(prop_type, 0))); draw_eval_vec4(rval); if (ivl_expr_value(rval)!=IVL_VT_BOOL) @@ -1097,8 +1098,9 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net) fprintf(vvp_out, " %%pop/obj 1, 0;\n"); } else if (ivl_type_base(prop_type) == IVL_VT_LOGIC) { - assert(ivl_type_packed_dimensions(prop_type) == 1); - assert(ivl_type_packed_msb(prop_type,0) >= ivl_type_packed_lsb(prop_type, 0)); + assert(ivl_type_packed_dimensions(prop_type) == 0 || + (ivl_type_packed_dimensions(prop_type) == 1 && + ivl_type_packed_msb(prop_type,0) >= ivl_type_packed_lsb(prop_type, 0))); draw_eval_vec4(rval); diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 407df5219..fb1f22400 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -644,6 +644,7 @@ static int show_stmt_block_named(ivl_statement_t net, ivl_scope_t scope) static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope) { int rc = 0; + ivl_case_quality_t qual = ivl_stmt_case_quality(net); ivl_expr_t expr = ivl_stmt_cond_expr(net); unsigned count = ivl_stmt_case_count(net); @@ -651,6 +652,12 @@ static int show_stmt_case(ivl_statement_t net, ivl_scope_t sscope) unsigned idx, default_case; + if (qual != IVL_CASE_QUALITY_BASIC) { + fprintf(stderr, "%s:%u: tgt-vvp sorry: " + "Case unique/unique0/priority qualities are ignored.\n", + ivl_stmt_file(net), ivl_stmt_lineno(net)); + } + show_stmt_file_line(net, "Case statement."); local_count += count + 1;