How to get logic signal width, and use as a parameter?

In my top testbench module, I am binding a checker module into a VHDL DUT. The 2nd parameter, PC_WIDTH, must be the width of the signal “pc”.
I could just punch it in, but I’d like to automate it, because pc width may change in future.

This was my attempt…

bind inst_LNP_top LNP_assertions #(.MAIN_STATE(13), .PC_WIDTH($bits(inst_LNP.inst_9408.pc))) LNP_checker (
    clock, POReset,
    inst_LNP.inst_9408.pc, inst_LNP.inst_alu.a, inst_LNP.inst_alu.b, inst_LNP.inst_alu.c, inst_LNP.inst_alu.d,
    inst_LNP.inst_alu.e, inst_LNP.inst_alu.f, inst_LNP.inst_alu.data_out
);

resulting in…
“Parameter override PC_WIDTH must be compile time constant in context of bind to instance.”

for ref:

module LNP_assertions #(parameter MAIN_STATE, parameter PC_WIDTH ) (
  input logic clk, reset, logic [PC_WIDTH-1:0] pc,
  alu_a, alu_b, alu_c, alu_d, alu_e, alu_f, alu_dout
);

thoughts?

You are not allowed to override parameters with hierarchical references to other parameters. The flow of parameter resolution must remain in a top-down fashion.

You might try changing the bind_target_instance to be in the scope where pc is declared.

bind inst_LNP_top.inst_LNP.inst_9408 LNP_assertions #(.MAIN_STATE(13), .PC_WIDTH($bits(pc))) LNP_checker (
    inst_LNP_top.clock, inst_LNP_top.POReset,
    pc, inst_LNP_top.inst_LNP.inst_alu.a, inst_LNP_top.inst_LNP.inst_alu.b, inst_LNP_top.inst_LNP.inst_alu.c, inst_LNP_top.inst_LNP.inst_alu.d,
    inst_LNP_top.inst_LNP.inst_alu.e, inst_LNP_top.inst_LNP.inst_alu.f, inst_LNP_top.inst_LNP.inst_alu.data_out
);

In reply to dave_59:

Thanks Dave, understood.

What I ended up doing was simply eliminating the parameter input, and making the pc logic signal (in the assertions module) a 32bit unsigned. No reason for it to exactly match the RTL signal.

In reply to bmorris:
Yes. Do use parameters whenever possible (instead of `define or const) and avoid parameterization whenever possible.