From 883ff01d214253270ebd76744aafe1189ce18b0e Mon Sep 17 00:00:00 2001 From: Jose Drowne <45007167+jdrowne@users.noreply.github.com> Date: Sun, 4 Jan 2026 10:22:52 -0500 Subject: [PATCH] Tests: Add self-checking tests for tagged union features (#6867 partial) (#6869) --- test_regress/driver.py | 3 + test_regress/t/t_tagged_case.out | 158 ++++++++++++ test_regress/t/t_tagged_case.py | 16 ++ test_regress/t/t_tagged_case.v | 306 ++++++++++++++++++++++ test_regress/t/t_tagged_if.out | 158 ++++++++++++ test_regress/t/t_tagged_if.py | 16 ++ test_regress/t/t_tagged_if.v | 412 ++++++++++++++++++++++++++++++ test_regress/t/t_tagged_union.out | 158 ++++++++++++ test_regress/t/t_tagged_union.py | 16 ++ test_regress/t/t_tagged_union.v | 276 ++++++++++++++++++++ 10 files changed, 1519 insertions(+) create mode 100644 test_regress/t/t_tagged_case.out create mode 100755 test_regress/t/t_tagged_case.py create mode 100644 test_regress/t/t_tagged_case.v create mode 100644 test_regress/t/t_tagged_if.out create mode 100755 test_regress/t/t_tagged_if.py create mode 100644 test_regress/t/t_tagged_if.v create mode 100644 test_regress/t/t_tagged_union.out create mode 100755 test_regress/t/t_tagged_union.py create mode 100644 test_regress/t/t_tagged_union.v diff --git a/test_regress/driver.py b/test_regress/driver.py index 025e3d263..2629e7480 100755 --- a/test_regress/driver.py +++ b/test_regress/driver.py @@ -2435,6 +2435,9 @@ class VlTest: if n: l1o.append(line) break # Trunc rest + if re.search(r'This fatal error may be caused', line): + l1o.append(line) + break # Trunc after "This fatal error" line l1o.append(line) # l1s = l1o diff --git a/test_regress/t/t_tagged_case.out b/test_regress/t/t_tagged_case.out new file mode 100644 index 000000000..83af24ffe --- /dev/null +++ b/test_regress/t/t_tagged_case.out @@ -0,0 +1,158 @@ +%Error-UNSUPPORTED: t/t_tagged_case.v:24:17: Unsupported: tagged union + 24 | typedef union tagged { + | ^~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_tagged_case.v:25:5: Unsupported: void (for tagged unions) + 25 | void Invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged_case.v:30:17: Unsupported: tagged union + 30 | typedef union tagged packed { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_case.v:31:5: Unsupported: void (for tagged unions) + 31 | void Invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged_case.v:39:17: Unsupported: tagged union + 39 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_case.v:40:5: Unsupported: void (for tagged unions) + 40 | void Invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged_case.v:46:17: Unsupported: tagged union + 46 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_case.v:50:11: Unsupported: tagged union + 50 | union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_case.v:60:17: Unsupported: tagged union + 60 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_case.v:61:5: Unsupported: void (for tagged unions) + 61 | void Invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged_case.v:66:17: Unsupported: tagged union + 66 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_case.v:67:5: Unsupported: void (for tagged unions) + 67 | void Invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged_case.v:75:17: Unsupported: tagged union + 75 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_case.v:76:5: Unsupported: void (for tagged unions) + 76 | void Invalid; + | ^~~~ +%Warning-SHORTREAL: t/t_tagged_case.v:78:5: Unsupported: shortreal being promoted to real (suggest use real instead) + 78 | shortreal ShortRealVal; + | ^~~~~~~~~ + ... For warning description see https://verilator.org/warn/SHORTREAL?v=latest + ... Use "/* verilator lint_off SHORTREAL */" and lint_on around source to disable this message. +%Error-UNSUPPORTED: t/t_tagged_case.v:82:17: Unsupported: tagged union + 82 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_case.v:83:5: Unsupported: void (for tagged unions) + 83 | void Invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged_case.v:88:17: Unsupported: tagged union + 88 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_case.v:89:5: Unsupported: void (for tagged unions) + 89 | void Invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged_case.v:97:17: Unsupported: tagged union + 97 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_case.v:98:5: Unsupported: void (for tagged unions) + 98 | void Invalid; + | ^~~~ +%Error: t/t_tagged_case.v:122:9: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 122 | v = tagged Invalid; + | ^~~~~~ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: t/t_tagged_case.v:125:7: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 125 | tagged Invalid : result = 1; + | ^~~~~~ +%Error: t/t_tagged_case.v:128:161: syntax error, unexpected while + 128 | do if ((result) !== (1)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", "t/t_tagged_case.v",128, (result), (1), "result", "1"); $stop; end while(0);; + | ^~~~~ +%Error: t/t_tagged_case.v:131:7: syntax error, unexpected '=', expecting '(' + 131 | v = tagged Valid (123); + | ^ +%Error: t/t_tagged_case.v:133:14: syntax error, unexpected matches, expecting IDENTIFIER-for-type + 133 | case (v) matches + | ^~~~~~~ +%Error: t/t_tagged_case.v:140:8: syntax error, unexpected '=', expecting '(' + 140 | wt = tagged Wide60 (60'hFEDCBA987654321); + | ^ +%Error: t/t_tagged_case.v:142:15: syntax error, unexpected matches, expecting IDENTIFIER-for-type + 142 | case (wt) matches + | ^~~~~~~ +%Error: t/t_tagged_case.v:150:8: syntax error, unexpected '=', expecting '(' + 150 | wt = tagged Wide90 (90'hDE_ADBEEFCA_FEBABE12_3456); + | ^ +%Error: t/t_tagged_case.v:152:15: syntax error, unexpected matches, expecting IDENTIFIER-for-type + 152 | case (wt) matches + | ^~~~~~~ +%Error: t/t_tagged_case.v:160:8: syntax error, unexpected '=', expecting '(' + 160 | wt = tagged Byte8NonZeroLSB (8'hA5); + | ^ +%Error: t/t_tagged_case.v:162:15: syntax error, unexpected matches, expecting IDENTIFIER-for-type + 162 | case (wt) matches + | ^~~~~~~ +%Error: t/t_tagged_case.v:169:8: syntax error, unexpected '=', expecting '(' + 169 | wt = tagged Word32LittleEndian (32'hDEADBEEF); + | ^ +%Error: t/t_tagged_case.v:171:15: syntax error, unexpected matches, expecting IDENTIFIER-for-type + 171 | case (wt) matches + | ^~~~~~~ +%Error: t/t_tagged_case.v:178:8: syntax error, unexpected '=', expecting '(' + 178 | at = tagged Arr '{10, 20, 30, 40}; + | ^ +%Error: t/t_tagged_case.v:180:15: syntax error, unexpected matches, expecting IDENTIFIER-for-type + 180 | case (at) matches + | ^~~~~~~ +%Error: t/t_tagged_case.v:188:11: syntax error, unexpected '=', expecting '(' + 188 | instr = tagged Jmp (tagged JmpC '{2'd1, 10'd256}); + | ^ +%Error: t/t_tagged_case.v:190:18: syntax error, unexpected matches, expecting IDENTIFIER-for-type + 190 | case (instr) matches + | ^~~~~~~ +%Error: t/t_tagged_case.v:198:9: syntax error, unexpected '=', expecting '(' + 198 | cht = tagged Invalid; + | ^ +%Error: t/t_tagged_case.v:200:16: syntax error, unexpected matches, expecting IDENTIFIER-for-type + 200 | case (cht) matches + | ^~~~~~~ +%Error: t/t_tagged_case.v:207:9: syntax error, unexpected =-then-new, expecting '(' + 207 | obj = new(42); + | ^ +%Error: t/t_tagged_case.v:210:16: syntax error, unexpected matches, expecting IDENTIFIER-for-type + 210 | case (clt) matches + | ^~~~~~~ +%Error: t/t_tagged_case.v:217:8: syntax error, unexpected '=', expecting '(' + 217 | rt = tagged Invalid; + | ^ +%Error: t/t_tagged_case.v:219:15: syntax error, unexpected matches, expecting IDENTIFIER-for-type + 219 | case (rt) matches + | ^~~~~~~ +%Error: t/t_tagged_case.v:226:8: syntax error, unexpected '=', expecting '(' + 226 | rt = tagged RealVal (3.14159); + | ^ +%Error: t/t_tagged_case.v:228:15: syntax error, unexpected matches, expecting IDENTIFIER-for-type + 228 | case (rt) matches + | ^~~~~~~ +%Error: t/t_tagged_case.v:239:8: syntax error, unexpected '=', expecting '(' + 239 | rt = tagged ShortRealVal (2.5); + | ^ +%Error: t/t_tagged_case.v:241:15: syntax error, unexpected matches, expecting IDENTIFIER-for-type + 241 | case (rt) matches + | ^~~~~~~ +%Error: t/t_tagged_case.v:252:8: syntax error, unexpected '=', expecting '(' + 252 | st = tagged Invalid; + | ^ +%Error: t/t_tagged_case.v:254:15: syntax error, unexpected matches, expecting IDENTIFIER-for-type + 254 | case (st) matches + | ^~~~~~~ +%Error: t/t_tagged_case.v:260:8: syntax error, unexpected '=', expecting '(' + 260 | st = tagged StrVal ("hello"); + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_tagged_case.py b/test_regress/t/t_tagged_case.py new file mode 100755 index 000000000..710a094ab --- /dev/null +++ b/test_regress/t/t_tagged_case.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile(fails=test.vlt_all, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_tagged_case.v b/test_regress/t/t_tagged_case.v new file mode 100644 index 000000000..dca8eaab3 --- /dev/null +++ b/test_regress/t/t_tagged_case.v @@ -0,0 +1,306 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// Test case pattern matching with tagged unions +// IEEE 1800-2023 Section 12.6.1 + +// Class for testing class references in tagged unions +class TestClass; + int value; + function new(int v); + value = v; + endfunction +endclass + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); + +module t; + + // Basic tagged union (IEEE example) + typedef union tagged { + void Invalid; + int Valid; + } VInt; + + // Tagged union with wide types + typedef union tagged packed { + void Invalid; + bit [8:1] Byte8NonZeroLSB; // Non-zero LSB + bit [0:31] Word32LittleEndian; // Opposite endianness + bit [59:0] Wide60; // 60-bit (33-64 special handling) + bit [89:0] Wide90; // 90-bit (64+ special handling) + } WideType; + + // Tagged union with unpacked array + typedef union tagged { + void Invalid; + int Scalar; + int Arr[4]; // Unpacked array + } ArrayType; + + // Tagged union with nested structure (IEEE example) + typedef union tagged { + struct { + bit [4:0] reg1, reg2, regd; + } Add; + union tagged { + bit [9:0] JmpU; + struct { + bit [1:0] cc; + bit [9:0] addr; + } JmpC; + } Jmp; + } Instr; + + // Tagged union with chandle member + typedef union tagged { + void Invalid; + chandle Handle; + } ChandleType; + + // Tagged union with class reference member + typedef union tagged { + void Invalid; + TestClass Obj; + } ClassType; + + // Enum for testing enum members + typedef enum {RED, GREEN, BLUE} Color; + + // Tagged union with real/shortreal members + typedef union tagged { + void Invalid; + real RealVal; + shortreal ShortRealVal; + } RealType; + + // Tagged union with string member + typedef union tagged { + void Invalid; + string StrVal; + } StringType; + + // Tagged union with enum member + typedef union tagged { + void Invalid; + Color ColorVal; + } EnumType; + +`ifndef VCS + // Tagged union with event member + // Note: VCS incorrectly reports "the event data type is not allowed in structures and unions" + // but IEEE 1800-2023 does not prohibit this + typedef union tagged { + void Invalid; + event EvtVal; + } EventType; +`endif + + VInt v; + WideType wt; + ArrayType at; + Instr instr; + ChandleType cht; + ClassType clt; + TestClass obj; + RealType rt; + StringType st; + EnumType et; +`ifndef VCS + EventType evt; +`endif + int result; + bit [59:0] wide60_result; + bit [89:0] wide90_result; + + initial begin + // Test 1: Basic case matches with void tag + v = tagged Invalid; + result = 0; + case (v) matches + tagged Invalid : result = 1; + tagged Valid .n : result = n; + endcase + `checkh(result, 1); + + // Test 2: Case matches with value binding + v = tagged Valid (123); + result = 0; + case (v) matches + tagged Invalid : result = -1; + tagged Valid .n : result = n; + endcase + `checkh(result, 123); + + // Test 3: Wide type case matching - 60-bit + wt = tagged Wide60 (60'hFEDCBA987654321); + wide60_result = 0; + case (wt) matches + tagged Invalid : wide60_result = 0; + tagged Wide60 .w : wide60_result = w; + default : wide60_result = 0; + endcase + `checkh(wide60_result, 60'hFEDCBA987654321); + + // Test 4: Wide type case matching - 90-bit + wt = tagged Wide90 (90'hDE_ADBEEFCA_FEBABE12_3456); + wide90_result = 0; + case (wt) matches + tagged Invalid : wide90_result = 0; + tagged Wide90 .w : wide90_result = w; + default : wide90_result = 0; + endcase + `checkh(wide90_result, 90'hDE_ADBEEFCA_FEBABE12_3456); + + // Test 5: Non-zero LSB case match + wt = tagged Byte8NonZeroLSB (8'hA5); + result = 0; + case (wt) matches + tagged Byte8NonZeroLSB .b : result = b; + default : result = -1; + endcase + `checkh(result, 8'hA5); + + // Test 6: Opposite endianness case match + wt = tagged Word32LittleEndian (32'hDEADBEEF); + result = 0; + case (wt) matches + tagged Word32LittleEndian .w : result = w; + default : result = -1; + endcase + `checkh(result, 32'hDEADBEEF); + + // Test 7: Array type case matching + at = tagged Arr '{10, 20, 30, 40}; + result = 0; + case (at) matches + tagged Invalid : result = -1; + tagged Scalar .s : result = s; + tagged Arr .a : result = a[0] + a[1] + a[2] + a[3]; + endcase + `checkh(result, 100); + + // Test 8: Nested tagged union case matching + instr = tagged Jmp (tagged JmpC '{2'd1, 10'd256}); + result = 0; + case (instr) matches + tagged Add .* : result = -1; + tagged Jmp (tagged JmpU .a) : result = a; + tagged Jmp (tagged JmpC '{cc:.c, addr:.a}) : result = a; + endcase + `checkh(result, 256); + + // Test 9: Chandle case matching (no binding - VCS limitation) + cht = tagged Invalid; + result = 0; + case (cht) matches + tagged Invalid : result = 1; + tagged Handle .* : result = 2; // Wildcard - can't bind chandle + endcase + `checkh(result, 1); + + // Test 10: Class reference case matching + obj = new(42); + clt = tagged Obj (obj); + result = 0; + case (clt) matches + tagged Invalid : result = -1; + tagged Obj .o : result = o.value; + endcase + `checkh(result, 42); + + // Test 11: Real member case matching + rt = tagged Invalid; + result = 0; + case (rt) matches + tagged Invalid : result = 1; + tagged RealVal .r : result = 2; + tagged ShortRealVal .r : result = 3; + endcase + `checkh(result, 1); + + rt = tagged RealVal (3.14159); + result = 0; + case (rt) matches + tagged Invalid : result = -1; + tagged RealVal .r : begin + if (r == 3.14159) result = 1; + else result = 2; + end + tagged ShortRealVal .r : result = 3; + endcase + `checkh(result, 1); + + // Test 12: Shortreal member case matching + rt = tagged ShortRealVal (2.5); + result = 0; + case (rt) matches + tagged Invalid : result = -1; + tagged RealVal .r : result = 2; + tagged ShortRealVal .r : begin + if (r == 2.5) result = 1; + else result = 3; + end + endcase + `checkh(result, 1); + + // Test 13: String member case matching + st = tagged Invalid; + result = 0; + case (st) matches + tagged Invalid : result = 1; + tagged StrVal .s : result = 2; + endcase + `checkh(result, 1); + + st = tagged StrVal ("hello"); + result = 0; + case (st) matches + tagged Invalid : result = -1; + tagged StrVal .s : begin + if (s == "hello") result = 1; + else result = 2; + end + endcase + `checkh(result, 1); + + // Test 14: Enum member case matching + et = tagged Invalid; + result = 0; + case (et) matches + tagged Invalid : result = 1; + tagged ColorVal .c : result = 2; + endcase + `checkh(result, 1); + + et = tagged ColorVal (GREEN); + result = 0; + case (et) matches + tagged Invalid : result = -1; + tagged ColorVal .c : begin + if (c == GREEN) result = 1; + else result = 2; + end + endcase + `checkh(result, 1); + +`ifndef VCS + // Test 15: Event member case matching + evt = tagged Invalid; + result = 0; + case (evt) matches + tagged Invalid : result = 1; + tagged EvtVal .* : result = 2; + endcase + `checkh(result, 1); +`endif + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_tagged_if.out b/test_regress/t/t_tagged_if.out new file mode 100644 index 000000000..35e3a1e57 --- /dev/null +++ b/test_regress/t/t_tagged_if.out @@ -0,0 +1,158 @@ +%Error-UNSUPPORTED: t/t_tagged_if.v:24:17: Unsupported: tagged union + 24 | typedef union tagged { + | ^~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_tagged_if.v:25:5: Unsupported: void (for tagged unions) + 25 | void Invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:30:17: Unsupported: tagged union + 30 | typedef union tagged packed { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:31:5: Unsupported: void (for tagged unions) + 31 | void Invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:39:17: Unsupported: tagged union + 39 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:40:5: Unsupported: void (for tagged unions) + 40 | void Invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:46:17: Unsupported: tagged union + 46 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:50:11: Unsupported: tagged union + 50 | union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:60:17: Unsupported: tagged union + 60 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:61:5: Unsupported: void (for tagged unions) + 61 | void Invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:66:17: Unsupported: tagged union + 66 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:67:5: Unsupported: void (for tagged unions) + 67 | void Invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:75:17: Unsupported: tagged union + 75 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:76:5: Unsupported: void (for tagged unions) + 76 | void Invalid; + | ^~~~ +%Warning-SHORTREAL: t/t_tagged_if.v:78:5: Unsupported: shortreal being promoted to real (suggest use real instead) + 78 | shortreal ShortRealVal; + | ^~~~~~~~~ + ... For warning description see https://verilator.org/warn/SHORTREAL?v=latest + ... Use "/* verilator lint_off SHORTREAL */" and lint_on around source to disable this message. +%Error-UNSUPPORTED: t/t_tagged_if.v:82:17: Unsupported: tagged union + 82 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:83:5: Unsupported: void (for tagged unions) + 83 | void Invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:88:17: Unsupported: tagged union + 88 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:89:5: Unsupported: void (for tagged unions) + 89 | void Invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:97:17: Unsupported: tagged union + 97 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:98:5: Unsupported: void (for tagged unions) + 98 | void Invalid; + | ^~~~ +%Error: t/t_tagged_if.v:122:9: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 122 | v = tagged Invalid; + | ^~~~~~ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: t/t_tagged_if.v:124:33: syntax error, unexpected ')', expecting '.' or tagged or .* + 124 | if (v matches tagged Invalid) + | ^ +%Error: t/t_tagged_if.v:131:9: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 131 | v = tagged Valid (42); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:133:32: Unsupported: '{} tagged patterns + 133 | if (v matches tagged Valid .n) + | ^ +%Error-UNSUPPORTED: t/t_tagged_if.v:133:19: Unsupported: '{} tagged patterns + 133 | if (v matches tagged Valid .n) + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:133:11: Unsupported: matches operator + 133 | if (v matches tagged Valid .n) + | ^~~~~~~ +%Error: t/t_tagged_if.v:140:9: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 140 | v = tagged Valid (100); + | ^~~~~~ +%Error: t/t_tagged_if.v:142:33: syntax error, unexpected ')', expecting '.' or tagged or .* + 142 | if (v matches tagged Invalid) + | ^ +%Error: t/t_tagged_if.v:149:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 149 | wt = tagged Wide60 (60'hFEDCBA987654321); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:151:34: Unsupported: '{} tagged patterns + 151 | if (wt matches tagged Wide60 .w) + | ^ +%Error-UNSUPPORTED: t/t_tagged_if.v:151:20: Unsupported: '{} tagged patterns + 151 | if (wt matches tagged Wide60 .w) + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:151:12: Unsupported: matches operator + 151 | if (wt matches tagged Wide60 .w) + | ^~~~~~~ +%Error: t/t_tagged_if.v:158:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 158 | wt = tagged Wide90 (90'hDE_ADBEEFCA_FEBABE12_3456); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:160:34: Unsupported: '{} tagged patterns + 160 | if (wt matches tagged Wide90 .w) + | ^ +%Error-UNSUPPORTED: t/t_tagged_if.v:160:20: Unsupported: '{} tagged patterns + 160 | if (wt matches tagged Wide90 .w) + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:160:12: Unsupported: matches operator + 160 | if (wt matches tagged Wide90 .w) + | ^~~~~~~ +%Error: t/t_tagged_if.v:167:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 167 | wt = tagged Byte8NonZeroLSB (8'hA5); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:169:43: Unsupported: '{} tagged patterns + 169 | if (wt matches tagged Byte8NonZeroLSB .b) + | ^ +%Error-UNSUPPORTED: t/t_tagged_if.v:169:20: Unsupported: '{} tagged patterns + 169 | if (wt matches tagged Byte8NonZeroLSB .b) + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:169:12: Unsupported: matches operator + 169 | if (wt matches tagged Byte8NonZeroLSB .b) + | ^~~~~~~ +%Error: t/t_tagged_if.v:176:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 176 | wt = tagged Word32LittleEndian (32'hDEADBEEF); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:178:46: Unsupported: '{} tagged patterns + 178 | if (wt matches tagged Word32LittleEndian .w) + | ^ +%Error-UNSUPPORTED: t/t_tagged_if.v:178:20: Unsupported: '{} tagged patterns + 178 | if (wt matches tagged Word32LittleEndian .w) + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:178:12: Unsupported: matches operator + 178 | if (wt matches tagged Word32LittleEndian .w) + | ^~~~~~~ +%Error: t/t_tagged_if.v:185:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 185 | at = tagged Arr '{10, 20, 30, 40}; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:187:31: Unsupported: '{} tagged patterns + 187 | if (at matches tagged Arr .a) + | ^ +%Error-UNSUPPORTED: t/t_tagged_if.v:187:20: Unsupported: '{} tagged patterns + 187 | if (at matches tagged Arr .a) + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:187:12: Unsupported: matches operator + 187 | if (at matches tagged Arr .a) + | ^~~~~~~ +%Error: t/t_tagged_if.v:194:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 194 | at = tagged Scalar (999); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_if.v:196:34: Unsupported: '{} tagged patterns + 196 | if (at matches tagged Scalar .s) + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_tagged_if.py b/test_regress/t/t_tagged_if.py new file mode 100755 index 000000000..710a094ab --- /dev/null +++ b/test_regress/t/t_tagged_if.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile(fails=test.vlt_all, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_tagged_if.v b/test_regress/t/t_tagged_if.v new file mode 100644 index 000000000..7a0c79c37 --- /dev/null +++ b/test_regress/t/t_tagged_if.v @@ -0,0 +1,412 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// Test if pattern matching with tagged unions +// IEEE 1800-2023 Section 12.6.2 + +// Class for testing class references in tagged unions +class TestClass; + int value; + function new(int v); + value = v; + endfunction +endclass + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); + +module t; + + // Basic tagged union (IEEE example) + typedef union tagged { + void Invalid; + int Valid; + } VInt; + + // Tagged union with wide types + typedef union tagged packed { + void Invalid; + bit [8:1] Byte8NonZeroLSB; // Non-zero LSB + bit [0:31] Word32LittleEndian; // Opposite endianness + bit [59:0] Wide60; // 60-bit (33-64 special handling) + bit [89:0] Wide90; // 90-bit (64+ special handling) + } WideType; + + // Tagged union with unpacked array + typedef union tagged { + void Invalid; + int Scalar; + int Arr[4]; // Unpacked array + } ArrayType; + + // Tagged union with nested structure + typedef union tagged { + struct { + bit [4:0] reg1, reg2, regd; + } Add; + union tagged { + bit [9:0] JmpU; + struct { + bit [1:0] cc; + bit [9:0] addr; + } JmpC; + } Jmp; + } Instr; + + // Tagged union with chandle member + typedef union tagged { + void Invalid; + chandle Handle; + } ChandleType; + + // Tagged union with class reference member + typedef union tagged { + void Invalid; + TestClass Obj; + } ClassType; + + // Enum for testing enum members + typedef enum {RED, GREEN, BLUE} Color; + + // Tagged union with real/shortreal members + typedef union tagged { + void Invalid; + real RealVal; + shortreal ShortRealVal; + } RealType; + + // Tagged union with string member + typedef union tagged { + void Invalid; + string StrVal; + } StringType; + + // Tagged union with enum member + typedef union tagged { + void Invalid; + Color ColorVal; + } EnumType; + +`ifndef VCS + // Tagged union with event member + // Note: VCS incorrectly reports "the event data type is not allowed in structures and unions" + // but IEEE 1800-2023 does not prohibit this + typedef union tagged { + void Invalid; + event EvtVal; + } EventType; +`endif + + VInt v; + WideType wt; + ArrayType at; + Instr instr; + ChandleType cht; + ClassType clt; + TestClass obj; + RealType rt; + StringType st; + EnumType et; +`ifndef VCS + EventType evt; +`endif + int result; + bit [59:0] wide60_result; + bit [89:0] wide90_result; + + initial begin + // Test 1: Basic if matches - void tag + v = tagged Invalid; + result = 0; + if (v matches tagged Invalid) + result = 1; + else + result = 2; + `checkh(result, 1); + + // Test 2: Basic if matches - value with binding + v = tagged Valid (42); + result = 0; + if (v matches tagged Valid .n) + result = n; + else + result = -1; + `checkh(result, 42); + + // Test 3: if-else chain + v = tagged Valid (100); + result = 0; + if (v matches tagged Invalid) + result = 1; + else if (v matches tagged Valid .n) + result = n; + `checkh(result, 100); + + // Test 4: Wide type if matching - 60-bit + wt = tagged Wide60 (60'hFEDCBA987654321); + wide60_result = 0; + if (wt matches tagged Wide60 .w) + wide60_result = w; + else + wide60_result = 0; + `checkh(wide60_result, 60'hFEDCBA987654321); + + // Test 5: Wide type if matching - 90-bit + wt = tagged Wide90 (90'hDE_ADBEEFCA_FEBABE12_3456); + wide90_result = 0; + if (wt matches tagged Wide90 .w) + wide90_result = w; + else + wide90_result = 0; + `checkh(wide90_result, 90'hDE_ADBEEFCA_FEBABE12_3456); + + // Test 6: Non-zero LSB if match + wt = tagged Byte8NonZeroLSB (8'hA5); + result = 0; + if (wt matches tagged Byte8NonZeroLSB .b) + result = b; + else + result = -1; + `checkh(result, 8'hA5); + + // Test 7: Opposite endianness if match + wt = tagged Word32LittleEndian (32'hDEADBEEF); + result = 0; + if (wt matches tagged Word32LittleEndian .w) + result = w; + else + result = -1; + `checkh(result, 32'hDEADBEEF); + + // Test 8: Array type if matching + at = tagged Arr '{10, 20, 30, 40}; + result = 0; + if (at matches tagged Arr .a) + result = a[0] + a[1] + a[2] + a[3]; + else + result = -1; + `checkh(result, 100); + + // Test 9: Array type scalar if match + at = tagged Scalar (999); + result = 0; + if (at matches tagged Scalar .s) + result = s; + else + result = -1; + `checkh(result, 999); + + // Test 10: Nested pattern matching (IEEE example) + instr = tagged Jmp (tagged JmpC '{2'd1, 10'd256}); + result = 0; + if (instr matches tagged Jmp (tagged JmpC '{cc:.c, addr:.a})) + result = a; // 'a' is bound in pattern + else + result = -1; + `checkh(result, 256); + + // Test 11: Chained matches with &&& (IEEE example) + instr = tagged Jmp (tagged JmpC '{2'd2, 10'd128}); + result = 0; + if (instr matches tagged Jmp .j &&& + j matches tagged JmpC '{cc:.c, addr:.a}) + result = a; // 'a' bound from second pattern + else + result = -1; + `checkh(result, 128); + + // Test 12: Pattern with boolean filter expression + v = tagged Valid (75); + result = 0; + if (v matches tagged Valid .n &&& (n > 50)) + result = 1; + else + result = 2; + `checkh(result, 1); + + // Test 13: Pattern with boolean filter - no match + v = tagged Valid (25); + result = 0; + if (v matches tagged Valid .n &&& (n > 50)) + result = 1; + else + result = 2; + `checkh(result, 2); + + // Test 14: Scope test - bound variable only in true branch + v = tagged Valid (99); + result = 0; + if (v matches tagged Valid .x) begin + result = x; // x is in scope here + end + // x is NOT in scope here (else branch / after) + `checkh(result, 99); + + // Test 15: Add instruction matching + instr = tagged Add '{5'd10, 5'd20, 5'd30}; + result = 0; + if (instr matches tagged Add '{.r1, .r2, .rd}) + result = r1 + r2 + rd; + else + result = -1; + `checkh(result, 60); + + // Test 16: Complex filter with register file simulation + instr = tagged Jmp (tagged JmpC '{2'd3, 10'd100}); + result = 0; + // If conditional jump and condition register is non-zero + // Use nested if for boolean filter (VCS limitation with &&& after chained matches) + if (instr matches tagged Jmp .j &&& + j matches tagged JmpC '{cc:.c, addr:.a}) begin + if (c != 0) + result = a; + else + result = -1; + end else + result = -1; + `checkh(result, 100); + + // Test 17: Unconditional jump matching + instr = tagged Jmp (tagged JmpU 10'd512); + result = 0; + if (instr matches tagged Jmp (tagged JmpU .a)) + result = a; + else + result = -1; + `checkh(result, 512); + + // Test 18: Wildcard pattern in if + instr = tagged Add '{5'd1, 5'd2, 5'd3}; + result = 0; + if (instr matches tagged Add .*) + result = 1; + else if (instr matches tagged Jmp .*) + result = 2; + `checkh(result, 1); + + // Test 19: Chandle member if matching + cht = tagged Invalid; + result = 0; + if (cht matches tagged Invalid) + result = 1; + else + result = 2; + `checkh(result, 1); + + cht = tagged Handle (null); + result = 0; + if (cht matches tagged Handle .*) // Wildcard - VCS can't bind chandle + result = 1; + else + result = 2; + `checkh(result, 1); + + // Test 20: Class reference member if matching + obj = new(42); + clt = tagged Invalid; + result = 0; + if (clt matches tagged Invalid) + result = 1; + else + result = 2; + `checkh(result, 1); + + clt = tagged Obj (obj); + result = 0; + if (clt matches tagged Obj .o) + result = o.value; + else + result = -1; + `checkh(result, 42); + + // Test 21: Real member if matching + rt = tagged Invalid; + result = 0; + if (rt matches tagged Invalid) + result = 1; + else + result = 2; + `checkh(result, 1); + + rt = tagged RealVal (3.14159); + result = 0; + if (rt matches tagged RealVal .r) begin + if (r == 3.14159) + result = 1; + else + result = 2; + end else + result = -1; + `checkh(result, 1); + + // Test 22: Shortreal member if matching + rt = tagged ShortRealVal (2.5); + result = 0; + if (rt matches tagged ShortRealVal .r) begin + if (r == 2.5) + result = 1; + else + result = 2; + end else + result = -1; + `checkh(result, 1); + + // Test 23: String member if matching + st = tagged Invalid; + result = 0; + if (st matches tagged Invalid) + result = 1; + else + result = 2; + `checkh(result, 1); + + st = tagged StrVal ("hello"); + result = 0; + if (st matches tagged StrVal .s) begin + if (s == "hello") + result = 1; + else + result = 2; + end else + result = -1; + `checkh(result, 1); + + // Test 24: Enum member if matching + et = tagged Invalid; + result = 0; + if (et matches tagged Invalid) + result = 1; + else + result = 2; + `checkh(result, 1); + + et = tagged ColorVal (GREEN); + result = 0; + if (et matches tagged ColorVal .c) begin + if (c == GREEN) + result = 1; + else + result = 2; + end else + result = -1; + `checkh(result, 1); + +`ifndef VCS + // Test 25: Event member if matching + evt = tagged Invalid; + result = 0; + if (evt matches tagged Invalid) + result = 1; + else + result = 2; + `checkh(result, 1); +`endif + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_tagged_union.out b/test_regress/t/t_tagged_union.out new file mode 100644 index 000000000..40622e7b8 --- /dev/null +++ b/test_regress/t/t_tagged_union.out @@ -0,0 +1,158 @@ +%Error-UNSUPPORTED: t/t_tagged_union.v:24:17: Unsupported: tagged union + 24 | typedef union tagged { + | ^~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_tagged_union.v:25:5: Unsupported: void (for tagged unions) + 25 | void Invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:31:17: Unsupported: tagged union + 31 | typedef union tagged packed { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:32:5: Unsupported: void (for tagged unions) + 32 | void Invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:52:17: Unsupported: tagged union + 52 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:53:5: Unsupported: void (for tagged unions) + 53 | void Invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:60:17: Unsupported: tagged union + 60 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:64:11: Unsupported: tagged union + 64 | union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:74:17: Unsupported: tagged union + 74 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:75:5: Unsupported: void (for tagged unions) + 75 | void Invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:80:17: Unsupported: tagged union + 80 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:81:5: Unsupported: void (for tagged unions) + 81 | void Invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:89:17: Unsupported: tagged union + 89 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:90:5: Unsupported: void (for tagged unions) + 90 | void Invalid; + | ^~~~ +%Warning-SHORTREAL: t/t_tagged_union.v:92:5: Unsupported: shortreal being promoted to real (suggest use real instead) + 92 | shortreal ShortRealVal; + | ^~~~~~~~~ + ... For warning description see https://verilator.org/warn/SHORTREAL?v=latest + ... Use "/* verilator lint_off SHORTREAL */" and lint_on around source to disable this message. +%Error-UNSUPPORTED: t/t_tagged_union.v:96:17: Unsupported: tagged union + 96 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:97:5: Unsupported: void (for tagged unions) + 97 | void Invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:102:17: Unsupported: tagged union + 102 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:103:5: Unsupported: void (for tagged unions) + 103 | void Invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:111:17: Unsupported: tagged union + 111 | typedef union tagged { + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:112:5: Unsupported: void (for tagged unions) + 112 | void Invalid; + | ^~~~ +%Error: t/t_tagged_union.v:133:11: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 133 | vi1 = tagged Invalid; + | ^~~~~~ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: t/t_tagged_union.v:134:11: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 134 | vi2 = tagged Invalid; + | ^~~~~~ +%Error: t/t_tagged_union.v:137:11: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 137 | vi1 = tagged Valid (42); + | ^~~~~~ +%Error: t/t_tagged_union.v:140:11: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 140 | vi2 = tagged Valid (23 + 34); + | ^~~~~~ +%Error: t/t_tagged_union.v:144:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 144 | mt = tagged Invalid; + | ^~~~~~ +%Error: t/t_tagged_union.v:146:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 146 | mt = tagged IntVal (32'h12345678); + | ^~~~~~ +%Error: t/t_tagged_union.v:149:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 149 | mt = tagged ShortVal (16'hABCD); + | ^~~~~~ +%Error: t/t_tagged_union.v:152:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 152 | mt = tagged ByteVal (8'h5A); + | ^~~~~~ +%Error: t/t_tagged_union.v:155:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 155 | mt = tagged BitVal (1'b1); + | ^~~~~~ +%Error: t/t_tagged_union.v:159:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 159 | mt = tagged Byte8NonZeroLSB (8'hA5); + | ^~~~~~ +%Error: t/t_tagged_union.v:162:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 162 | mt = tagged Word16NonZeroLSB (16'h1234); + | ^~~~~~ +%Error: t/t_tagged_union.v:166:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 166 | mt = tagged Word32LittleEndian (32'hDEADBEEF); + | ^~~~~~ +%Error: t/t_tagged_union.v:169:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 169 | mt = tagged Word16LittleEndian (16'hCAFE); + | ^~~~~~ +%Error: t/t_tagged_union.v:173:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 173 | mt = tagged Wide60 (60'hFEDCBA987654321); + | ^~~~~~ +%Error: t/t_tagged_union.v:176:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 176 | mt = tagged Wide60NonZeroLSB (60'h123456789ABCDEF); + | ^~~~~~ +%Error: t/t_tagged_union.v:179:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 179 | mt = tagged Wide60LittleEndian (60'hABCDEF012345678); + | ^~~~~~ +%Error: t/t_tagged_union.v:183:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 183 | mt = tagged Wide90 (90'hFF_FFFFFFFF_FFFFFFFF_FFFF); + | ^~~~~~ +%Error: t/t_tagged_union.v:186:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 186 | mt = tagged Wide90NonZeroLSB (90'hDE_ADBEEFCA_FEBABE12_3456); + | ^~~~~~ +%Error: t/t_tagged_union.v:189:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 189 | mt = tagged Wide90LittleEndian (90'h11_11111122_22222233_3333); + | ^~~~~~ +%Error: t/t_tagged_union.v:193:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 193 | at = tagged Invalid; + | ^~~~~~ +%Error: t/t_tagged_union.v:195:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 195 | at = tagged Scalar (999); + | ^~~~~~ +%Error: t/t_tagged_union.v:198:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 198 | at = tagged UnpackedArr '{100, 200, 300, 400}; + | ^~~~~~ +%Error: t/t_tagged_union.v:204:10: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 204 | at = tagged UnpackedArr2D '{'{32'hA, 32'hB, 32'hC}, '{32'hD, 32'hE, 32'hF}}; + | ^~~~~~ +%Error: t/t_tagged_union.v:213:13: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 213 | instr = tagged Add '{5'd1, 5'd2, 5'd3}; + | ^~~~~~ +%Error: t/t_tagged_union.v:219:13: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 219 | instr = tagged Add '{reg2:5'd10, regd:5'd20, reg1:5'd5}; + | ^~~~~~ +%Error: t/t_tagged_union.v:225:13: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 225 | instr = tagged Jmp (tagged JmpU 10'd512); + | ^~~~~~ +%Error: t/t_tagged_union.v:229:13: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 229 | instr = tagged Jmp (tagged JmpC '{2'd1, 10'd256}); + | ^~~~~~ +%Error: t/t_tagged_union.v:234:13: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 234 | instr = tagged Jmp (tagged JmpC '{cc:2'd3, addr:10'd100}); + | ^~~~~~ +%Error: t/t_tagged_union.v:239:11: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 239 | cht = tagged Invalid; + | ^~~~~~ +%Error: t/t_tagged_union.v:240:11: syntax error, unexpected tagged, expecting IDENTIFIER-for-type + 240 | cht = tagged Handle (null); + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_tagged_union.py b/test_regress/t/t_tagged_union.py new file mode 100755 index 000000000..710a094ab --- /dev/null +++ b/test_regress/t/t_tagged_union.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile(fails=test.vlt_all, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_tagged_union.v b/test_regress/t/t_tagged_union.v new file mode 100644 index 000000000..31995165d --- /dev/null +++ b/test_regress/t/t_tagged_union.v @@ -0,0 +1,276 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// Test tagged union declaration, expressions, and member access +// IEEE 1800-2023 Sections 7.3.2, 11.9 + +// Class for testing class references in tagged unions +class TestClass; + int value; + function new(int v); + value = v; + endfunction +endclass + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); + +module t; + + // Basic tagged union with void and int (IEEE example) + typedef union tagged { + void Invalid; + int Valid; + } VInt; + + // Tagged union with multiple data types including wide types + // Tests: non-zero LSBs, 60-bit (33-64 range), 90-bit (64+ range), opposite endianness + typedef union tagged packed { + void Invalid; + int IntVal; + shortint ShortVal; + longint LongVal; + byte ByteVal; + bit BitVal; + logic LogicVal; + bit [8:1] Byte8NonZeroLSB; // Non-zero LSB + bit [16:1] Word16NonZeroLSB; // Non-zero LSB + bit [0:31] Word32LittleEndian; // Opposite endianness + bit [0:15] Word16LittleEndian; // Opposite endianness + bit [59:0] Wide60; // 60-bit (33-64 special handling) + bit [89:0] Wide90; // 90-bit (64+ special handling) + bit [63:4] Wide60NonZeroLSB; // 60-bit with non-zero LSB + bit [99:10] Wide90NonZeroLSB; // 90-bit with non-zero LSB + bit [0:59] Wide60LittleEndian; // 60-bit opposite endianness + bit [0:89] Wide90LittleEndian; // 90-bit opposite endianness + } MultiType; + + // Tagged union with unpacked array members + typedef union tagged { + void Invalid; + int Scalar; + int UnpackedArr[4]; // Unpacked array + bit [31:0] UnpackedArr2D[2][3]; // 2D unpacked array + } ArrayType; + + // Tagged union with nested struct (IEEE example) + typedef union tagged { + struct { + bit [4:0] reg1, reg2, regd; + } Add; + union tagged { + bit [9:0] JmpU; + struct { + bit [1:0] cc; + bit [9:0] addr; + } JmpC; + } Jmp; + } Instr; + + // Tagged union with chandle member + typedef union tagged { + void Invalid; + chandle Handle; + } ChandleType; + + // Tagged union with class reference member + typedef union tagged { + void Invalid; + TestClass Obj; + } ClassType; + + // Enum for testing enum members + typedef enum {RED, GREEN, BLUE} Color; + + // Tagged union with real/shortreal members + typedef union tagged { + void Invalid; + real RealVal; + shortreal ShortRealVal; + } RealType; + + // Tagged union with string member + typedef union tagged { + void Invalid; + string StrVal; + } StringType; + + // Tagged union with enum member + typedef union tagged { + void Invalid; + Color ColorVal; + } EnumType; + +`ifndef VCS + // Tagged union with event member + // Note: VCS incorrectly reports "the event data type is not allowed in structures and unions" + // but IEEE 1800-2023 does not prohibit this + typedef union tagged { + void Invalid; + event EvtVal; + } EventType; +`endif + + VInt vi1, vi2; + MultiType mt; + ArrayType at; + Instr instr; + ChandleType cht; + ClassType clt; + TestClass obj; + RealType rt; + StringType st; + EnumType et; +`ifndef VCS + EventType evt; +`endif + + initial begin + // Test 1: Basic void member + vi1 = tagged Invalid; + vi2 = tagged Invalid; + + // Test 2: Basic value member + vi1 = tagged Valid (42); + `checkh(vi1.Valid, 42); + + vi2 = tagged Valid (23 + 34); + `checkh(vi2.Valid, 57); + + // Test 3: MultiType with various data types + mt = tagged Invalid; + + mt = tagged IntVal (32'h12345678); + `checkh(mt.IntVal, 32'h12345678); + + mt = tagged ShortVal (16'hABCD); + `checkh(mt.ShortVal, 16'hABCD); + + mt = tagged ByteVal (8'h5A); + `checkh(mt.ByteVal, 8'h5A); + + mt = tagged BitVal (1'b1); + `checkh(mt.BitVal, 1'b1); + + // Test 4: Non-zero LSB types + mt = tagged Byte8NonZeroLSB (8'hA5); + `checkh(mt.Byte8NonZeroLSB, 8'hA5); + + mt = tagged Word16NonZeroLSB (16'h1234); + `checkh(mt.Word16NonZeroLSB, 16'h1234); + + // Test 5: Opposite endianness (little-endian style ranges) + mt = tagged Word32LittleEndian (32'hDEADBEEF); + `checkh(mt.Word32LittleEndian, 32'hDEADBEEF); + + mt = tagged Word16LittleEndian (16'hCAFE); + `checkh(mt.Word16LittleEndian, 16'hCAFE); + + // Test 6: Wide types (60-bit, in 33-64 range) + mt = tagged Wide60 (60'hFEDCBA987654321); + `checkh(mt.Wide60, 60'hFEDCBA987654321); + + mt = tagged Wide60NonZeroLSB (60'h123456789ABCDEF); + `checkh(mt.Wide60NonZeroLSB, 60'h123456789ABCDEF); + + mt = tagged Wide60LittleEndian (60'hABCDEF012345678); + `checkh(mt.Wide60LittleEndian, 60'hABCDEF012345678); + + // Test 7: Wide types (90-bit, in 64+ range) + mt = tagged Wide90 (90'hFF_FFFFFFFF_FFFFFFFF_FFFF); + `checkh(mt.Wide90, 90'hFF_FFFFFFFF_FFFFFFFF_FFFF); + + mt = tagged Wide90NonZeroLSB (90'hDE_ADBEEFCA_FEBABE12_3456); + `checkh(mt.Wide90NonZeroLSB, 90'hDE_ADBEEFCA_FEBABE12_3456); + + mt = tagged Wide90LittleEndian (90'h11_11111122_22222233_3333); + `checkh(mt.Wide90LittleEndian, 90'h11_11111122_22222233_3333); + + // Test 8: Unpacked array members + at = tagged Invalid; + + at = tagged Scalar (999); + `checkh(at.Scalar, 999); + + at = tagged UnpackedArr '{100, 200, 300, 400}; + `checkh(at.UnpackedArr[0], 100); + `checkh(at.UnpackedArr[1], 200); + `checkh(at.UnpackedArr[2], 300); + `checkh(at.UnpackedArr[3], 400); + + at = tagged UnpackedArr2D '{'{32'hA, 32'hB, 32'hC}, '{32'hD, 32'hE, 32'hF}}; + `checkh(at.UnpackedArr2D[0][0], 32'hA); + `checkh(at.UnpackedArr2D[0][1], 32'hB); + `checkh(at.UnpackedArr2D[0][2], 32'hC); + `checkh(at.UnpackedArr2D[1][0], 32'hD); + `checkh(at.UnpackedArr2D[1][1], 32'hE); + `checkh(at.UnpackedArr2D[1][2], 32'hF); + + // Test 9: Nested tagged union (Instr example from IEEE) + instr = tagged Add '{5'd1, 5'd2, 5'd3}; + `checkh(instr.Add.reg1, 5'd1); + `checkh(instr.Add.reg2, 5'd2); + `checkh(instr.Add.regd, 5'd3); + + // Create Add with named struct fields + instr = tagged Add '{reg2:5'd10, regd:5'd20, reg1:5'd5}; + `checkh(instr.Add.reg1, 5'd5); + `checkh(instr.Add.reg2, 5'd10); + `checkh(instr.Add.regd, 5'd20); + + // Test 10: Nested tagged union - unconditional jump + instr = tagged Jmp (tagged JmpU 10'd512); + `checkh(instr.Jmp.JmpU, 10'd512); + + // Test 11: Nested tagged union - conditional jump + instr = tagged Jmp (tagged JmpC '{2'd1, 10'd256}); + `checkh(instr.Jmp.JmpC.cc, 2'd1); + `checkh(instr.Jmp.JmpC.addr, 10'd256); + + // Test 12: Nested tagged union - conditional jump with named fields + instr = tagged Jmp (tagged JmpC '{cc:2'd3, addr:10'd100}); + `checkh(instr.Jmp.JmpC.cc, 2'd3); + `checkh(instr.Jmp.JmpC.addr, 10'd100); + + // Test 13: Chandle member + cht = tagged Invalid; + cht = tagged Handle (null); + + // Test 14: Class reference member + obj = new(42); + clt = tagged Invalid; + clt = tagged Obj (obj); + `checkh(clt.Obj.value, 42); + + // Test 15: Real member + rt = tagged Invalid; + rt = tagged RealVal (3.14159); + if (rt.RealVal != 3.14159) $stop; + + // Test 16: Shortreal member + rt = tagged ShortRealVal (2.5); + if (rt.ShortRealVal != 2.5) $stop; + + // Test 17: String member + st = tagged Invalid; + st = tagged StrVal ("hello"); + if (st.StrVal != "hello") $stop; + + // Test 18: Enum member + et = tagged Invalid; + et = tagged ColorVal (GREEN); + if (et.ColorVal != GREEN) $stop; + +`ifndef VCS + // Test 19: Event member + evt = tagged Invalid; +`endif + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule