1800 question: why the restriction for a dynamic slice of a vector is illegal?

From two tools I get an 1800 restriction for this code:
int k; if (v[k:0] > 3) …
Expected a constant as index: k." “testbench.sv” 10 16
Range must be bounded by constant expressions.

Question: What is the rationale behind this?
Seems like a useful operation.


module m;
  int k;
  bit clk;
  bit [15:0] v=16'HAA71;
  bit [15:0] temp, vect;
  initial forever #10 clk = !clk;
  always @(posedge clk) begin
    k = 4;    
    // ** Error: .\testr.sv(9): Range must be bounded by constant expressions.
    if (v[k:0] > 3) $display("i= %d, v=%b", k, v);  // line 9
    // workaround  
    for (int i=15; i>k;  i--)  temp[i]=0;
    for (int i=k;  i>=0; i--)  temp[i]=1;
    vect=v & temp;
    if (vect > 3) $display("i\k= %d, vect=%b", k, vect);  
  end
endmodule

In reply to ben@SystemVerilog.us:

SystemVerilog is statically typed meaning the compiler must determine all expression type at compile/elaboration. The width of a variable/operand is part of the type. An operand can be buried deep inside the context of an expression. The compiler has to determine the widths of all operands and propagate them through the entire expression through a complex set of rules. Doing this at runtime would have a significant impact on performance.

There is a simpler way of creating the mask in a single expression.

let range(val, width) = ( val & (2<<width)-1 )
if ( range(v,k) ) > 3)

In reply to dave_59:

Thanks Dave.
Does vhdl have the same restrictions?

Does VHDL have the same restrictions?

No. :) It is nice to see the conciseness of VHDL.

library IEEE, OSVVM ;
use ieee.std_logic_1164.all ; 
use ieee.numeric_std.all ; 
use ieee.numeric_std_unsigned.all; 

context osvvm.OsvvmContext ; 

entity TestDynamicRange is
end entity TestDynamicRange ;
architecture t1 of TestDynamicRange is 
  signal k : integer := 0 ; 
  signal v : std_logic_vector(15 downto 0) := X"AA71" ; 
begin

  k <= k + 1 after 10 ns; 

  AffirmIf(v(k downto 0) > 3, "k = " & to_string(k) & ", v=" & to_hstring(v(k downto 0)) ) ;
  
  process 
  begin
    SetAlertLogName("TestDynamicRange") ; 
    SetLogEnable(PASSED, TRUE) ; 
    wait until k = 15 for 1 ms ; 
    wait for 5 ns ;
    EndOfTestReports (ExternalErrors => (0, -4, 0)) ;  -- expecting 4 errors 
    std.env.stop ; 
  end process ; 
end architecture t1 ;

Output:

%% Alert ERROR k = 0, v=1 at 0 ns

%% Alert ERROR k = 1, v=1 at 10 ns

%% Alert ERROR k = 2, v=1 at 20 ns

%% Alert ERROR k = 3, v=1 at 30 ns

%% Log PASSED k = 4, v=11 at 40 ns

%% Log PASSED k = 5, v=31 at 50 ns

%% Log PASSED k = 6, v=71 at 60 ns

%% Log PASSED k = 7, v=71 at 70 ns

%% Log PASSED k = 8, v=071 at 80 ns

%% Log PASSED k = 9, v=271 at 90 ns

%% Log PASSED k = 10, v=271 at 100 ns

%% Log PASSED k = 11, v=A71 at 110 ns

%% Log PASSED k = 12, v=0A71 at 120 ns

%% Log PASSED k = 13, v=2A71 at 130 ns

%% Log PASSED k = 14, v=2A71 at 140 ns

%% Log PASSED k = 15, v=AA71 at 150 ns

%% DONE PASSED TestDynamicRange Passed: 12 Affirmations Checked: 16 at 155 ns