IMPORTANT: Rewrite tristate handling, tri0, tri1, etc.

This commit is contained in:
Wilson Snyder 2012-04-21 21:45:28 -04:00
parent 0048b04540
commit 9734931f67
20 changed files with 1026 additions and 663 deletions

View File

@ -5,8 +5,15 @@ indicates the contributor was also the author of the fix; Thanks!
* Verilator 3.840 devel
** Rewrote tristate handling; supports tri0, tri1, tristate bit selects,
concatenates and pullup/pulldowns, bug395, bug56, bug54, bug51.
[Alex Solomatnikov, Lane Brooks, et al]
*** Support tri0 and tri1, bug462. [Alex Solomatnikov]
*** Fix generate operators not short circuiting, bug413. [by Jeremy Bennett]
* Verilator 3.833 2012/04/15
*** Support += and -= in standard for loops, bug463. [Alex Solomatnikov]

View File

@ -2212,11 +2212,11 @@ optimizations will be disabled around the latch.
All delays (#) are ignored, as they are in synthesis.
=head2 Two State
=head2 Unknown states
Verilator is a two state simulator, not a four state simulator. However, it
has two features which uncover most initialization bugs (including many that
a four state simulator will miss.)
Verilator is mostly a two state simulator, not a four state simulator.
However, it has two features which uncover most initialization bugs
(including many that a four state simulator will miss.)
Identity comparisons (=== or !==) are converted to standard ==/!== when
neither side is a constant. This may make the expression result differ
@ -2238,19 +2238,21 @@ practice, just setting all variables to one at startup finds most problems.
=head2 Tri/Inout
Verilator converts some simple tristate structures into two state. An assignment
of the form:
Verilator converts some simple tristate structures into two state. Pullup,
pulldown, bufif0, bufif1, notif0, notif1, tri0 and tri1 are also supported.
Simple comparisons with === 1'bz are also supported.
An assignment of the form:
inout driver;
wire driver = (enable) ? output_value : 1'bz;
Will be converted to
input driver__in; // Value being driven in from "external" drivers
output driver__en; // True if driven from this module
output driver__enout; // Value being driven from this module
input driver; // Value being driven in from "external" drivers
output driver__en; // True if driven from this module
output driver__out; // Value being driven from this module
Pullup, pulldown, bufif0, bufif1, notif0, notif1 are also supported.
External logic will be needed to combine these signals with any external
drivers.

File diff suppressed because it is too large Load Diff

View File

@ -32,7 +32,6 @@
class V3Tristate {
public:
static void tristateAll(AstNetlist* nodep);
static void inoutAll(AstNetlist* nodep);
};
#endif // Guard

View File

@ -233,12 +233,6 @@ void process () {
V3Const::constifyAllLint(v3Global.rootp());
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
if (!v3Global.opt.xmlOnly()) {
// Expand Inouts
V3Tristate::inoutAll(v3Global.rootp());
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("inouts.tree"));
}
if (!v3Global.opt.xmlOnly()) {
// Remove cell arrays (must be between V3Width and scoping)
V3Inst::dearrayAll(v3Global.rootp());

View File

@ -296,6 +296,8 @@ word [a-zA-Z0-9_]+
"tranif0" { FL; return yTRANIF0; }
"tranif1" { FL; return yTRANIF1; }
"tri" { FL; return yTRI; }
"tri0" { FL; return yTRI0; }
"tri1" { FL; return yTRI1; }
"vectored" { FL; return yVECTORED; }
"while" { FL; return yWHILE; }
"wire" { FL; return yWIRE; }
@ -333,8 +335,6 @@ word [a-zA-Z0-9_]+
"triand" { yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext); }
"trior" { yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext); }
"trireg" { yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext); }
"tri0" { yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext); }
"tri1" { yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext); }
"wait" { yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext); }
"wand" { yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext); }
"weak0" { yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext); }

View File

@ -376,6 +376,8 @@ class AstSenTree;
%token<fl> yTRANIF0 "tranif0"
%token<fl> yTRANIF1 "tranif1"
%token<fl> yTRI "tri"
%token<fl> yTRI0 "tri0"
%token<fl> yTRI1 "tri1"
%token<fl> yTRUE "true"
%token<fl> yTYPEDEF "typedef"
%token<fl> yUNIQUE "unique"
@ -1007,8 +1009,8 @@ net_type: // ==IEEE: net_type
ySUPPLY0 { VARDECL(SUPPLY0); }
| ySUPPLY1 { VARDECL(SUPPLY1); }
| yTRI { VARDECL(TRIWIRE); }
//UNSUP yTRI0 { VARDECL(TRI0); }
//UNSUP yTRI1 { VARDECL(TRI1); }
| yTRI0 { VARDECL(TRI0); }
| yTRI1 { VARDECL(TRI1); }
//UNSUP yTRIAND { VARDECL(TRIAND); }
//UNSUP yTRIOR { VARDECL(TRIOR); }
//UNSUP yTRIREG { VARDECL(TRIREG); }

View File

@ -21,7 +21,7 @@ module set (
input clk,
output enable
);
assign enable = 1'b0;
endmodule
module read (

18
test_regress/t/t_tri_eqcase.pl Executable file
View File

@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 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.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;

View File

@ -0,0 +1,128 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2011 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=0;
reg [63:0] crc;
reg [63:0] sum;
wire [3:0] drv_a = crc[3:0];
wire [3:0] drv_b = crc[7:4];
wire [3:0] drv_e = crc[19:16];
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [8:0] match1; // From test1 of Test1.v
wire [8:0] match2; // From test2 of Test2.v
// End of automatics
Test1 test1 (/*AUTOINST*/
// Outputs
.match1 (match1[8:0]),
// Inputs
.drv_a (drv_a[3:0]),
.drv_e (drv_e[3:0]));
Test2 test2 (/*AUTOINST*/
// Outputs
.match2 (match2[8:0]),
// Inputs
.drv_a (drv_a[3:0]),
.drv_e (drv_e[3:0]));
// Aggregate outputs into a single result vector
wire [63:0] result = {39'h0, match2, 7'h0, match1};
// Test loop
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] cyc==%0d crc=%x m1=%x m2=%x (%b??%b:%b)\n",$time, cyc, crc, match1, match2, drv_e,drv_a,drv_b);
`endif
cyc <= cyc + 1;
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]};
if (cyc==0) begin
// Setup
crc <= 64'h5aef0c8d_d70a4497;
sum <= 64'h0;
end
else if (cyc<10) begin
sum <= 64'h0;
end
else if (cyc<90) begin
end
else if (cyc==99) begin
$write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum);
if (crc !== 64'hc77bb9b3784ea091) $stop;
// What checksum will we end up with (above print should match)
`define EXPECTED_SUM 64'hc0c4a2b9aea7c4b4
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module Test1
(
input wire [3:0] drv_a,
input wire [3:0] drv_e,
output wire [8:0] match1
);
wire [2:1] drv_all;
bufif1 bufa [2:1] (drv_all, drv_a[2:1], drv_e[2:1]);
`ifdef VERILATOR
// At present Verilator only allows comparisons with Zs
assign match1[0] = (drv_a[2:1]== 2'b00 && drv_e[2:1]==2'b11);
assign match1[1] = (drv_a[2:1]== 2'b01 && drv_e[2:1]==2'b11);
assign match1[2] = (drv_a[2:1]== 2'b10 && drv_e[2:1]==2'b11);
assign match1[3] = (drv_a[2:1]== 2'b11 && drv_e[2:1]==2'b11);
`else
assign match1[0] = drv_all === 2'b00;
assign match1[1] = drv_all === 2'b01;
assign match1[2] = drv_all === 2'b10;
assign match1[3] = drv_all === 2'b11;
`endif
assign match1[4] = drv_all === 2'bz0;
assign match1[5] = drv_all === 2'bz1;
assign match1[6] = drv_all === 2'bzz;
assign match1[7] = drv_all === 2'b0z;
assign match1[8] = drv_all === 2'b1z;
endmodule
module Test2
(
input wire [3:0] drv_a,
input wire [3:0] drv_e,
output wire [8:0] match2
);
wire [2:1] drv_all;
bufif1 bufa [2:1] (drv_all, drv_a[2:1], drv_e[2:1]);
`ifdef VERILATOR
assign match2[0] = (drv_all !== 2'b00 || drv_e[2:1]!=2'b11);
assign match2[1] = (drv_all !== 2'b01 || drv_e[2:1]!=2'b11);
assign match2[2] = (drv_all !== 2'b10 || drv_e[2:1]!=2'b11);
assign match2[3] = (drv_all !== 2'b11 || drv_e[2:1]!=2'b11);
`else
assign match2[0] = drv_all !== 2'b00;
assign match2[1] = drv_all !== 2'b01;
assign match2[2] = drv_all !== 2'b10;
assign match2[3] = drv_all !== 2'b11;
`endif
assign match2[4] = drv_all !== 2'bz0;
assign match2[5] = drv_all !== 2'bz1;
assign match2[6] = drv_all !== 2'bzz;
assign match2[7] = drv_all !== 2'b0z;
assign match2[8] = drv_all !== 2'b1z;
endmodule

