-
Notifications
You must be signed in to change notification settings - Fork 16
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
RFC 36 (async/await testing) #742
Conversation
94ba441
to
76727d0
Compare
d6dc0e1
to
d260186
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only some bikeshedding.
async for _, _, ticks_val, combined_trigger_val, *record_vals in ( | ||
sim.tick("sync_neg") | ||
.sample(ticks, combined_trigger) | ||
.sample(*itertools.chain(*([record.trigger] + record.fields for record in records))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This equals to .sample(records[0].trigger, records[0].fields[0], ..., records[0].fields[-1], records[1].trigger, records[1].fields[0], ..., records[1].fields[-1], ...)
, do I understand right? It fits with logic inside handle_logs.
Looks a bit contrived, maybe some conversion could be extracted to a helper function, so that the records are grouped somehow maybe. Can handle_logs sample the records on its own?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had the exact same thought. To do it better, you would probably need to represent the records using amaranth.lib.data
or create custom ShapeCastables
, ValueCastables
, etc. Each record is different, so each would need a different shape. I decided to use this solution because it seemed to need less work than the alternative. I can leave a comment if you think it's warranted.
f43258d
to
86a7286
Compare
@tilk How was your experience with async/await processes/testbenches? Any pain points I should know about? |
@whitequark Pretty good actually. The sampling mechanism helps with races quite well. However, porting some tests required more work, because sampling requires you to take samples on a tick; you cannot decide later that you wanted to have a sample of some signal. A variant of It would be nice to have some synchronization mechanism which could allow removing races on Python state shared between processes. Currently I solve this by (ab)using |
Very happy that you like it! The plan is to treat the new simulation mechanism as stable and not ever have as much churn as this migration caused, so I'm glad that it works well. A lot of careful work went into it.
Yes. Sampling a value essentially sets up a "tripwire" which then calls .get and remembers the result. Copying the entire simulator state is of course technically feasible but seems very wasteful. We considered it and decided not to add it at the time. Of course an RFC could change that.
I agree! At the time, my "solution" to it is to use Amaranth signals to share state, but this of course does not cover everything. It comes to mind that you could probably make a "mutex" (or other sync primitives) out of an Amaranth signal and random Python data. Would this solve anything? Ideally I'd like to expose an easier to use concept, but I don't have any thoughts on the design. |
(When building a mutex there comes the issue of two processes locking it at exactly the same time. I'm thinking that each |
This PR refactors the tests for Amaranth's RFC 36. It is pretty massive, so thorough reviews are not expected. Let's merge this as quickly as possible and then deal with the possible aftermath later.
Important changes:
Settle
were replaced withsim.delay()
.Settle
were removed.sim.tick().sample()
) is used instead of signal value getting where it was reasonably simple to do so. In other cases,sim.get()
is used (but we should try to avoid it).MethodMock.effect
. The effects are run once per cycle.CallTrigger
was added, which allows to call multiple methods in a single clock cycle, together with sampling signals and the state of other methods.TicksKey()
.