diff --git a/elab_type.cc b/elab_type.cc index ae9b5f39a..62f28bbd7 100644 --- a/elab_type.cc +++ b/elab_type.cc @@ -180,6 +180,7 @@ netstruct_t* struct_type_t::elaborate_type_raw(Design*des, NetScope*scope) const netstruct_t*res = new netstruct_t; res->packed(packed_flag); + res->set_signed(signed_flag); if (union_flag) res->union_flag(true); diff --git a/ivtest/ivltests/struct_signed.v b/ivtest/ivltests/struct_signed.v new file mode 100644 index 000000000..eccc9d06a --- /dev/null +++ b/ivtest/ivltests/struct_signed.v @@ -0,0 +1,58 @@ +// Tests that packed structs can have signed/unsigned modifier and that signed +// packed structs when used as a primary behave correctly. + +module test; + + // Unsigned by default + struct packed { + logic [15:0] x; + } s1; + + // Explicitly unsigned + struct packed unsigned { + logic [15:0] x; + } s2; + + // Explicitly signed + struct packed signed { + logic [15:0] x; + } s3; + + + bit failed = 1'b0; + + `define check(x) \ + if (!(x)) begin \ + $display("FAILED: ", `"x`"); \ + failed = 1'b1; \ + end + + initial begin + s1 = -1; + s2 = -1; + s3 = -1; + + `check(!$is_signed(s1)); + `check(!$is_signed(s2)); + `check($is_signed(s3)); + + // These evaluate as signed + `check($signed(s1) < 0); + `check($signed(s2) < 0); + `check(s3 < 0); + + // These all evaluate as unsigned + `check(s1 > 0); + `check(s2 > 0); + `check(s3.x > 0) + `check(s3[15:0] > 0) + `check({s3} > 0) + `check($unsigned(s3) > 0) + `check(s3 > 16'h0) + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/regress-sv.list b/ivtest/regress-sv.list index 530bfd72c..80d054047 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -383,6 +383,7 @@ struct_packed_array2 normal,-g2009 ivltests struct_packed_sysfunct normal,-g2009 ivltests struct_packed_write_read2 normal,-g2009 ivltests struct_invalid_member CE,-g2009 ivltests gold=struct_invalid_member.gold +struct_signed normal,-g2009 ivltests sv-constants normal,-g2005-sv ivltests sv_array_assign_pattern2 normal,-g2009 ivltests sv_cast_integer normal,-g2005-sv ivltests diff --git a/ivtest/regress-vlog95.list b/ivtest/regress-vlog95.list index fdb1934a6..a595d4969 100644 --- a/ivtest/regress-vlog95.list +++ b/ivtest/regress-vlog95.list @@ -838,6 +838,7 @@ size_cast3 normal,-g2009,-pallowsigned=1 ivltests size_cast5 normal,-g2009,-pallowsigned=1 ivltests struct_packed_array normal,-g2009,-pallowsigned=1 ivltests struct_packed_array2 normal,-g2009,-pallowsigned=1 ivltests +struct_signed normal,-g2009,-pallowsigned=1 ivltests sv_for_variable normal,-g2009,-pallowsigned=1 ivltests sv_foreach1 normal,-g2009,-pallowsigned=1 ivltests sv_foreach5 normal,-g2009,-pallowsigned=1 ivltests diff --git a/ivtest/regression_report-devel.txt b/ivtest/regression_report-devel.txt index 795b643ce..e369a9b40 100644 --- a/ivtest/regression_report-devel.txt +++ b/ivtest/regression_report-devel.txt @@ -2158,6 +2158,7 @@ test_mos_strength_reduction: Passed. struct_packed_sysfunct: Passed. struct_packed_write_read2: Passed. struct_invalid_member: Passed - CE. + struct_signed: Passed. sv-constants: Passed. sv_array_assign_pattern2: Passed. sv_cast_integer: Passed. @@ -2565,4 +2566,4 @@ test_mos_strength_reduction: Passed. ufuncsynth1: Passed. ============================================================================ Test results: - Total=2563, Passed=2557, Failed=3, Not Implemented=0, Expected Fail=3 + Total=2564, Passed=2558, Failed=3, Not Implemented=0, Expected Fail=3 diff --git a/ivtest/regression_report-fsv.txt b/ivtest/regression_report-fsv.txt index d9a06e151..96700e7e1 100644 --- a/ivtest/regression_report-fsv.txt +++ b/ivtest/regression_report-fsv.txt @@ -2165,6 +2165,7 @@ test_mos_strength_reduction: Passed. struct_packed_sysfunct: Passed. struct_packed_write_read2: Passed. struct_invalid_member: Passed - CE. + struct_signed: Passed. sv-constants: Passed. sv_array_assign_pattern2: Passed. sv_cast_integer: Passed. @@ -2565,4 +2566,4 @@ test_mos_strength_reduction: Passed. ufuncsynth1: Passed. ============================================================================ Test results: - Total=2563, Passed=2543, Failed=17, Not Implemented=3, Expected Fail=0 + Total=2564, Passed=2544, Failed=17, Not Implemented=3, Expected Fail=0 diff --git a/ivtest/regression_report-strict.txt b/ivtest/regression_report-strict.txt index 684e37358..58d070cb8 100644 --- a/ivtest/regression_report-strict.txt +++ b/ivtest/regression_report-strict.txt @@ -2154,6 +2154,7 @@ test_mos_strength_reduction: Passed. struct_packed_sysfunct: Passed. struct_packed_write_read2: Passed. struct_invalid_member: Passed - CE. + struct_signed: Passed. sv-constants: Passed. sv_array_assign_pattern2: Passed. sv_cast_integer: Passed. @@ -2562,4 +2563,4 @@ test_mos_strength_reduction: Passed. ufuncsynth1: Passed. ============================================================================ Test results: - Total=2560, Passed=2554, Failed=3, Not Implemented=0, Expected Fail=3 + Total=2561, Passed=2555, Failed=3, Not Implemented=0, Expected Fail=3 diff --git a/ivtest/regression_report-vlog95.txt b/ivtest/regression_report-vlog95.txt index f59f4c4de..1ec2a7cf8 100644 --- a/ivtest/regression_report-vlog95.txt +++ b/ivtest/regression_report-vlog95.txt @@ -664,6 +664,7 @@ Running vlog95 compiler/VVP tests for Icarus Verilog version: 12. size_cast5: Passed. struct_packed_array: Passed. struct_packed_array2: Passed. + struct_signed: Passed. sv_for_variable: Passed. sv_foreach1: Passed. sv_foreach5: Passed. @@ -2565,4 +2566,4 @@ test_mos_strength_reduction: Passed. synth_if_no_else: Passed. ============================================================================ Test results: - Total=2563, Passed=2524, Failed=2, Not Implemented=3, Expected Fail=34 + Total=2564, Passed=2525, Failed=2, Not Implemented=3, Expected Fail=34 diff --git a/netstruct.h b/netstruct.h index d5f9eb0a2..767819e4b 100644 --- a/netstruct.h +++ b/netstruct.h @@ -51,6 +51,10 @@ class netstruct_t : public LineInfo, public ivl_type_s { void packed(bool flag); bool packed(void) const; + // When the struct is accessed as a primary it can be signed or unsigned + void set_signed(bool flag) { signed_ = flag; } + bool get_signed(void) const { return signed_; } + // Append a new member to the struct/union. This must be done // after the union_flag and packed settings are set. This // function does error checking, and the "des" argument is @@ -74,6 +78,7 @@ class netstruct_t : public LineInfo, public ivl_type_s { private: bool union_; bool packed_; + bool signed_; std::vectormembers_; }; diff --git a/parse.y b/parse.y index 7491fcbeb..8680fe3e6 100644 --- a/parse.y +++ b/parse.y @@ -457,6 +457,11 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector number pos_neg_number %type signing unsigned_signed_opt signed_unsigned_opt %type import_export -%type K_genvar_opt K_packed_opt K_reg_opt K_static_opt K_virtual_opt +%type K_genvar_opt K_reg_opt K_static_opt K_virtual_opt %type udp_reg_opt edge_operator %type drive_strength drive_strength_opt dr_strength0 dr_strength1 %type udp_input_sym udp_output_sym @@ -642,6 +647,7 @@ static void current_function_set_statement(const YYLTYPE&loc, std::vector struct_union_member %type struct_union_member_list %type struct_data_type +%type packed_signing %type class_declaration_extends_opt @@ -2988,38 +2994,54 @@ enum_name } ; -struct_data_type - : K_struct K_packed_opt '{' struct_union_member_list '}' +/* `signed` and `unsigned` are only valid if preceded by `packed` */ +packed_signing /* IEEE 1800-2012 A.2.2.1 */ + : K_packed unsigned_signed_opt + { $$.packed_flag = true; + $$.signed_flag = $2; + } + | + { $$.packed_flag = false; + $$.signed_flag = false; + } + ; + +struct_data_type /* IEEE 1800-2012 A.2.2.1 */ + : K_struct packed_signing '{' struct_union_member_list '}' { struct_type_t*tmp = new struct_type_t; FILE_NAME(tmp, @1); - tmp->packed_flag = $2; + tmp->packed_flag = $2.packed_flag; + tmp->signed_flag = $2.signed_flag; tmp->union_flag = false; tmp->members .reset($4); $$ = tmp; } - | K_union K_packed_opt '{' struct_union_member_list '}' + | K_union packed_signing '{' struct_union_member_list '}' { struct_type_t*tmp = new struct_type_t; FILE_NAME(tmp, @1); - tmp->packed_flag = $2; + tmp->packed_flag = $2.packed_flag; + tmp->signed_flag = $2.signed_flag; tmp->union_flag = true; tmp->members .reset($4); $$ = tmp; } - | K_struct K_packed_opt '{' error '}' + | K_struct packed_signing '{' error '}' { yyerror(@3, "error: Errors in struct member list."); yyerrok; struct_type_t*tmp = new struct_type_t; FILE_NAME(tmp, @1); - tmp->packed_flag = $2; + tmp->packed_flag = $2.packed_flag; + tmp->signed_flag = $2.signed_flag; tmp->union_flag = false; $$ = tmp; } - | K_union K_packed_opt '{' error '}' + | K_union packed_signing '{' error '}' { yyerror(@3, "error: Errors in union member list."); yyerrok; struct_type_t*tmp = new struct_type_t; FILE_NAME(tmp, @1); - tmp->packed_flag = $2; + tmp->packed_flag = $2.packed_flag; + tmp->signed_flag = $2.signed_flag; tmp->union_flag = true; $$ = tmp; } @@ -7453,7 +7475,6 @@ unique_priority collect those rules here. */ K_genvar_opt : K_genvar { $$ = true; } | { $$ = false; } ; -K_packed_opt : K_packed { $$ = true; } | { $$ = false; } ; K_reg_opt : K_reg { $$ = true; } | { $$ = false; } ; K_static_opt : K_static { $$ = true; } | { $$ = false; } ; K_virtual_opt : K_virtual { $$ = true; } | { $$ = false; } ; diff --git a/pform_types.h b/pform_types.h index 4e67a72db..2b15810fb 100644 --- a/pform_types.h +++ b/pform_types.h @@ -207,6 +207,7 @@ struct struct_type_t : public data_type_t { bool packed_flag; bool union_flag; + bool signed_flag; std::unique_ptr< std::list > members; };