whitequark[cis] changed the topic of #amaranth-lang to: Amaranth hardware definition language · weekly meetings: Amaranth each Mon 1700 UTC, Amaranth SoC each Fri 1700 UTC · code https://github.com/amaranth-lang · logs https://libera.irclog.whitequark.org/amaranth-lang · Matrix #amaranth-lang:matrix.org
Degi has quit [Ping timeout: 255 seconds]
Degi has joined #amaranth-lang
iposthuman[m] has joined #amaranth-lang
<iposthuman[m]> Question regarding FSMs. if i have a verilog always block that combines some "if" statements and state machine, for example:... (full message at <https://catircservices.org/_matrix/media/v3/download/catircservices.org/kPlFOnGfHIaLYCgxGrnNVXGp>)
<tpw_rules> amaranth will handle the FSM reset automatically
<crzwdjk> If you need to reset it with something that's not the global reset you can also use ResetInserter
<tpw_rules> as for the switch to init when (valid && !ready && state == STATE_IDLE), you can put an if statement inside the IDLE fsm state to handle that condition
<tpw_rules> like any other amaranth statement, only the last m.next which matches will be used
<tpw_rules> (it also follows that if you didn't want to use a resetinserter for whatever reason, you could put the reset logic at the end of every state)
<zyp[m]> is it possible to only reset the FSM and not all the other state in the module/submodules?
<tpw_rules> i don't know how
<whitequark[cis]> not if you use ResetInserter, no
<whitequark[cis]> (this is something we could fix once scopes land)
<tpw_rules> to use resetinserter on just the fsm you would indeed have to kick it into a submodule
<tpw_rules> you could put the reset logic in a python function too, i think that would be reasonably justifiable
<zyp[m]> I guess you could do something cursed like instancing a second module in the same elaboratable and put only the FSM into that
<whitequark[cis]> you could do that but it might cause a hierarchy flattening warning if you use certain patterns
<zyp[m]> ah, because it'd cause driver conflicts otherwise, yeah
<tpw_rules> does that warning flatten the whole design?
<tpw_rules> quasi-relatedly, is there hope for, if i construct 1000 of the same Elaboratable class, to emit verilog with one definition and 1000 instantiatons?
<whitequark[cis]> tpw_rules: no
<whitequark[cis]> Amaranth emits post-elaboration netlists
<whitequark[cis]> if you ran Yosys on this input, it would produce, as an intermediate result, exactly the same kind of netlist (in memory)
<whitequark[cis]> Amaranth simply brings this step closer to the source (necessarily so)
<whitequark[cis]> tpw_rules: no, only as-needed
<whitequark[cis]> however, note that with the new IR, what we are doing is flattening the whole design and then hallucinate module boundaries back
<whitequark[cis]> because this is the only practical approach to problems like "CDC analysis" and "people can use sig[0] to communicate between modules a and b in comb domain and sig[1] to communicate between modules c and d in sync domain"
<tpw_rules> what do you mean by hallucinate?
<tpw_rules> i thought the hierarchy preservation was a valuable improvement over migen
<whitequark[cis]> correct
<whitequark[cis]> what happens is that hierarchy is erased, the netlist is constructed and processed, and then, during emission, the hierarchy is reconstructed back based on debug information
<tpw_rules> sounds pretty ambitious
<whitequark[cis]> this is, interestingly enough, the same thing as what Vivado does if you use -keep_hierarchy
<whitequark[cis]> tpw_rules: we have most of it working
<whitequark[cis]> it's actually simpler than the existing scheme in some ways, and for sure more reliable
<iposthuman[m]> I've seen mention of ResetInserter several times but i don't quite understand how it affects the generator.
<tpw_rules> that's bringing up horrible memories of trying to SignalTap™ stuff
<whitequark[cis]> oh yeah, ILA for Amaranth is another item on the long term roadmap
<tpw_rules> that would be very exciting
<crzwdjk> iposthuman[m]: ResetInserter(some_signal)(my_submodule) returns a module that gets reset when some_signal is 1
<tpw_rules> i guess vendor ILAs are unreliable to preserve design behavior?
<tpw_rules> it's hard to fathom that their engines are so screwed up they can't stash a signal away reliably but i guess it's possible
<whitequark[cis]> hm? no, why would I even try to use vendor ILAs?
<tpw_rules> i'm not saying you would, just trying to explain my personal experiences with them
<tpw_rules> s/explain/understand/
<whitequark[cis]> there's no Yosys/nextpnr ILA, so Amaranth has to fill it in
<tpw_rules> i'm just wondering why "take this variable in the verilog and connect it to an ILA" is such a damn hard problem for quartus
<whitequark[cis]> oh, it's because Quartus isn't a good toolchain
<tpw_rules> is vivado's better?
<whitequark[cis]> I've not used it much but I think it is better, yes
<tpw_rules> like the ILA on quartus is okay, it's just that hooking signals to it is difficult and fraught with trouble
<tpw_rules> anyway that's probably enough rambling
<iposthuman[m]> Ok i think i understand, but what about the other if statements attempting to control the fsm "outside" of the fsm itself. In my example there is```m.if(x) m.next = "xx"
<iposthuman[m]> m.Elif(y) m.next = "yy".
<iposthuman[m]> ```In other words how would you modify the next state outside of the fsm's with-states?
<whitequark[cis]> tpw_rules: wait, were you using `(* keep *)` on signals of interest?
<tpw_rules> you can't
<tpw_rules> whitequark[cis]: i ended up having to make an always block to latch them into temporaries, then noprune those temporaries
<tpw_rules> iposthuman[m]: why not put that if statement into a state?
<whitequark[cis]> tpw_rules: ok, in Vivado `(*keep*)` is enough
<iposthuman[m]> Amaranth doesn't like that that verilog code was modifying the next state based some "if" statements. in verilog this is allowed but not Amaranth
<tpw_rules> whitequark[cis]: but why are they not smart enough to automatically add that to signals selected for ILA :(
<iposthuman[m]> That was one of my ideas but the fsm would need to be in that state in order to do stuff. yes?
<tpw_rules> yes
<tpw_rules> if the logic applies in multiple states, you'll have to duplicate it. judicious use of python local functions would make this cleaner
<iposthuman[m]> Ah. wouldn
<tpw_rules> i have internally wished for a reimagining of amaranth FSMs to make this easier before but i'm not really sure how it would look
<zyp[m]> litescope is easy to use and conceptually pretty simple and a minimal amaranth equivalent shouldn't really be all that much work
<iposthuman[m]> * Ah. wouldn't that produce larger resource usage?
<tpw_rules> probably not
<tpw_rules> zyp[m]: is it hooked up over jtag on intel?
<iposthuman[m]> * Ah. wouldn't that produce larger resource generation?
<whitequark[cis]> tpw_rules: yeah me too
<zyp[m]> tpw_rules: it's memory mapped, and litex has jtag memory bridges, so I expect it can be
<tpw_rules> iposthuman[m]: likely not. it's just changing the inputs to the circuit, not the circuit itself really
<tpw_rules> zyp[m]: problem is i was last using it to debug my bus :D
<iposthuman[m]> Ah, okay.
<zyp[m]> I've mainly used litescope with ethernet and usb bridges
<tpw_rules> the cost model for verilog is very different than regular code
<tpw_rules> litex is not really my favorite either but that's a separate problem
<zyp[m]> I've recently been wanting a utility to capture ADC streams for debugging, and I guess if I want to capture multiple streams that don't always run in sync, I might as well just do an ILA with RLE
<iposthuman[m]> Does anyone have, or know of, a ResetInserter being used with an FSM?
<crzwdjk> I mean I have a module with an FSM inside it, I wrap the module with a ResetInserter. Haven't pushed the code to github yet, but it's pretty straightforward.
<crzwdjk> Oh wait I have in fact pushed it, iposthuman[m] https://github.com/crzwdjk/uniterm/commit/70b5f99f5d55e6338f8f93ee21f654a88add5177
<iposthuman[m]> Basically every time fmreset toggles it triggers a reset?
josuah has quit [Quit: zzz]
Wolfvak has quit [Quit: ZNC - https://znc.in]
Wolfvak has joined #amaranth-lang
<zyp[m]> I've been turning the simulator racing over in the back of my head for a bit, and have an increasing belief that a way to distinguish «set now» from «set soon» is a viable solution, with a couple of different possible approaches
<zyp[m]> one is to actually have those as distinct methods or a method argument or whatever, which I guess will somewhat resemble blocking and nonblocking assignments in verilog
<zyp[m]> another is to have a sort of barrier where writes after the barrier doesn't affect reads before the barrier, which is what a picosecond delay achieves, but which would probably be cleaner if implemented as two different phases at a single simulation timestamp
jfng[m] has quit [Quit: Idle timeout reached: 172800s]
<whitequark[cis]> I'd like you to evaluate the solution I proposed yesterday before venturing into "let's replicate Verilog"
<whitequark[cis]> (I'm not going to replicate Verilog)
<whitequark[cis]> to clarify my position further, I think having testbench processes is an absolute necessity to enable the more complex SoC use cases (right now doing a write on the CSR bus for example is extremely difficult to do in a simulation) and I think that even having these races unresolved isn't a reason to avoid progressing on testbench processes. we could even show a warning if you add more than one at the same time; this would still
<whitequark[cis]> be a vast improvement over status quo
<zyp[m]> I agree, I'm of the opinion that both RFC 27 and RFC 36 are good and that the races should be fixed in a new RFC building on those
<zyp[m]> or to put it differently, that the races doesn't block RFC 27
<whitequark[cis]> that's good!
<whitequark[cis]> what do you think of my idea to track def-use relationships between processes?
<zyp[m]> I need to think it through, will get back to you later on that
<whitequark[cis]> thanks!