Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with modpaths when BUFT is in different scope #985

Closed
mole99 opened this issue Aug 7, 2023 · 2 comments · Fixed by #989
Closed

Issue with modpaths when BUFT is in different scope #985

mole99 opened this issue Aug 7, 2023 · 2 comments · Fixed by #989

Comments

@mole99
Copy link
Contributor

mole99 commented Aug 7, 2023

This is a very specify issue that only occurs when manually editing the VVP source file, but an issue nonetheless.

For my work on SDF interconnect, I need to add input and output buffers to modules. Below is the VVP code for a simple design, a buffer buffer0 instantiated inside the toplevel module top. Instead of a and b being directly connected to the BUFZ of buffer0, both signals go through a BUFT.

#! /usr/local/bin/vvp
:ivl_version "13.0 (devel)" "(s20221226-244-g3e96a7e1e)";
:ivl_delay_selection "TYPICAL";
:vpi_time_precision - 12;
:vpi_module "/usr/local/lib/ivl/system.vpi";
:vpi_module "/usr/local/lib/ivl/vhdl_sys.vpi";
:vpi_module "/usr/local/lib/ivl/vhdl_textio.vpi";
:vpi_module "/usr/local/lib/ivl/v2005_math.vpi";
:vpi_module "/usr/local/lib/ivl/va_math.vpi";
S_0x5650ecc5e540 .scope module, "top" "top" 2 15;
 .timescale -9 -12;
v0x5650ecc95a40_0 .var "a", 0 0;
v0x5650ecc95b00_0 .net "b", 0 0, L_0x5650ecc95d40;  1 drivers
S_0x5650ecc85830 .scope module, "buffer0" "buffer" 2 26, 2 3 0, S_0x5650ecc5e540;
 .timescale -9 -12;
    .port_info 0 /INPUT 1 "in";
    .port_info 1 /OUTPUT 1 "out";
L_0x5650ecc95bc0 .functor BUFZ 1, L_0x5650ecc95c80, C4<0>, C4<0>, C4<0>;
L_0x5650ecc95c80 .functor BUFT 1, v0x5650ecc95a40_0, C4<0>, C4<0>, C4<0>;
L_0x5650ecc95d40 .functor BUFT 1, V_0x5650ecc95920_0/m, C4<0>, C4<0>, C4<0>;
v0x5650ecc85a60_0 .net "in", 0 0, L_0x5650ecc95c80;  1 drivers
v0x5650ecc95920_0 .net "out", 0 0, V_0x5650ecc95920_0/m;  1 drivers
  .scope S_0x5650ecc85830;
V_0x5650ecc95920_0/m .modpath 1 L_0x5650ecc95bc0 v0x5650ecc95920_0,
   L_0x5650ecc95c80 (1000,1000,1000, 1000,1000,1000, 1000,1000,1000, 1000,1000,1000) v0x5650ecc85a60_0;
    .scope S_0x5650ecc5e540;
T_0 ;
    %vpi_call 2 19 "$dumpfile", "top.vcd" {0 0 0};
    %vpi_call 2 20 "$dumpvars", 32'sb00000000000000000000000000000000, S_0x5650ecc5e540 {0 0 0};
    %end;
    .thread T_0;
    .scope S_0x5650ecc5e540;
T_1 ;
    %delay 5000, 0;
    %pushi/vec4 0, 0, 1;
    %assign/vec4 v0x5650ecc95a40_0, 0;
    %delay 10000, 0;
    %pushi/vec4 1, 0, 1;
    %assign/vec4 v0x5650ecc95a40_0, 0;
    %delay 10000, 0;
    %vpi_call 2 37 "$finish" {0 0 0};
    %end;
    .thread T_1;
# The file index is used to find the file name in the following table.
:file_names 3;
    "N/A";
    "<interactive>";
    "top.v";

The expected result is that b is delayed by one ns. However, if you run this VVP source file with the latest master, the delay inside the specify block is not applied.

No delay

If the "BUFTs" are manually moved to the outer scope top, the simulation behaves correctly.

Correct delay

For example, insert the BUFTs directly after a and b.

v0x5650ecc95a40_0 .var "a", 0 0;
v0x5650ecc95b00_0 .net "b", 0 0, L_0x5650ecc95d40;  1 drivers
L_0x5650ecc95c80 .functor BUFT 1, v0x5650ecc95a40_0, C4<0>, C4<0>, C4<0>;
L_0x5650ecc95d40 .functor BUFT 1, V_0x5650ecc95920_0/m, C4<0>, C4<0>, C4<0>;

This is unexpected because the netlist stays the same, only the scope of the BUFTs has changed.

I am going to investigate this problem, because for SDF interconnect work I need input and output buffers in the same scope as the .port_info directives, so I can add a reference to the associated buffer.

But if someone already has a clue what it could be, please tell me :)

@mole99
Copy link
Contributor Author

mole99 commented Aug 8, 2023

It seems the issue depends only on the scope of the input buffer. It is enough to move the first of the two BUFTs into the outer scope.

@mole99
Copy link
Contributor Author

mole99 commented Aug 9, 2023

I am pretty sure that I have found the root cause for this issue.

The general concept of modpaths in Icarus Verilog is based on the vvp_fun_modpath_src and vvp_fun_modpath functors. The netlist for a simple buffer with a modpath could look like this:

                                                   output
           |--- vvp_fun_bufz --- vvp_fun_modpath ----------
   input   |
-----------|
           |
           |--- vvp_fun_modpath_src

The vvp_fun_bufz provides the actual functionality for the buffer, vvp_fun_modpath_src and vvp_fun_modpath are there to provide the correct delay from input to output.

What should happen (a bit simplified):

  1. The input value changes
  2. This triggers vvp_fun_modpath_src, it stores the current simulation time as wake_time_
  3. The input value propagates through the buffer and to vvp_fun_modpath
  4. vvp_fun_modpath looks up which of its vvp_fun_modpath_srcs are active and calculatse the wakeup time
    using the wake_time_ of the vvp_fun_modpath_src plus its delay. If this wakeup time is greater than the current simulation time, subtract the current simulation time from it. If no delays are between input and vvp_fun_modpath then this value should be the delay value of the selected vvp_fun_modpath_src.
  5. Finally, schedule the output value change with the calculated delay.

It is crucial that vvp_fun_modpath_src is evaluated before vvp_fun_modpath. But it seems that this was not the case in this instance.

In the working variant with the input buffer in the outer scope, the functors are connected to input in the following order:

  1. vvp_fun_modpath_src
  2. vvp_fun_bufz

If the buffer is moved into the inner scope, for some reason the order in which these functors are connected to the input is changed:

  1. vvp_fun_bufz
  2. vvp_fun_modpath_src

Since this seems to be the order in which the netlist is evaluated and vvp_fun_modpath is connected to vvp_fun_bufz, this causes vvp_fun_modpath to be evaluated before its vvp_fun_modpath_src. Thus wake_time_ of vvp_fun_modpath_src is still the previous value and the sum of wake_time_ plus the delay of vvp_fun_modpath_src is less than the current simulation time. Therefore, the delay is set to zero, and it appears that the specify delays are ignored during simulation.

The obvious solution would be to ensure that vvp_fun_modpath_srcs are always connected before any other functors. Or an alternative would be to make sure that vvp_fun_modpath_srcs are evaluated before the associated vvp_fun_modpath by design, though I do not yet know what that would look like. Maybe a prioritization in the scheduler, but that would result in a runtime loss.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant