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

Decide on the specific simulation and synthesis behavior for out-of-bounds Array access #7

Closed
whitequark opened this issue Dec 16, 2018 · 12 comments
Milestone

Comments

@whitequark
Copy link
Contributor

Migen left this undefined so we have wide latitude here. IMO the following should happen:

  • In simulation, a hard crash, with a nice message. (This already happens, but without the nice message.)
  • In synthesis, xs, to let the synthesizer discard useless logic. Migen's output causes waste in inferred multiplexers, and Migen's output already causes way too many multiplexers to be inferred.
@jordens
Copy link
Member

jordens commented Dec 16, 2018

I would prefer to have a well defined default. The last or first element. That's what mögen dies now. It's also what you want in practice. I suspect x won't synthesize and isn't something you want to face. And an empty array should be an error IMO.

@whitequark
Copy link
Contributor Author

I suspect x won't synthesize and isn't something you want to face.

Of course it will, x is saying to the synthesizer that this index is impossible even if it cannot prove that, so the synthesizer can discard any logic handling that state.

@whitequark
Copy link
Contributor Author

@jordens Are you opposed to making out-of-bounds access a hard error in simulation? Why? I understand having a well-defined default for synthesis instead of x (though I would rather have x as an option, even if off by default), but this seems like an easy decision for simulation.

@jordens
Copy link
Member

jordens commented Dec 16, 2018

But x doesn't mean "Impossible". If the synthesizer encounters it, afaik it will bail. X doesn't unify with any (valid) downstream logic. In if you out of bounds selectors, the only possible (synthesizable, in practice on fpga) end solution will be a default.

@whitequark
Copy link
Contributor Author

whitequark commented Dec 16, 2018

@jordens This is not true. IEEE 1364.1-2002 section 5.5 explicitly allows using X on RHS of assignment to specify a don't care value, which is exactly what I want here:
screenshot_20181216_125736

Of course, the end result will usually be that the synthesized logic will select some multiplexer input as an output, but the whole point here is to ease the pressure on the synthesizer and let it not use any extra
logic to ensure any specific output. Which I believe will make a nontrivial difference based on my examination of RTL generated from Migen code and the causes for its relative inefficiency, although I do not yet have numbers for some specific representative designs.

@whitequark
Copy link
Contributor Author

whitequark commented Dec 16, 2018

(And moreover, e.g. Yosys will happily introduce X values internally during synthesis when reorganizing logic. So of course it has to handle X correctly. Everything that uses the Synopsys frontend also should handle that correctly; Synopsys handles X and Z far better than Yosys, including permitting Z intra-chip...)

@jordens
Copy link
Member

jordens commented Dec 16, 2018

Ok. In general the offerings of the verilog spec should be checked against practicability. Does this also hold for e.g. vivado? I'd imagine that allowing x will taint all downstream logic and in turn prevent timing analysis (for example).
If x as default leads to valid synthesis in practice in almost all cases and if there is an easy way to override that default for out of bounds, I'm happy.
But for simulation, why would you do it any different? You'd have something desirable for synthesis but your code would not be simulatable. It's going to be tedious to implement and propagate NaN everywhere.

@whitequark
Copy link
Contributor Author

If x as default leads to valid synthesis in practice in almost all cases and if there is an easy way to override that default for out of bounds, I'm happy.

This is what I believe will happen, yes.

But for simulation, why would you do it any different? You'd have something desirable for synthesis but your code would not be simulatable. It's going to be tedious to implement and propagate NaN everywhere.

No X propagation. Just a hard error (exception, or maybe something equivalent but nicer) if you ever index an array out of bounds. When is this ever not a coding error? Especially given that Migen docs unambiguously require the array index to always point within bounds.

@jordens
Copy link
Member

jordens commented Dec 16, 2018

That sounds problematic. It would lead to valid and desirable (for synthesis) code that you can't simulate, right?
Or are you saying that you trust that the relevant synthesizers must all be able to infer that there won't be an oob access and x won't happen?

@whitequark
Copy link
Contributor Author

Or are you saying that you trust that the relevant synthesizers must all be able to infer that there won't be an oob access and x won't happen?

The other way around. Using X on RHS is communicating to the synthesizer that it can substitute whatever it wants with that expression because it will never happen because of some invariant in your design that you know holds true but the synthesizer may not be able to infer on its own.

So these are two sides of the same coin. The invariant is that OOB access will never happen. In simulation, if this invariant is violated, we can detect it directly because it's easy, and indicate it as a programming bug. In synthesis, we assume that the invariant is never violated, and communicate this to the synthesizer.

So long as the invariant is not actually violated, which is the contract Migen already requires you to uphold, neither the simulation behavior (which is an exception) nor the synthesis behavior (which is an arbitrary, possibly nonsensical value being assigned), actually ever happen. There is no simulation-synthesis mismatch because the out of bounds case never happens neither in simulation nor in synthesis, and there is nothing that may or may not 'match'.

@jordens
Copy link
Member

jordens commented Dec 16, 2018

Are you sure that vivado handles x correctly (it can do whatever it wants and uses it to simplify logic)?
If x is ever not removed during synthesis, I'd be worried:
If the synthesizer actually chooses a value (it must) for x, then how does it choose e.g. other information for that signal, like timing constraints? That information can't be "don't care".
I don't see what's wrong with the migen behavior and the docs there. "Any out-of-bounds access performed on an Array object will refer to the last element." sounds well defined to me. There is nothing required from the user, Migen plasters over OOB.
I'd postulate that actually using the default (and hence the desire to make it well defined) is a common case.

@whitequark
Copy link
Contributor Author

I'd postulate that actually using the default (and hence the desire to make it well defined) is a common case.

After discussion with @sbourdeauducq I agree with this. The default will be the same as in Migen, with using X as an opt-in possibility.

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

No branches or pull requests

2 participants