nickg / nvc

VHDL compiler and simulator
https://www.nickg.me.uk/nvc/
GNU General Public License v3.0
636 stars 80 forks source link

crash during Elaboration when using 'last_value attribute #1043

Closed jobtijhuis closed 1 month ago

jobtijhuis commented 1 month ago

I ran into an error when trying to run a function that is checking a couple of signal properties. NVC seems to not like the use of the last_value attribute in combination with a record. I did manage to run this code on another simulator.

Version nvc 1.14-devel (1.13.0.r36.gc81905e1) (Using LLVM 11.0.1)

Error report

Name       AXI_STREAM.AXI_STREAM_PKG.ISCONTINUOUS(s38AXI_STREAM.AXI_STREAM_PKG.AXI_STREAM_T)B
Kind       function
Context    AXI_STREAM.AXI_STREAM_PKG
Blocks     1
Registers  3
Types      10
  AXI_STREAM.AXI_STREAM_PKG.AXI_STREAM_T$ {$<0..8>, $<0..8>, [*] : $<0..8>, $<0..8>, [*] : $<0..8>, [*] : $<0..8>, [*] : $<0..8>, [*] : $<0..8>, [*] : $<0..8>}
  AXI_STREAM.AXI_STREAM_PKG.AXI_STREAM_T {0..8, 0..8, [*] : 0..8, 0..8, [*] : 0..8, [*] : 0..8, [*] : 0..8, [*] : 0..8, [*] : 0..8}
Variables  3
  ID_AND_DEST_STABLE                    // 0..1
  NO_INT_NULL_BYTES                     // 0..1
  CONTINUOUS_NULL_BYTES                 // 0..1
Result     0..1
Parameters 2
  r0    context                         // P<AXI_STREAM.AXI_STREAM_PKG>
  r1    STREAM                          // @<AXI_STREAM.AXI_STREAM_PKG.AXI_STREAM_T${}> => AXI_STREAM.AXI_STREAM_PKG.AXI_STREAM_T{}
Begin
   0: r2 := const 0                     // 0..1 => 0
      ID_AND_DEST_STABLE := store r2
      NO_INT_NULL_BYTES := store r2
      CONTINUOUS_NULL_BYTES := store r2
      invalid := last value r1   <----

** Fatal: argument r1 to resolved is not a signal
[0x4d0be6] ../src/diag.c:1048 diag_femit
[0x4104f0] ../src/util.c:585 fatal_trace
[0x4bd1ef] ../src/vcode.c:5451 emit_signal_data_op
[0x48c058] ../src/lower.c:1334 lower_last_value
[0x48c058] ../src/lower.c:4865 lower_attr_ref
[0x48c058] ../src/lower.c:5125 lower_expr
[0x48abab] ../src/lower.c:4257 lower_record_ref
[0x48abab] ../src/lower.c:5115 lower_expr
[0x48a916] ../src/lower.c:12851 lower_rvalue
[0x49f143] ../src/lower.c:1238 lower_subprogram_arg
[0x49e529] ../src/lower.c:2176 lower_builtin
[0x48ab83] ../src/lower.c:5099 lower_expr
[0x48a916] ../src/lower.c:12851 lower_rvalue
[0x4a2794] ../src/lower.c:6270 lower_if
[0x4a2794] ../src/lower.c:7308 lower_stmt
[0x490656] ../src/lower.c:6253 lower_sequence
[0x490656] ../src/lower.c:11193 lower_func_body
[0x48fe95] ../src/lower.c:13366 unit_registry_get
[0x48d7e4] ../src/lower.c:2403 lower_context_for_call
[0x49e02e] ../src/lower.c:2470 lower_fcall
[0x48ab83] ../src/lower.c:5099 lower_expr
[0x48a916] ../src/lower.c:12851 lower_rvalue
[0x49f143] ../src/lower.c:1238 lower_subprogram_arg
[0x49e05c] ../src/lower.c:2473 lower_fcall
[0x48ab83] ../src/lower.c:5099 lower_expr
[0x48a916] ../src/lower.c:12851 lower_rvalue
[0x49fbe6] ../src/lower.c:2054 lower_flatten_concat
[0x49f37d] ../src/lower.c:2065 lower_concat
[0x48ab83] ../src/lower.c:5099 lower_expr
[0x48a916] ../src/lower.c:12851 lower_rvalue
[0x4a3d0f] ../src/lower.c:5348 lower_report
[0x4a3d0f] ../src/lower.c:7290 lower_stmt
[0x48a036] ../src/lower.c:6253 lower_sequence
[0x48a036] ../src/lower.c:11515 lower_process
[0x47086b] ../src/elab.c:2018 elab_stmts
[0x46e070] ../src/elab.c:1541 elab_architecture
[0x46d8e4] ../src/elab.c:2306 elab
[0x40c9ec] ../src/nvc.c:464 elaborate
[0x40c9ec] ../src/nvc.c:1922 process_command
[0x40b1d5] ../src/nvc.c:2060 main

How to reproduce

type axi_stream_t is record
  t_valid : std_logic;
  t_ready : std_logic;
  t_data  : std_logic_vector;
  t_last  : std_logic;

  t_strb  : std_logic_vector;
  t_keep  : std_logic_vector;

  t_id    : std_logic_vector;
  t_dest  : std_logic_vector;
  t_user  : std_logic_vector;
end record;

function IsContinuous (signal stream : in axi_stream_t) return boolean is
  variable id_and_dest_stable    : boolean;
  variable no_int_null_bytes     : boolean;
  variable continuous_null_bytes : boolean;
begin

  id_and_dest_stable    := (stream.t_id = stream'last_value.t_id and
                            stream.t_dest = stream'last_value.t_dest) when stream'last_value.t_last = '0'
                           else TRUE;
  no_int_null_bytes     := (stream.t_keep = (stream.t_keep'range => '1')) when stream.t_last = '0'
                           else TRUE;
  continuous_null_bytes := TRUE;

  return id_and_dest_stable and no_int_null_bytes and continuous_null_bytes;

end function;

-- Running function

test_stream <= (
  t_valid => '1',
  t_ready => '1',
  t_last  => '0',
  t_data => x"00",
  t_strb => (0 => '1'),
  t_keep => (0 => '1'),
  t_id   => x"0",
  t_dest => x"0",
  t_user => (0 => '0')
);
wait for 1 ns;
test_stream <= (
  t_valid => '1',
  t_ready => '1',
  t_last  => '0',
  t_data => x"01",
  t_strb => (0 => '1'),
  t_keep => (0 => '1'),
  t_id   => x"0",
  t_dest => x"0",
  t_user => (0 => '0')
);

report "test: "&to_string(IsContinuous(test_stream));