verilator/test_regress/t/t_display_enum_format.v

200 lines
7.2 KiB
Systemverilog

// DESCRIPTION: Verilator: Verilog Test module
//
// 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-FileCopyrightText: 2026 Wilson Snyder
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
module t (
input string empty_no_opt
);
typedef enum logic [1:0] {
E0 = 0,
E1 = 1,
E2 = 2
} my_e;
typedef enum logic [63:0] {
W64A = 64'h1,
W64B = 64'h0000_0001_0000_0001
} wide64_e;
// Enums > 64 bits are beyond enum.name() support, so %p/%s format numerically
typedef enum logic [95:0] {
W96A = 96'h1,
W96B = 96'hA_0000_0000_0000_0001
} wide96_e;
typedef logic signed [4095:0] uvm_bitstream_t;
my_e e;
wide64_e e64;
wide96_e e96;
logic [63:0] n64;
uvm_bitstream_t bitstream_value;
`define check(got, exp) do if ((got) != (exp)) begin \
$write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__, `__LINE__, got, exp); \
$stop; \
end while(0)
initial begin
string fmt;
begin
my_e it;
string names_p;
string names_s;
string vals_d;
names_p = "";
names_s = "";
vals_d = "";
for (it = it.first; ; it = it.next) begin
if (names_p != "") begin
names_p = {names_p, ","};
names_s = {names_s, ","};
vals_d = {vals_d, ","};
end
names_p = {names_p, $sformatf("%p", it)};
names_s = {names_s, $sformatf("%s", it)};
vals_d = {vals_d, $sformatf("%0d", it)};
if (it == it.last) break;
end
`check(names_p, "E0,E1,E2");
`check(names_s, "E0,E1,E2");
`check(vals_d, "0,1,2");
end
// Valid enum values print mnemonic for %p/%s.
e = E0;
`check($sformatf("%p", e), "E0");
`check($sformatf("%s", e), "E0");
e = E1;
`check($sformatf("%p", e), "E1");
`check($sformatf("%P", e), "E1");
`check($sformatf("%0p", e), "E1");
`check($sformatf("%s", e), "E1");
`check($sformatf("%S", e), "E1");
`check($sformatf("%d", e), "1");
`check($sformatf("%0d", e), "1");
`check($sformatf("%h", e), "1");
`check($sformatf("%0h", e), "1");
`check($sformatf("%b", e), "01");
`check($sformatf("%0b", e), "1");
`check($sformatf("%o", e), "1");
`check($sformatf("%0o", e), "1");
`check($sformatf("%x", e), "1");
`check($sformatf("%0x", e), "1");
e = E2;
`check($sformatf("%p", e), "E2");
`check($sformatf("%s", e), "E2");
`check($sformatf("%s|%p", e, e), "E2|E2");
`check($sformatf("%4p", e), "E2");
`check($sformatf("%-4p", e), "E2");
`check($sformatf("%d", e), "2");
`check($sformatf("%h", e), "2");
`check($sformatf("%b", e), "10");
`check($sformatf("%0b", e), "10");
`check($sformatf("%o", e), "2");
`check($sformatf("%x", e), "2");
`check($sformatf("%4d", e), " 2");
`check($sformatf("%04d", e), "0002");
`check($sformatf("%4h", e), "0002");
`check($sformatf("%-4s", e), "E2 ");
`check($sformatf("%4s", e), " E2");
// `%p`/`%s` in non-terminal positions with mixed formatters.
`check($sformatf("%0d:%s:%0d", 9, e, 7), "9:E2:7");
`check($sformatf("%s %h %p", e, 4'hA, e), "E2 a E2");
`check($sformatf("pre %% %s post", e), "pre % E2 post");
// Complex enum expressions (non-var-ref) in format args.
`check($sformatf("%s", (1'b1 ? E2 : E0)), "E2");
// 64-bit enums should preserve bits above 32 in both named and numeric cases.
e64 = W64B;
`check($sformatf("%p", e64), "W64B");
`check($sformatf("%s", e64), "W64B");
e64 = wide64_e'(64'h0000_0002_0000_0001);
`check($sformatf("%p", e64), "8589934593");
`check($sformatf("%s", e64), "8589934593");
n64 = 64'h0000_0000_0000_0001;
`check($sformatf("%0p", n64), "'h1");
// > 64-bit enums print numerically for %p (no name table support)
e96 = W96B; // 10 * 2**64 + 1
if (empty_no_opt != "") e96 = W96A; // Defeat constant folding
`check($sformatf("%p", e96), "184467440737095516161");
`check($sformatf("%0p", e96), "'ha0000000000000001");
`check($sformatf("%0d", e96), "184467440737095516161");
`check($sformatf("%0h", e96), "a0000000000000001");
// Exercise display/write-family formatting path in addition to $sformatf checks.
$display("display-valid:%s:%0d:%p", e, 7, e);
$write("write-valid:%s:%0d:%p\n", e, 8, e);
// Invalid enum values fall back to numeric formatting for %p/%s.
e = my_e'(3);
`check($sformatf("%p", e), "3");
`check($sformatf("%P", e), "3");
`check($sformatf("%0p", e), "'h3");
`check($sformatf("%s", e), "3");
`check($sformatf("%S", e), "3");
`check($sformatf("%4p", e), "3");
`check($sformatf("%4s", e), " 3");
`check($sformatf("%d", e), "3");
`check($sformatf("%0d", e), "3");
`check($sformatf("%h", e), "3");
`check($sformatf("%0h", e), "3");
`check($sformatf("%b", e), "11");
`check($sformatf("%0b", e), "11");
`check($sformatf("%o", e), "3");
`check($sformatf("%x", e), "3");
// Non-terminal invalid-value fallback with mixed formatters.
`check($sformatf("%0d:%p:%0d", 9, e, 7), "9:3:7");
`check($sformatf("%s %h %p", e, 4'hA, e), "3 a 3");
`check($sformatf("pre %% %s post", e), "pre % 3 post");
`check($sformatf("%s|%p", e, e), "3|3");
`check($sformatf("%s", (1'b1 ? my_e'(3) : E0)), "3");
`check($sformatf("%p", (1'b0 ? E0 : my_e'(3))), "3");
$display("display-invalid:%s:%0d:%p", e, 7, e);
$write("write-invalid:%s:%0d:%p\n", e, 8, e);
// Runtime-computed $sformatf formats should preserve enum mnemonic/fallback behavior.
e = E2;
fmt = {"%", "s", empty_no_opt};
`check($sformatf(fmt, e), "E2");
fmt = {"%", "p", empty_no_opt};
`check($sformatf(fmt, e), "E2");
fmt = {"%0d:%", "s", ":%0d", empty_no_opt};
`check($sformatf(fmt, 9, e, 7), "9:E2:7");
fmt = {"%", "s", " %h %", "p", empty_no_opt};
`check($sformatf(fmt, e, 4'hA, e), "E2 a E2");
e = my_e'(3);
fmt = {"%", "s", empty_no_opt};
`check($sformatf(fmt, e), "3");
fmt = {"%", "p", empty_no_opt};
`check($sformatf(fmt, e), "3");
fmt = {"%0", "p", empty_no_opt};
`check($sformatf(fmt, e), "'h3");
fmt = {"%0d:%", "s", ":%0d", empty_no_opt};
`check($sformatf(fmt, 9, e, 7), "9:3:7");
fmt = {"%", "s", " %h %", "p", empty_no_opt};
`check($sformatf(fmt, e, 4'hA, e), "3 a 3");
fmt = {"%", "p", empty_no_opt};
`check($sformatf(fmt, e64), "8589934593");
// > 64-bit enums use the non-ENUM format in runtime formats too
fmt = {"%", "p", empty_no_opt};
`check($sformatf(fmt, e96), "184467440737095516161");
fmt = {"%0d", empty_no_opt};
`check($sformatf(fmt, e96), "184467440737095516161");
bitstream_value = 30;
`check($sformatf("%0s%0t", "", bitstream_value), "30");
bitstream_value = '0;
bitstream_value[32] = 1'b1;
`check($sformatf("%0s%0t", "", bitstream_value), "4294967296");
bitstream_value = '0;
bitstream_value[63:0] = 64'h0000_0001_0000_0001;
`check($sformatf("%0s%0t", "", bitstream_value), "4294967297");
bitstream_value[7:0] = "A";
// verilator lint_off WIDTHTRUNC
`check($sformatf("%c", bitstream_value), "A");
// verilator lint_on WIDTHTRUNC
$write("*-* All Finished *-*\n");
$finish;
end
endmodule