247 lines
5.5 KiB
Systemverilog
247 lines
5.5 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
|
|
|
|
// verilog_format: off
|
|
`define stop $stop
|
|
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
|
// verilog_format: on
|
|
|
|
// verilator lint_off MULTIDRIVEN
|
|
|
|
// ---------------- Compare semantics (=== / !==) ----------------
|
|
interface ifc_cmp;
|
|
logic we;
|
|
tri [7:0] d;
|
|
endinterface
|
|
|
|
module drv_cmp (
|
|
ifc_cmp io_ifc
|
|
);
|
|
assign io_ifc.d = io_ifc.we ? 8'h5A : 8'hzz;
|
|
endmodule
|
|
|
|
module chk_cmp (
|
|
ifc_cmp io_ifc,
|
|
output logic is_z,
|
|
output logic is_5a,
|
|
output logic not_z,
|
|
output logic not_5a
|
|
);
|
|
assign is_z = (io_ifc.d === 8'hzz);
|
|
assign is_5a = (io_ifc.d === 8'h5A);
|
|
assign not_z = (io_ifc.d !== 8'hzz);
|
|
assign not_5a = (io_ifc.d !== 8'h5A);
|
|
endmodule
|
|
|
|
interface ifc_cmp_mp;
|
|
logic we;
|
|
tri [7:0] d;
|
|
modport drv_mp(input we, inout d);
|
|
modport chk_mp(input we, inout d);
|
|
endinterface
|
|
|
|
module drv_cmp_mp (
|
|
ifc_cmp_mp.drv_mp io_ifc
|
|
);
|
|
assign io_ifc.d = io_ifc.we ? 8'h5A : 8'hzz;
|
|
endmodule
|
|
|
|
module chk_cmp_mp (
|
|
ifc_cmp_mp.chk_mp io_ifc,
|
|
output logic is_z,
|
|
output logic is_5a,
|
|
output logic not_z,
|
|
output logic not_5a
|
|
);
|
|
assign is_z = (io_ifc.d === 8'hzz);
|
|
assign is_5a = (io_ifc.d === 8'h5A);
|
|
assign not_z = (io_ifc.d !== 8'hzz);
|
|
assign not_5a = (io_ifc.d !== 8'h5A);
|
|
endmodule
|
|
|
|
module passthru_cmp (
|
|
ifc_cmp io_ifc
|
|
);
|
|
drv_cmp u_drv (.*);
|
|
endmodule
|
|
|
|
// ---------------- Mixed local + external contributors ----------------
|
|
interface ifc_mix;
|
|
logic we_local;
|
|
logic we_ext;
|
|
tri [7:0] d;
|
|
assign d = we_local ? 8'hA5 : 8'hzz;
|
|
endinterface
|
|
|
|
module drv_mix (
|
|
ifc_mix io_ifc
|
|
);
|
|
assign io_ifc.d = io_ifc.we_ext ? 8'h3C : 8'hzz;
|
|
endmodule
|
|
|
|
interface ifc_mix_mp;
|
|
logic we_local;
|
|
logic we_ext;
|
|
tri [7:0] d;
|
|
modport drv_mp(input we_ext, inout d);
|
|
assign d = we_local ? 8'hA5 : 8'hzz;
|
|
endinterface
|
|
|
|
module drv_mix_mp (
|
|
ifc_mix_mp.drv_mp io_ifc
|
|
);
|
|
assign io_ifc.d = io_ifc.we_ext ? 8'h3C : 8'hzz;
|
|
endmodule
|
|
|
|
module t;
|
|
// ---- Compare semantics: basic ----
|
|
ifc_cmp i_cmp ();
|
|
logic is_z, is_5a, not_z, not_5a;
|
|
drv_cmp u_drv_cmp (.io_ifc(i_cmp));
|
|
chk_cmp u_chk_cmp (
|
|
.io_ifc(i_cmp),
|
|
.is_z(is_z),
|
|
.is_5a(is_5a),
|
|
.not_z(not_z),
|
|
.not_5a(not_5a)
|
|
);
|
|
|
|
// ---- Compare semantics: modport ----
|
|
ifc_cmp_mp i_cmp_mp ();
|
|
logic mp_is_z, mp_is_5a, mp_not_z, mp_not_5a;
|
|
drv_cmp_mp u_drv_cmp_mp (.io_ifc(i_cmp_mp));
|
|
chk_cmp_mp u_chk_cmp_mp (
|
|
.io_ifc(i_cmp_mp),
|
|
.is_z(mp_is_z),
|
|
.is_5a(mp_is_5a),
|
|
.not_z(mp_not_z),
|
|
.not_5a(mp_not_5a)
|
|
);
|
|
|
|
// ---- Compare semantics: deep hierarchy ----
|
|
ifc_cmp i_cmp_deep ();
|
|
logic deep_is_z, deep_is_5a, deep_not_z, deep_not_5a;
|
|
passthru_cmp u_cmp_deep (.io_ifc(i_cmp_deep));
|
|
chk_cmp u_chk_cmp_deep (
|
|
.io_ifc(i_cmp_deep),
|
|
.is_z(deep_is_z),
|
|
.is_5a(deep_is_5a),
|
|
.not_z(deep_not_z),
|
|
.not_5a(deep_not_5a)
|
|
);
|
|
|
|
// ---- Mixed contributors ----
|
|
ifc_mix i_mix ();
|
|
drv_mix u_mix (.io_ifc(i_mix));
|
|
|
|
ifc_mix_mp i_mix_mp ();
|
|
drv_mix_mp u_mix_mp (.io_ifc(i_mix_mp));
|
|
|
|
initial begin
|
|
// ---- Compare semantics ----
|
|
i_cmp.we = 1'b0;
|
|
i_cmp_mp.we = 1'b0;
|
|
i_cmp_deep.we = 1'b0;
|
|
#1;
|
|
|
|
`checkh(is_z, 1'b1);
|
|
`checkh(is_5a, 1'b0);
|
|
`checkh(not_z, 1'b0);
|
|
`checkh(not_5a, 1'b1);
|
|
`checkh(mp_is_z, 1'b1);
|
|
`checkh(mp_is_5a, 1'b0);
|
|
`checkh(mp_not_z, 1'b0);
|
|
`checkh(mp_not_5a, 1'b1);
|
|
`checkh(deep_is_z, 1'b1);
|
|
`checkh(deep_is_5a, 1'b0);
|
|
|
|
#1;
|
|
i_cmp.we = 1'b1;
|
|
i_cmp_mp.we = 1'b1;
|
|
i_cmp_deep.we = 1'b1;
|
|
#1;
|
|
|
|
`checkh(is_z, 1'b0);
|
|
`checkh(is_5a, 1'b1);
|
|
`checkh(not_z, 1'b1);
|
|
`checkh(not_5a, 1'b0);
|
|
`checkh(mp_is_z, 1'b0);
|
|
`checkh(mp_is_5a, 1'b1);
|
|
`checkh(mp_not_z, 1'b1);
|
|
`checkh(mp_not_5a, 1'b0);
|
|
`checkh(deep_is_z, 1'b0);
|
|
`checkh(deep_is_5a, 1'b1);
|
|
|
|
#1;
|
|
i_cmp.we = 1'b0;
|
|
i_cmp_mp.we = 1'b0;
|
|
i_cmp_deep.we = 1'b0;
|
|
#1;
|
|
|
|
`checkh(is_z, 1'b1);
|
|
`checkh(is_5a, 1'b0);
|
|
`checkh(not_z, 1'b0);
|
|
`checkh(not_5a, 1'b1);
|
|
`checkh(mp_is_z, 1'b1);
|
|
`checkh(mp_is_5a, 1'b0);
|
|
`checkh(mp_not_z, 1'b0);
|
|
`checkh(mp_not_5a, 1'b1);
|
|
`checkh(deep_is_z, 1'b1);
|
|
`checkh(deep_is_5a, 1'b0);
|
|
|
|
// ---- Mixed contributors ----
|
|
i_mix.we_local = 1'b0;
|
|
i_mix.we_ext = 1'b0;
|
|
i_mix_mp.we_local = 1'b0;
|
|
i_mix_mp.we_ext = 1'b0;
|
|
#1;
|
|
|
|
`checkh(i_mix.d, 8'hzz);
|
|
`checkh(i_mix_mp.d, 8'hzz);
|
|
|
|
#1;
|
|
i_mix.we_local = 1'b1;
|
|
i_mix.we_ext = 1'b0;
|
|
i_mix_mp.we_local = 1'b1;
|
|
i_mix_mp.we_ext = 1'b0;
|
|
#1;
|
|
`checkh(i_mix.d, 8'hA5);
|
|
`checkh(i_mix_mp.d, 8'hA5);
|
|
|
|
#1;
|
|
i_mix.we_local = 1'b0;
|
|
i_mix.we_ext = 1'b1;
|
|
i_mix_mp.we_local = 1'b0;
|
|
i_mix_mp.we_ext = 1'b1;
|
|
#1;
|
|
`checkh(i_mix.d, 8'h3C);
|
|
`checkh(i_mix_mp.d, 8'h3C);
|
|
|
|
#1;
|
|
i_mix.we_local = 1'b1;
|
|
i_mix.we_ext = 1'b1;
|
|
i_mix_mp.we_local = 1'b1;
|
|
i_mix_mp.we_ext = 1'b1;
|
|
#1;
|
|
`checkh(i_mix.d, 8'hBD);
|
|
`checkh(i_mix_mp.d, 8'hBD);
|
|
|
|
#1;
|
|
i_mix.we_local = 1'b0;
|
|
i_mix.we_ext = 1'b0;
|
|
i_mix_mp.we_local = 1'b0;
|
|
i_mix_mp.we_ext = 1'b0;
|
|
#1;
|
|
`checkh(i_mix.d, 8'hzz);
|
|
`checkh(i_mix_mp.d, 8'hzz);
|
|
|
|
$write("*-* All Finished *-*\n");
|
|
$finish;
|
|
end
|
|
endmodule
|