<whitequark>
anuejn: needs to have a metaclass so that `class Foo(data.Struct):` lets you do `Shape.cast(Foo)` and thus `Signal(Foo)`
<whitequark>
and by that point you might as well just use inheritance for the rest
<whitequark>
this is the purely technical reason
<whitequark>
the more conceptual reason is that dataclasses are designed to be as unobtrusive as possible, since they're a building block for your own classes (which you want to inherit from whatever) that's as generic as possible, but `data.Struct` and friends are serving a very specific purpose
<whitequark>
it's fine to add a bunch of attributes or properties to a `data.Struct` but you probably shouldn't be using that as a generic building block. having to inherit indicates that the derived class is Amaranth's more so than yours
<_whitenotifier-9>
[amaranth-lang/amaranth-lang.github.io] whitequark ee718d4 - Deploying to main from @ amaranth-lang/amaranth@ee9da63287c1ea5b478f93ca9624f1449e3c4d0c 🚀
<lsneff>
Catherine: Is there a plan in the future to revisit whether there should be a semantic distinction between storing data and moving data in amaranth? e.g. registers vs wires?
<d1b2>
<dub_dub_11> isn't that sync vs comb
<lsneff>
Pretty much I guess
<lsneff>
Sync vs. comb is a great distinction, but it constantly throws me off that they're assigned with the same syntax
<whitequark>
Lachlan Sneff: by "registers vs wires" do you mean the Verilog concepts, or the EE concepts?
<lsneff>
The EE concept
<lsneff>
~vaguely~
<whitequark>
the answer is "no" in either case, but for the latter I'm curious what you would like to see?
<lsneff>
If only python was expression rather than statement based
<lsneff>
I'm not 100% sure, but I feel like something that feels more like a dataflow programming language for the combinatorial logic would fit what I'm saying
<lsneff>
Instead of treating it as a clock domain
<lsneff>
That's not actionable though
<lsneff>
I'll keep thinking about something concrete
<whitequark>
Amaranth is a thin abstraction over decision trees and multiplexers; the difference between a signal assigned in m.d.comb and m.d.sync is that in the former case the freshly computed value is propagated immediately, and in the latter it's buffered through a flop
<lsneff>
Right. I understand that
<whitequark>
it doesn't quite work that way right now, but most of a Module should translate to one giant `always @*` process computing the `s$next` values for every signal `s`, and then one process per domain (including the comb pseudo-domain) assigning the `s$next` values back to `s`
<whitequark>
(the RTLIL backend is doing something silly, inefficient, and vaguely unsound instead; I should fix that)
<modwizcode>
I am still not entirely sure how the provided fix actually changes how sound what is happening is
<whitequark>
with the "LHS grouping" workaround, you can construct a contrived sequence of statements using Cat() on the LHS to make Amaranth emit an equivalent of `always @* begin c = b; b = a; end`; something along the lines of `m.d.comb += [Cat(z, c).eq(Cat(z, b)), Cat(z, b).eq(Cat(z, a))]`
<modwizcode>
That unfortunately makes a lot of sense.
<whitequark>
it's kind of tricky to actually get it to do that
<Degi>
What is the z for
<whitequark>
tying c and b together
<whitequark>
m = Module(); with m.If(t): m.d.comb += [Cat(z, c).eq(Cat(z, b)), Cat(z, b).eq(Cat(z, a))] # this does it
<Degi>
Does that result in c = b = a? Or what while the if is true that c has the old value of b and b has the value of a or so?
<whitequark>
ignore the If, just set t to 1
<Degi>
Hmm, shouldn't that be equivant to m.d.comb += [c.eq(a), b.eq(a)]
<whitequark>
run it unmodified and with the modifications in the text
<modwizcode>
<whitequark> "tying c and b together" <- Technical explanation: Without it, Amaranth splits the assigns into separate processes which has a different behavior. But anything grouped on the LHS of an assignment is currently grouped together so it will end up in a single `always @*` block and trigger this race condition.
<whitequark>
s/text/comments/
<whitequark>
it's not actually a race
<whitequark>
it's a sensitivity issue
<modwizcode>
Isn't it a race condition in the sensitivity?
<modwizcode>
Well, I guess technically not
<modwizcode>
It's only a race in a theoretical sense, there is some actual defined order internally
<whitequark>
it's 100% deterministic, just always wrong
<modwizcode>
Oh is it actually deterministic?
<whitequark>
I like how they fixed this issue in `always_comb`, but made it so that if you run the same two statements in the _reverse_ order, you get a different wrong result
<modwizcode>
Amazing
<whitequark>
Verilog is infuriating
<modwizcode>
Do you actually like VHDL any better though? (Besides the simulation scheduling model being better/actually defined)
<whitequark>
I would be working on GHDL if I liked VHDL a bunch
<Degi>
Huh it kinda produces the opposite of what I'd expect
<whitequark>
whitequark: oh, nevermind, I misread something
<whitequark>
they just didn't fix this for `always_comb`. they only fixed the issue where `always @*` would not be run at time 0 if you don't have any regs on the RHS
lf has quit [Ping timeout: 256 seconds]
<whitequark>
`always @*` has another maddening issue, where `reg x = 0;` is actually just `reg x; initial x = 0;` and therefore it's racing with `always @* y = x;`
lf has joined #amaranth-lang
<whitequark>
> (IEEE 1800-2017 9.2.2.2) The [always_comb] procedure is automatically triggered once at time zero, after all initial and always procedures have been started so that the outputs of the procedure are consistent with the inputs.
<whitequark>
okay, at least they fixed that one too
<modwizcode>
Oh, because Verilog doesn't define `initial` to run before T=0?
<modwizcode>
Well I guess it does now
<whitequark>
yeah, it runs at 0 exactly
<whitequark>
no, it's more that `always_comb` runs at 0 plus epsilon now
<whitequark>
you know, at time 0+0, which is strictly greater than time 0
<modwizcode>
I'm sure that everyone using Verilog has a copy of the specification on hand and looks at it frequently to avoid these sorts of issues!!
<whitequark>
hahaha sob
<modwizcode>
whitequark: How does that differ from saying `initial` and `always` runs at T=0-epsilon?
<mwk>
*sigh*
<whitequark>
hi mwk
<mwk>
'reg x; initial x = 0;' is racey, 'reg x = 0;' is not
<mwk>
and yes I just had to look it up
<modwizcode>
We summoned mwk by talking about verilog