View File

@ -1,19 +1,20 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2008 by Lane Brooks
module top (input SEL, input[1:0] A, output Z, output Y, output X, output W);
module top (input SEL, input[1:0] A, output W, output X, output Y, output Z);
mux mux2 (.A(A), .SEL(SEL), .Z(W));
pass mux1 (.A(A), .SEL(SEL), .Z(X));
tbuf mux0[1:0] (.A(A), .OE({SEL,!SEL}), .Z(Y));
assign Z = ( SEL) ? A[1] : 1'bz;
tbuf tbuf(.A(A[0]), .OE(!SEL), .Z(Z));
tbuf mux0[1:0](.A(A), .OE({SEL,!SEL}), .Z(Y));
pass mux1(.A(A), .SEL(SEL), .Z(X));
mux mux2(.A(A), .SEL(SEL), .Z(W));
tbuf tbuf (.A(A[0]), .OE(!SEL), .Z(Z));
endmodule
module pass (input[1:0] A, input SEL, output Z);
tbuf tbuf1(.A(A[1]), .OE(SEL), .Z(Z));
tbuf tbuf0(.A(A[0]), .OE(!SEL),.Z(Z));
tbuf tbuf1 (.A(A[1]), .OE(SEL), .Z(Z));
tbuf tbuf0 (.A(A[0]), .OE(!SEL),.Z(Z));
endmodule
module tbuf (input A, input OE, output Z);
@ -35,4 +36,5 @@ endmodule
module mux (input[1:0] A, input SEL, output Z);
assign Z = (SEL) ? A[1] : 1'bz;
assign Z = (!SEL)? A[0] : 1'bz;
assign Z = 1'bz;
endmodule

View File

@ -4,13 +4,16 @@
module top (input A, input B, input SEL, output Y1, output Y2, output Z);
io io1(.A(A), .OE( SEL), .Z(Z), .Y(Y1));
pass io2(.A(B), .OE(!SEL), .Z(Z), .Y(Y2));
assign Z = 1'bz;
endmodule
module pass (input A, input OE, inout Z, output Y);
io io(.A(A), .OE(OE), .Z(Z), .Y(Y));
assign Z = 1'bz;
endmodule
module io (input A, input OE, inout Z, output Y);
assign Z = (OE) ? A : 1'bz;
assign Y = Z;
assign Z = 1'bz;
endmodule

17
test_regress/t/t_tri_inout2.pl Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# General Public License or the Perl Artistic License.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;

View File

@ -0,0 +1,77 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2008 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
reg [2:0] in;
wire a,y,y_fixed;
wire b = in[0];
wire en = in[1];
pullup(a);
ChildA childa ( .A(a), .B(b), .en(en), .Y(y),.Yfix(y_fixed) );
initial in=0;
initial en=0;
// Test loop
always @ (posedge clk) begin
in <= in + 1;
$display ( "a %d b %d en %d y %d yfix: %d)" , a, b, en, y, y_fixed);
if (en) begin
// driving b
// a should be b
// y and yfix should also be b
if (a!=b || y != b || y_fixed != b) begin
$display ( "Expected a %d y %b yfix %b" , a, y, y_fixed);
$stop;
end
end else begin
// not driving b
// a should be 1 (pullup)
// y and yfix shold be 1
if (a!=1 || y != 1 || y_fixed != 1) begin
$display( "Expected a,y,yfix == 1");
$stop;
end
end
if (in==3) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module ChildA(inout A, input B, input en, output Y, output Yfix);
// workaround
wire a_in = A;
ChildB childB(.A(A), .Y(Y));
assign A = en ? B : 1'bz;
ChildB childBfix(.A(a_in),.Y(Yfix));
endmodule
module ChildB(input A, output Y);
assign Y = A;
endmodule

View File

@ -7,8 +7,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug462");
compile (
);

View File

@ -7,15 +7,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, tri");
compile (
fails=>$Self->{v3},
expect=>
'%Error: t/t_tri_bad_pull2.v:19: Unsupported: Conflicting pull directions.
%Error: t/t_tri_bad_pull2.v:9: ... Location of conflicing pull.
'%Error: t/t_tri_pull2_bad.v:\d+: Unsupported: Conflicting pull directions.
%Error: t/t_tri_pull2_bad.v:\d+: ... Location of conflicing pull.
%Error: Exiting due to',
) if
);
ok(1);
1;

View File

@ -7,15 +7,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, tri");
compile (
fails=>$Self->{v3},
expect=>
'%Error: t/t_tri_bad_pull.v:9: Unsupported: Conflicting pull directions.
%Error: t/t_tri_bad_pull.v:10: ... Location of conflicing pull.
'%Error: t/t_tri_pull_bad.v:\d+: Unsupported: Conflicting pull directions.
%Error: t/t_tri_pull_bad.v:\d+: ... Location of conflicing pull.
%Error: Exiting due to',
) if
);
ok(1);
1;

View File

@ -17,8 +17,8 @@ module top (
// have 2 different 'chips' drive the PAD to act like a bi-directional bus
wire [`WIDTH-1:0] PAD;
io_ring io_ring1(.OE(OE1), .A(A1), .Y(Y1), .PAD(PAD));
io_ring io_ring2(.OE(OE2), .A(A2), .Y(Y2), .PAD(PAD));
io_ring io_ring1 (.OE(OE1), .A(A1), .Y(Y1), .PAD(PAD));
io_ring io_ring2 (.OE(OE2), .A(A2), .Y(Y2), .PAD(PAD));
pullup p1(PAD);
// pulldown p1(PAD);
@ -29,7 +29,7 @@ module top (
endmodule
module io_ring (input OE, input [`WIDTH-1:0] A, output [`WIDTH-1:0] Y, inout [`WIDTH-1:0] PAD);
io io[`WIDTH-1:0](.OE(OE), .I(A), .O(Y), .PAD(PAD));
io io[`WIDTH-1:0] (.OE(OE), .I(A), .O(Y), .PAD(PAD));
endmodule
module io (input OE, input I, output O, inout PAD);

View File

@ -1,8 +1,6 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
$Self->{vlt} and $Self->unsupported("Verilator unsupported, tri");
compile (
);

View File

