Add wire data type checking per IEEE.

This commit is contained in:
Wilson Snyder 2025-07-20 07:21:30 -04:00
parent b8b9478938
commit 078bb21a89
20 changed files with 181 additions and 75 deletions

View File

@ -16,7 +16,7 @@ Verilator 5.039 devel
* Add ENUMITEMWIDTH error, and apply to X-extended and ranged values.
* Add NOEFFECT warning, replacing previous `foreach` error.
* Add SPECIFYIGN warning for specify constructs that were previously silently ignored.
* Add enum base type checking per IEEE.
* Add enum base data type, and wire data type checking per IEEE.
* Support member-level triggers for virtual interfaces (#5166) (#6148). [Yilou Wang]
* Support disabling a fork in additional contexts (#5432 partial) (#6174) (#6183). [Ryszard Rozak, Antmicro Ltd.]
* Support disable dotted references (#6154). [Ryszard Rozak, Antmicro Ltd.]

View File

@ -3,6 +3,6 @@
:linenos:
:emphasize-lines: 3
int array[5];
bit [1:0] rd_addr;
wire int rd_value = array[rd_addr]; //<--- Warning
logic [31:0] array[5];
bit [1:0] rd_addr;
wire [31:0] rd_value = array[rd_addr]; //<--- Warning

View File

@ -2,4 +2,4 @@
.. code-block:: sv
:emphasize-lines: 1
wire int rd_value = array[{1'b0, rd_addr}]; //<--- Fixed
wire [31:0] rd_value = array[{1'b0, rd_addr}]; //<--- Fixed

View File

@ -1,4 +1,4 @@
.. comment: generated by t_lint_widthexpand_docs_bad
.. code-block::
%Warning-WIDTHEXPAND: example.v:3:29 Bit extraction of array[4:0] requires 3 bit index, not 2 bits.
%Warning-WIDTHEXPAND: example.v:3:31 Bit extraction of array[4:0] requires 3 bit index, not 2 bits.

View File

@ -2422,6 +2422,18 @@ class WidthVisitor final : public VNVisitor {
nodep->dtypeSetLogicSized(1, bdtypep->numeric());
VL_DANGLING(bdtypep);
}
if (nodep->isNet()) {
AstNodeDType* const badDtp = dtypeNot4StateIntegralRecurse(nodep->dtypep());
if (badDtp)
nodep->v3error(
"Net " << nodep->prettyNameQ()
<< " data type must be 4-state integral or array/union/struct of such"
<< " (IEEE 1800-2023 6.7.1)\n"
<< nodep->warnContextPrimary() << '\n'
<< badDtp->warnOther() << "... Location of failing data type "
<< badDtp->prettyDTypeNameQ() << '\n'
<< badDtp->warnContextSecondary());
}
if (nodep->valuep() && !didchk) {
// if (debug()) nodep->dumpTree("- final: ");
// AstPattern requires assignments to pass datatype on PRELIM
@ -8328,6 +8340,25 @@ class WidthVisitor final : public VNVisitor {
}
return nodep;
}
AstNodeDType* dtypeNot4StateIntegralRecurse(AstNodeDType* nodep) {
// If node is _not_ inet valid data type, 4-state integral packed or union, return node
// that makes it fail
nodep = nodep->skipRefp();
if (AstBasicDType* const dtp = VN_CAST(nodep, BasicDType)) {
if (!dtp->keyword().isFourstate()) return dtp;
return nullptr;
} else if (AstNodeArrayDType* const dtp = VN_CAST(nodep, NodeArrayDType)) {
return dtypeNot4StateIntegralRecurse(nodep->subDTypep());
} else if (AstNodeUOrStructDType* const dtp = VN_CAST(nodep, NodeUOrStructDType)) {
for (AstMemberDType* itemp = dtp->membersp(); itemp;
itemp = VN_AS(itemp->nextp(), MemberDType)) {
AstNodeDType* const badDtp = dtypeNot4StateIntegralRecurse(itemp->dtypep());
if (badDtp) return badDtp;
}
return nullptr;
}
return nodep;
}
//----------------------------------------------------------------------
// METHODS - special type detection

View File

@ -6,7 +6,8 @@
module t (/*AUTOARG*/);
wire bit [255:0] C = {32'h1111_1111,
bit [255:0] C;
initial C = {32'h1111_1111,
32'h2222_2222,
32'h3333_3333,
32'h4444_4444,
@ -16,7 +17,8 @@ module t (/*AUTOARG*/);
32'h8888_8888};
// Same values as above, but with different type
wire logic [255:0] D = {32'h1111_1111,
logic [255:0] D;
initial D = {32'h1111_1111,
32'h2222_2222,
32'h3333_3333,
32'h4444_4444,
@ -28,7 +30,7 @@ module t (/*AUTOARG*/);
int i;
initial begin
// Note: Base index via $c to prevent optimizatoin by Verilator
// Note: Base index via $c to prevent optimization by Verilator
i = $c(0*32); $display("0x%8x", C[i+:32]);
i = $c(1*32); $display("0x%8x", D[i+:32]);
i = $c(2*32); $display("0x%8x", C[i+:32]);

View File

@ -19,6 +19,6 @@ test.execute(expect_filename=test.golden_filename)
if test.vlt_all:
test.file_grep(test.stats, r'Optimizations, Prelim extracted value to ConstPool\s+(\d+)', 8)
test.file_grep(test.stats, r'ConstPool, Constants emitted\s+(\d+)', 2)
test.file_grep(test.stats, r'ConstPool, Constants emitted\s+(\d+)', 1)
test.passes()

View File

@ -13,7 +13,7 @@ module sub;
/* verilator no_inline_module */
// Goes into const pool which is separate file
wire bit [255:0] C = {32'h1111_1111,
wire logic [255:0] C = {32'h1111_1111,
32'h2222_2222,
32'h3333_3333,
32'h4444_4444,

View File

@ -1,7 +1,7 @@
%Warning-WIDTHEXPAND: t/t_lint_widthexpand_docs_bad.v:10:29: Bit extraction of array[4:0] requires 3 bit index, not 2 bits.
%Warning-WIDTHEXPAND: t/t_lint_widthexpand_docs_bad.v:10:31: Bit extraction of array[4:0] requires 3 bit index, not 2 bits.
: ... note: In instance 't'
10 | wire int rd_value = array[rd_addr];
| ^
10 | wire [31:0] rd_value = array[rd_addr];
| ^
... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest
... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message.
%Error: Exiting due to

View File

@ -5,15 +5,15 @@
// SPDX-License-Identifier: CC0-1.0
module t;
int array[5];
bit [1:0] rd_addr;
wire int rd_value = array[rd_addr]; //<--- Warning
logic [31:0] array[5];
bit [1:0] rd_addr;
wire [31:0] rd_value = array[rd_addr]; //<--- Warning
ok ok();
ok ok ();
endmodule
module ok;
int array[5];
bit [1:0] rd_addr;
wire int rd_value = array[{1'b0, rd_addr}]; //<--- Fixed
endmodule;
logic [31:0] array[5];
bit [1:0] rd_addr;
wire [31:0] rd_value = array[{1'b0, rd_addr}]; //<--- Fixed
endmodule

View File

@ -0,0 +1,37 @@
%Error: t/t_net_dtype_bad.v:25:15: Net 'bad_real' data type must be 4-state integral or array/union/struct of such (IEEE 1800-2023 6.7.1)
: ... note: In instance 't'
25 | wire real_t bad_real;
| ^~~~~~~~
t/t_net_dtype_bad.v:11:11: ... Location of failing data type 'real'
11 | typedef real real_t;
| ^~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: t/t_net_dtype_bad.v:27:12: Net 'bad_class' data type must be 4-state integral or array/union/struct of such (IEEE 1800-2023 6.7.1)
: ... note: In instance 't'
27 | wire Cls bad_class;
| ^~~~~~~~~
t/t_net_dtype_bad.v:27:8: ... Location of failing data type 'class{}Cls'
27 | wire Cls bad_class;
| ^~~
%Error: t/t_net_dtype_bad.v:29:15: Net 'bad_string' data type must be 4-state integral or array/union/struct of such (IEEE 1800-2023 6.7.1)
: ... note: In instance 't'
29 | wire string bad_string;
| ^~~~~~~~~~
t/t_net_dtype_bad.v:29:8: ... Location of failing data type 'string'
29 | wire string bad_string;
| ^~~~~~
%Error: t/t_net_dtype_bad.v:31:12: Net 'bad_bit' data type must be 4-state integral or array/union/struct of such (IEEE 1800-2023 6.7.1)
: ... note: In instance 't'
31 | wire bit bad_bit;
| ^~~~~~~
t/t_net_dtype_bad.v:31:8: ... Location of failing data type 'bit'
31 | wire bit bad_bit;
| ^~~
%Error: t/t_net_dtype_bad.v:33:14: Net 'bad_struct' data type must be 4-state integral or array/union/struct of such (IEEE 1800-2023 6.7.1)
: ... note: In instance 't'
33 | wire bad_t bad_struct;
| ^~~~~~~~~~
t/t_net_dtype_bad.v:14:5: ... Location of failing data type 'bit'
14 | bit m_bit;
| ^~~
%Error: Exiting due to

View File

@ -0,0 +1,16 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 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('linter')
test.lint(fails=True, expect_filename=test.golden_filename)
test.passes()

View File

@ -0,0 +1,40 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class Cls;
endclass
module t;
typedef real real_t;
typedef struct packed {
bit m_bit;
} bad_t;
typedef struct {
logic m_bit;
} ok_unpk_t;
typedef struct packed {
logic m_bit;
} ok_t;
wire real_t bad_real; // <--- Error - bad net type
wire Cls bad_class; // <--- Error - bad net type
wire string bad_string; // <--- Error - bad net type
wire bit bad_bit; // <--- Error - bad net type
wire bad_t bad_struct; // <--- Error - bad net type
wire ok_unpk_t ok_unpk_struct;
wire ok_t ok_struct; // Ok
initial $stop;
endmodule

View File

@ -45,7 +45,8 @@ module t(/*AUTOARG*/
int cnt = 0;
always @(posedge gclk[n]) cnt <= cnt + 1;
wire int cnt_plus_one = cnt + 1;
int cnt_plus_one;
always_comb cnt_plus_one = cnt + 1;
final begin
`checkh(cnt_plus_one, ITERATIONS + 1);

View File

@ -10,10 +10,10 @@ module t;
//typedef struct pack2; // Forward declaration
typedef struct packed { // [3:0]
bit b3;
bit b2;
bit b1;
bit b0;
logic b3;
logic b2;
logic b1;
logic b0;
} b4_t;
typedef struct packed { // [3:0]
@ -28,17 +28,17 @@ module t;
} q4_t;
typedef struct packed { // [5:0]
bit msb;
logic msb;
q4_t four;
bit lsb;
logic lsb;
} pack2_t;
typedef union packed { // [5:0]
pack2_t pack2;
bit [6:1] pvec;
// Vector not allowed in packed structure, per spec:
// bit vec[6];
// bit vec2d[2][3];
// logic vec[6];
// logic vec2d[2][3];
} pack3_t;
const b4_t b4_const_a = '{1'b1, 1'b0, 1'b0, 1'b1};

View File

@ -28,7 +28,8 @@ endmodule
module sub1 #(parameter int ADD)
(input int cyc);
wire int value = cyc + ADD;
int value;
always_comb value = cyc + ADD;
sub2 #(ADD + 1) sub2a(.*);
sub2 #(ADD + 2) sub2b(.*);
@ -38,5 +39,6 @@ endmodule
module sub2 #(parameter int ADD)
(input int cyc);
wire int value = cyc + ADD;
int value;
always_comb value = cyc + ADD;
endmodule

View File

@ -1,5 +1,5 @@
$date
Sat Mar 5 14:06:13 2022
Sat Jul 19 22:57:16 2025
$end
$version
@ -16,41 +16,41 @@ $var int 32 " cyc [31:0] $end
$scope module sub1a $end
$var parameter 32 # ADD [31:0] $end
$var wire 32 " cyc [31:0] $end
$var wire 32 $ value [31:0] $end
$var int 32 $ value [31:0] $end
$scope module sub2a $end
$var parameter 32 % ADD [31:0] $end
$var wire 32 " cyc [31:0] $end
$var wire 32 & value [31:0] $end
$var int 32 & value [31:0] $end
$upscope $end
$scope module sub2b $end
$var parameter 32 ' ADD [31:0] $end
$var wire 32 " cyc [31:0] $end
$var wire 32 ( value [31:0] $end
$var int 32 ( value [31:0] $end
$upscope $end
$scope module sub2c $end
$var parameter 32 ) ADD [31:0] $end
$var wire 32 " cyc [31:0] $end
$var wire 32 * value [31:0] $end
$var int 32 * value [31:0] $end
$upscope $end
$upscope $end
$scope module sub1b $end
$var parameter 32 + ADD [31:0] $end
$var wire 32 " cyc [31:0] $end
$var wire 32 , value [31:0] $end
$var int 32 , value [31:0] $end
$scope module sub2a $end
$var parameter 32 - ADD [31:0] $end
$var wire 32 " cyc [31:0] $end
$var wire 32 . value [31:0] $end
$var int 32 . value [31:0] $end
$upscope $end
$scope module sub2b $end
$var parameter 32 / ADD [31:0] $end
$var wire 32 " cyc [31:0] $end
$var wire 32 0 value [31:0] $end
$var int 32 0 value [31:0] $end
$upscope $end
$scope module sub2c $end
$var parameter 32 1 ADD [31:0] $end
$var wire 32 " cyc [31:0] $end
$var wire 32 2 value [31:0] $end
$var int 32 2 value [31:0] $end
$upscope $end
$upscope $end
$upscope $end

View File

@ -1,5 +1,5 @@
$date
Sat Apr 5 13:56:24 2025
Sat Jul 19 22:57:23 2025
$end
$version
@ -14,7 +14,7 @@ $var int 32 ! cyc [31:0] $end
$scope module sub1a $end
$var parameter 32 " ADD [31:0] $end
$var wire 32 ! cyc [31:0] $end
$var wire 32 # value [31:0] $end
$var int 32 # value [31:0] $end
$scope module sub2a $end
$upscope $end
$scope module sub2b $end
@ -25,21 +25,21 @@ $upscope $end
$scope module sub1b $end
$var parameter 32 $ ADD [31:0] $end
$var wire 32 ! cyc [31:0] $end
$var wire 32 % value [31:0] $end
$var int 32 % value [31:0] $end
$scope module sub2a $end
$var parameter 32 & ADD [31:0] $end
$var wire 32 ! cyc [31:0] $end
$var wire 32 ' value [31:0] $end
$var int 32 ' value [31:0] $end
$upscope $end
$scope module sub2b $end
$var parameter 32 ( ADD [31:0] $end
$var wire 32 ! cyc [31:0] $end
$var wire 32 ) value [31:0] $end
$var int 32 ) value [31:0] $end
$upscope $end
$scope module sub2c $end
$var parameter 32 * ADD [31:0] $end
$var wire 32 ! cyc [31:0] $end
$var wire 32 + value [31:0] $end
$var int 32 + value [31:0] $end
$upscope $end
$upscope $end
$upscope $end

View File

@ -28,7 +28,8 @@ endmodule
module sub1 #(parameter int ADD)
(input int cyc);
wire int value = cyc + ADD;
int value;
always_comb value = cyc + ADD;
sub2 #(ADD + 1) sub2a(.*);
sub2 #(ADD + 2) sub2b(.*);
@ -38,5 +39,6 @@ endmodule
module sub2 #(parameter int ADD)
(input int cyc);
wire int value = cyc + ADD;
int value;
always_comb value = cyc + ADD;
endmodule

View File

@ -15,48 +15,23 @@ module t (/*AUTOARG*/
input clk;
// IEEE: integer_atom_type
wire byte w_byte;
wire shortint w_shortint;
wire int w_int;
wire longint w_longint;
wire integer w_integer;
// IEEE: integer_atom_type
wire bit w_bit;
wire logic w_logic;
wire bit [1:0] w_bit2;
wire logic [1:0] w_logic2;
// IEEE: non_integer_type
//UNSUP shortreal w_shortreal;
wire real w_real;
assign w_byte = 8'h12;
assign w_shortint = 16'h1234;
assign w_int = -123456;
assign w_longint = -1234567;
assign w_integer = -123456;
assign w_bit = 1'b1;
assign w_logic = 1'b1;
assign w_bit2 = 2'b10;
assign w_logic2 = 2'b10;
assign w_real = 3.14;
always @ (posedge clk) begin
`checkh(w_byte, 8'h12);
`checkh(w_shortint, 16'h1234);
`checkh(w_int, -123456);
`checkh(w_longint, -1234567);
`checkh(w_integer, -123456);
`checkh(w_bit, 1'b1);
`checkh(w_logic, 1'b1);
`checkh(w_bit2, 2'b10);
`checkh(w_logic2, 2'b10);
`checkr(w_real, 3.14);
$write("*-* All Finished *-*\n");
$finish;
end