2025-10-31 12:49:30 -07:00
// DESCRIPTION: Test interface parameter dependency resolution
//
// Test that interface/modport parameters can be accessed when the
// interface/modport is an IO port of the module.
//
2026-01-26 20:24:34 -05:00
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2025 Paul Swirhun
2025-10-31 12:49:30 -07:00
// SPDX-License-Identifier: CC0-1.0
2025-12-20 21:46:43 -05:00
// verilog_format: off
2025-10-31 12:49:30 -07:00
`define stop $stop
2025-12-20 21:46:43 -05:00
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
// verilog_format: on
2025-10-31 12:49:30 -07:00
interface TEST_IF #(
parameter int FOO = 1 ,
parameter int BAR = FOO * 10
);
logic [ 31 : 0 ] data ;
modport mp ( input data );
endinterface
module submod_iface (
output logic [ 31 : 0 ] result ,
TEST_IF iface
);
assign result = iface . FOO + iface . BAR ;
endmodule
module submod_modport (
output logic [ 31 : 0 ] result ,
TEST_IF . mp mp
);
assign result = mp . FOO + mp . BAR ;
endmodule
2025-10-31 20:06:26 -07:00
module submod_assert2 #(
parameter int EXPECTED_FOO = 0 ,
parameter int EXPECTED_BAR = 0
) (
TEST_IF iface
);
initial begin
// Verify the dependent parameter BAR is correctly computed in the module
if ( iface . FOO != EXPECTED_FOO ) begin
$error ( "FOO mismatch in module: expected %0d, got %0d" , EXPECTED_FOO , iface . FOO );
end
if ( iface . BAR != EXPECTED_BAR ) begin
$error ( "BAR dependency failed in module: expected %0d, got %0d" , EXPECTED_BAR , iface . BAR );
end
end
endmodule
2025-10-31 12:49:30 -07:00
// Test module that asserts interface parameter values - catches dependency bugs
module submod_assert #(
parameter int EXPECTED_FOO = 0 ,
parameter int EXPECTED_BAR = 0
) (
TEST_IF iface
);
2025-10-31 20:06:26 -07:00
// Make a new interface with inherited parameters and pass it to a submodule
// with inherited expectations.
TEST_IF #(
. FOO ( iface . FOO ),
. BAR ( iface . BAR )
) iface2 ();
// Test mixed parameters: constant + interface port reference
TEST_IF #(
2025-12-20 21:46:43 -05:00
. FOO ( 7 ), // Constant parameter
2025-10-31 20:06:26 -07:00
. BAR ( iface . FOO ) // References interface port
) iface_mixed ();
// Test specifying only FOO parameter (BAR should use default calculation)
TEST_IF #(
. FOO ( iface . FOO ) // Only FOO specified, BAR = FOO * 10
) iface_foo_only ();
// Test specifying only BAR parameter (FOO should use default)
TEST_IF #(
. BAR ( iface . BAR ) // Only BAR specified, FOO = default (1)
) iface_bar_only ();
// Test no parameters specified (both should use defaults)
TEST_IF iface_defaults ();
submod_assert2 #(
. EXPECTED_FOO ( EXPECTED_FOO ),
. EXPECTED_BAR ( EXPECTED_BAR )
) u_submod_assert2 (
. iface ( iface2 )
);
// Test the mixed parameter interface
submod_assert2 #(
. EXPECTED_FOO ( 7 ),
. EXPECTED_BAR ( EXPECTED_FOO ) // BAR should get iface.FOO value
) u_mixed_assert (
. iface ( iface_mixed )
);
// Test FOO-only interface
submod_assert2 #(
. EXPECTED_FOO ( EXPECTED_FOO ),
. EXPECTED_BAR ( EXPECTED_FOO * 10 ) // BAR = FOO * 10
) u_foo_only_assert (
. iface ( iface_foo_only )
);
// Test BAR-only interface
submod_assert2 #(
2025-12-20 21:46:43 -05:00
. EXPECTED_FOO ( 1 ), // FOO = default
2025-10-31 20:06:26 -07:00
. EXPECTED_BAR ( EXPECTED_BAR ) // BAR = specified value
) u_bar_only_assert (
. iface ( iface_bar_only )
);
// Test defaults interface
submod_assert2 #(
. EXPECTED_FOO ( 1 ), // FOO = default
. EXPECTED_BAR ( 10 ) // BAR = FOO * 10 = 1 * 10
) u_defaults_assert (
. iface ( iface_defaults )
);
2025-10-31 12:49:30 -07:00
initial begin
// Verify the dependent parameter BAR is correctly computed in the module
if ( iface . FOO != EXPECTED_FOO ) begin
$error ( "FOO mismatch in module: expected %0d, got %0d" , EXPECTED_FOO , iface . FOO );
end
if ( iface . BAR != EXPECTED_BAR ) begin
$error ( "BAR dependency failed in module: expected %0d, got %0d" , EXPECTED_BAR , iface . BAR );
end
2025-10-31 20:06:26 -07:00
// Verify all interface instances have correct parameter values
if ( iface2 . FOO != EXPECTED_FOO ) begin
$error ( "iface2.FOO mismatch: expected %0d, got %0d" , EXPECTED_FOO , iface2 . FOO );
end
if ( iface2 . BAR != EXPECTED_BAR ) begin
$error ( "iface2.BAR mismatch: expected %0d, got %0d" , EXPECTED_BAR , iface2 . BAR );
end
if ( iface_mixed . FOO != 7 ) begin
$error ( "iface_mixed.FOO mismatch: expected 7, got %0d" , iface_mixed . FOO );
end
if ( iface_mixed . BAR != EXPECTED_FOO ) begin
$error ( "iface_mixed.BAR mismatch: expected %0d, got %0d" , EXPECTED_FOO , iface_mixed . BAR );
end
if ( iface_foo_only . FOO != EXPECTED_FOO ) begin
$error ( "iface_foo_only.FOO mismatch: expected %0d, got %0d" , EXPECTED_FOO ,
iface_foo_only . FOO );
end
if ( iface_foo_only . BAR != EXPECTED_FOO * 10 ) begin
$error ( "iface_foo_only.BAR mismatch: expected %0d, got %0d" , EXPECTED_FOO * 10 ,
iface_foo_only . BAR );
end
if ( iface_bar_only . FOO != 1 ) begin
$error ( "iface_bar_only.FOO mismatch: expected 1, got %0d" , iface_bar_only . FOO );
end
if ( iface_bar_only . BAR != EXPECTED_BAR ) begin
$error ( "iface_bar_only.BAR mismatch: expected %0d, got %0d" , EXPECTED_BAR ,
iface_bar_only . BAR );
end
if ( iface_defaults . FOO != 1 ) begin
$error ( "iface_defaults.FOO mismatch: expected 1, got %0d" , iface_defaults . FOO );
end
if ( iface_defaults . BAR != 10 ) begin
$error ( "iface_defaults.BAR mismatch: expected 10, got %0d" , iface_defaults . BAR );
end
2025-10-31 12:49:30 -07:00
end
endmodule
// Test parameterized interface chain: module parameter -> interface parameter -> submodule
module param_chain #(
parameter int TOP_PARAM = 3
) (
output logic [ 31 : 0 ] result
);
// Interface gets parameter from module parameter
TEST_IF #(. FOO ( TOP_PARAM )) chain_iface ();
// Submodule uses interface (FOO=3, BAR should be 30)
submod_iface chain_sub (
. result ( result ),
2025-12-20 21:46:43 -05:00
. iface ( chain_iface )
2025-10-31 12:49:30 -07:00
);
// Assert the chain works correctly
submod_assert #(
. EXPECTED_FOO ( TOP_PARAM ),
. EXPECTED_BAR ( TOP_PARAM * 10 )
) chain_assert (
. iface ( chain_iface )
);
endmodule
module t ;
// Test case 1: FOO specified, BAR should be FOO*10
TEST_IF #(. FOO ( 5 )) tif_1 ();
// Test case 2: Both FOO and BAR specified explicitly
TEST_IF #(
. FOO ( 6 ),
. BAR ( 66 )
) tif_2 ();
// Test case 3: Only BAR specified, FOO should be default
TEST_IF #(. BAR ( 77 )) tif_3 ();
// Test case 4: Default parameters
TEST_IF tif_4 ();
logic [ 8 : 0 ][ 31 : 0 ] result ;
// Test interface as port parameter
submod_iface u0 (
. result ( result [ 0 ]),
2025-12-20 21:46:43 -05:00
. iface ( tif_1 )
2025-10-31 12:49:30 -07:00
);
submod_iface u1 (
. result ( result [ 1 ]),
2025-12-20 21:46:43 -05:00
. iface ( tif_2 )
2025-10-31 12:49:30 -07:00
);
submod_iface u2 (
. result ( result [ 2 ]),
2025-12-20 21:46:43 -05:00
. iface ( tif_3 )
2025-10-31 12:49:30 -07:00
);
submod_iface u3 (
. result ( result [ 3 ]),
2025-12-20 21:46:43 -05:00
. iface ( tif_4 )
2025-10-31 12:49:30 -07:00
);
// Test modport as port parameter
submod_modport u4 (
. result ( result [ 4 ]),
. mp ( tif_1 )
);
submod_modport u5 (
. result ( result [ 5 ]),
. mp ( tif_2 )
);
submod_modport u6 (
. result ( result [ 6 ]),
. mp ( tif_3 )
);
submod_modport u7 (
. result ( result [ 7 ]),
. mp ( tif_4 )
);
// Test that interface parameter dependencies are correctly resolved in modules
submod_assert #(
. EXPECTED_FOO ( 5 ),
. EXPECTED_BAR ( 50 )
) assert1 (
. iface ( tif_1 )
);
// Test parameterized interface chain: module param -> interface param -> submodule
param_chain #(. TOP_PARAM ( 4 )) chain_test (. result ( result [ 8 ]));
// Allow hierarchichal references to locally declared interfaces only when HIERPARAM is waived
/* verilator lint_off HIERPARAM */
TEST_IF #(. FOO ( 3 )) test_if_local ();
logic [ 31 : 0 ] foo_local_1 = 32 '( test_if_local . FOO );
logic [ 31 : 0 ] bar_local_1 = 32 '( test_if_local . BAR );
localparam FOO_LOCAL = test_if_local . FOO ;
localparam BAR_LOCAL = test_if_local . BAR ;
logic [ 31 : 0 ] foo_local_2 = 32 '( FOO_LOCAL );
logic [ 31 : 0 ] bar_local_2 = 32 '( BAR_LOCAL );
/* verilator lint_on HIERPARAM */
initial begin
// Verify modules can access interface parameters correctly
`checkd ( result [ 0 ], 55 ); // 5 + 50
`checkd ( result [ 1 ], 72 ); // 6 + 66
`checkd ( result [ 2 ], 78 ); // 1 + 77 (FOO default + BAR explicit)
`checkd ( result [ 3 ], 11 ); // 1 + 10 (both defaults, BAR = FOO*10)
// Verify modport access gives same results
`checkd ( result [ 4 ], 55 ); // 5 + 50
`checkd ( result [ 5 ], 72 ); // 6 + 66
`checkd ( result [ 6 ], 78 ); // 1 + 77
`checkd ( result [ 7 ], 11 ); // 1 + 10
// Verify parameterized chain works
`checkd ( result [ 8 ], 44 ); // 4 + 40 (TOP_PARAM=4, so FOO=4, BAR=40)
`checkd ( foo_local_1 , 3 );
`checkd ( bar_local_1 , 30 );
`checkd ( foo_local_2 , 3 );
`checkd ( bar_local_2 , 30 );
$write ( "*-* All Finished *-* \n " );
$finish ;
end
endmodule