@ -9,7 +9,9 @@ module t (clk);
wire A = state[0];
wire OE = state[1];
wire Z1, Z2, Z3, Z4, Z5, Z6, Z7, Z8, Z9;
wire [3:0] Z10;
wire Z11;
Test1 test1(/*AUTOINST*/
// Inouts
.Z1 (Z1),
@ -45,58 +47,86 @@ module t (clk);
.Z9 (Z9),
// Inputs
.OE (OE));
Test6 test6(/*AUTOINST*/
// Inouts
.Z10 (Z10[3:0]),
// Inputs
.OE (OE));
Test7 test7(/*AUTOINST*/
// Outputs
.Z11 (Z11),
// Inputs
.state (state[2:0]));
always @(posedge clk) begin
state <= state + 1;
`ifdef TEST_VERBOSE
$display(" Z1=%b 2=%b 3=%b 4=%b 5=%b 6=%b 7=%b 8=%b 9=%b",Z1,Z2,Z3,Z4,Z5,Z6,Z7,Z8,Z9);
$write("[%0t] state=%d Z1=%b 2=%b 3=%b 4=%b 5=%b 6=%b 7=%b 8=%b 9=%b 10=%b 11=%b\n",
$time, state, Z1,Z2,Z3,Z4,Z5,Z6,Z7,Z8,Z9,Z10,Z11);
`endif
if(state == 0) begin
if(Z1 !== 1'b1) $stop; // tests pullups
if(Z2 !== 1'b1) $stop;
if(Z3 !== 1'b1) $stop;
`ifndef VERILATOR
if(Z4 !== 1'b1) $stop;
`endif
if(Z5 !== 1'b1) $stop;
if(Z6 !== 1'b1) $stop;
if(Z7 !== 1'b0) $stop;
if(Z8 !== 1'b0) $stop;
if(Z9 !== 1'b1) $stop;
end
if(Z10 !== 4'b0001) $stop;
if(Z11 !== 1'b0) $stop;
end
else if(state == 1) begin
if(Z1 !== 1'b1) $stop; // tests pullup
if(Z2 !== 1'b1) $stop;
if(Z3 !== 1'b1) $stop;
`ifndef VERILATOR
if(Z4 !== 1'b1) $stop;
`endif
if(Z5 !== 1'b1) $stop;
if(Z6 !== 1'b1) $stop;
if(Z7 !== 1'b0) $stop;
if(Z8 !== 1'b0) $stop;
if(Z9 !== 1'b1) $stop;
if(Z10 !== 4'b0001) $stop;
if(Z11 !== 1'b1) $stop;
end
else if(state == 2) begin
if(Z1 !== 1'b0) $stop; // tests output driver low
if(Z2 !== 1'b0) $stop;
//if(Z3 !== 1'b1) $stop; // "X"
if(Z3 !== 1'b1 && Z3 !== 1'bx) $stop; // Conflicts
`ifndef VERILATOR
if(Z4 !== 1'b1) $stop;
`endif
if(Z5 !== 1'b1) $stop;
if(Z6 !== 1'b0) $stop;
if(Z7 !== 1'b1) $stop;
if(Z8 !== 1'b1) $stop;
if(Z9 !== 1'b0) $stop;
if(Z10 !== 4'b0010) $stop;
//if(Z11 !== 1'bx) $stop; // Doesn't matter
end
else if(state == 3) begin
if(Z1 !== 1'b1) $stop; // tests output driver high
if(Z2 !== 1'b1) $stop;
if(Z3 !== 1'b1) $stop;
`ifndef VERILATOR
if(Z4 !== 1'b1) $stop;
`endif
if(Z5 !== 1'b1) $stop;
if(Z6 !== 1'b0) $stop;
if(Z7 !== 1'b1) $stop;
if(Z8 !== 1'b1) $stop;
if(Z9 !== 1'b0) $stop;
end
if(Z10 !== 4'b0010) $stop;
if(Z11 !== 1'b1) $stop;
end
else if(state == 4) begin
$write("*-* All Finished *-*\n");
$finish;
@ -111,6 +141,7 @@ module t (clk);
pulldown(Z7);
pullup(Z8);
pulldown(Z9);
pulldown pd10[3:0] (Z10);
endmodule
@ -143,6 +174,26 @@ module Test5(input OE, inout Z6, inout Z7, inout Z8, inout Z9);
assign Z9 = (OE) ? 1'bz : 1'b1;
endmodule
// AND gate tristates
module Test6(input OE, inout [3:0] Z10);
wire [1:0] i;
Test6a a (.OE(OE), .Z({Z10[0],Z10[1]}));
Test6a b (.OE(~OE), .Z({Z10[2],Z10[0]}));
endmodule
module Test6a(input OE, inout [1:0] Z);
assign Z = (OE) ? 2'b01 : 2'bzz;
endmodule
module Test7(input [2:0] state, output reg Z11);
always @(*) begin
casez (state)
3'b000: Z11 = 1'b0;
3'b0?1: Z11 = 1'b1;
default: Z11 = 1'bx;
endcase
end
endmodule
// This is not implemented yet
//module Test3(input OE, input A, inout Z3);