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

wait until in for loop waits only once #1134

Open
m-kru opened this issue Jan 15, 2025 · 10 comments
Open

wait until in for loop waits only once #1134

m-kru opened this issue Jan 15, 2025 · 10 comments

Comments

@m-kru
Copy link

m-kru commented Jan 15, 2025

nvc 1.16-devel (1.15.0.r4.g230dffd9) (Using LLVM 14.0.0)

I am not 100 % sure it is a bug, but it smells like a bug.
https://github.com/m-kru/vhdl-amba5/blob/c140cce127754a53599bdf802ed55bac7a5e5eab/apb/tb/serial-bridge/tb-read.vhd#L106

I would expect this loop to wait for 4 rising edges with valid handshake conditions.
What is observe is that it iterates 4 items after the
wait until rising_edge(clk) and byte_out_ready = '1' and sb.byte_out_valid = '1';
becomes true for the first time.

If I manually unroll the loop to:

      -- Read data
      byte_out_ready <= '1';
      wait until rising_edge(clk) and byte_out_ready = '1' and sb.byte_out_valid = '1';
      rdata(31 downto 24) <= sb.byte_out;
      byte_out_ready <= '0';
      wait for delay * CLK_PERIOD;

      byte_out_ready <= '1';
      wait until rising_edge(clk) and byte_out_ready = '1' and sb.byte_out_valid = '1';
      rdata(23 downto 16) <= sb.byte_out;
      byte_out_ready <= '0';
      wait for delay * CLK_PERIOD;

      byte_out_ready <= '1';
      wait until rising_edge(clk) and byte_out_ready = '1' and sb.byte_out_valid = '1';
      rdata(15 downto 8) <= sb.byte_out;
      byte_out_ready <= '0';
      wait for delay * CLK_PERIOD;

      byte_out_ready <= '1';
      wait until rising_edge(clk) and byte_out_ready = '1' and sb.byte_out_valid = '1';
      rdata(7 downto 0) <= sb.byte_out;
      byte_out_ready <= '0';
      wait for delay * CLK_PERIOD;

      assert rdata = want
        report "invalid rdata, got " & rdata'image & ", want " & want'image
        severity failure;

it works as expected. I catch 4 bytes on rising edges with valid handshake condition.

If you clone the repo you can run simulation by executing the following commands:

nvc  --std=2019 -L. --work=apb  -a ./apb.vhd
nvc  --std=2019 -L. --work=apb  -a ./checker.vhd
nvc  --std=2019 -L. --work=apb  -a ./mock-completer.vhd
nvc  --std=2019 -L. --work=apb  -a ./serial-bridge.vhd
nvc  --std=2019 -L. --work=work -a ./tb/serial-bridge/tb-read.vhd
nvc  --std=2019 -L. -e tb_read
nvc --messages=compact --std=2019 -L. -r tb_read --wave --exit-severity=error --dump-arrays
@nickg
Copy link
Owner

nickg commented Jan 15, 2025

for i in 3 to 0 loop

This executes zero times (3 to 0 is a null range, you probably want 3 downto 0).

@m-kru
Copy link
Author

m-kru commented Jan 15, 2025

Damn, you're right. Shouldn't the compiler at least warn about such silly mistakes? They are easy to make when you are already tired after hours of work.

@amb5l
Copy link
Contributor

amb5l commented Jan 15, 2025

I use null ranges in a few situations. I do not like the way they are specified in VHDL, and I can well understand your frustration, but I would not want existing working code to start causing compilation warnings.

@nickg
Copy link
Owner

nickg commented Jan 15, 2025

I use null ranges in a few situations. I do not like the way they are specified in VHDL, and I can well understand your frustration, but I would not want existing working code to start causing compilation warnings.

How about in for loops specifically? Modelsim does issue a warning in this case:

** Warning: ../test/bounds/issue1134.vhd(9): (vcom-1246) Range 3 to 0 is null.
** Warning: ../test/bounds/issue1134.vhd(11): (vcom-1246) Range 3 to 0 is null.
** Warning: ../test/bounds/issue1134.vhd(16): (vcom-1246) Range 3 to 0 is null.

@amb5l
Copy link
Contributor

amb5l commented Jan 15, 2025

How about in for loops specifically?

Good point - no. If ModelSim issues a warning for this case then I'd support NVC doing so.

@avelure
Copy link

avelure commented Jan 15, 2025

Modelsim warns on all null ranges with the same 1246 warning, which I find quite annoying, but I see that it would have helped in this situation.

@m-kru
Copy link
Author

m-kru commented Jan 16, 2025

I use null ranges in a few situations. I do not like the way they are specified in VHDL, and I can well understand your frustration, but I would not want existing working code to start causing compilation warnings.

When do you use null ranges? I have never found any use case for them.

@amb5l
Copy link
Contributor

amb5l commented Jan 16, 2025

When do you use null ranges? I have never found any use case for them.

I've tried and failed to locate the relevant code, but - from memory.. there are times when binding an unconstrained vector port in a module to a null range signal in its parent indicates that port is not needed (I don't think a module can tell if an output is left open), and it then adjusts itself accordingly (via if generate constructs). Sorry if this is not helpful!

@m-kru
Copy link
Author

m-kru commented Jan 17, 2025

Do you have any open source example?

@amb5l
Copy link
Contributor

amb5l commented Jan 18, 2025

See this file for an example.

In this case I have a generic - a 2D array of std_logic - that can be used to initialise the contents of inferred RAM blocks. Its default value is a null range. A function is used to detect the dimensions of the generic and skip initialisation if it doesn't match the RAM dimensions. This is not a great example, but was the best I could find.

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

No branches or pull requests

4 participants