<bsmt>
yeah that's what i mean. i have my testbenches write a gtkw file so I can just run "gtkwave blah.gtkw" and it pops up with most of the traces I want to see
electronic_eel has quit [Ping timeout: 260 seconds]
electronic_eel has joined #nmigen
electronic_eel has quit [Ping timeout: 240 seconds]
electronic_eel has joined #nmigen
key2 has quit [Read error: Connection reset by peer]
key2 has joined #nmigen
Degi has quit [Ping timeout: 240 seconds]
Degi has joined #nmigen
electronic_eel has quit [Ping timeout: 240 seconds]
electronic_eel has joined #nmigen
PyroPeter_ has joined #nmigen
PyroPeter has quit [Ping timeout: 240 seconds]
PyroPeter_ is now known as PyroPeter
<whitequark>
anuejn: just to check--you're not waiting on me for #512, right?
<whitequark>
< tpw_rules> python's way is the most logical to me. verilog and stuff is weird
<whitequark>
this tends to be the experience of people who didn't start with verilog
<whitequark>
and the opposite for people who did
<tpw_rules>
absolutely
<whitequark>
e.g. myhdl chose to break with python collections
<tpw_rules>
maybe in a way it's just easier for me to rationalize. like i find cat being backwards to be a bit weird, but it's logical and consistent
<tpw_rules>
so many things in so many places are not
<whitequark>
yes, that's what i went for
<whitequark>
(it even says so in the manual)
<tpw_rules>
yeah i agree and think it's the right choice
<cr1901_modern>
>cat being backwards to be a bit weird
<cr1901_modern>
Wouldn't feel weird if we read numbers left to right like we do words
<whitequark>
or if we wrote code RTL :p
<cr1901_modern>
(we as in primarily English speaking users)
<cr1901_modern>
lmao
<d1b2>
<OmniTechnoMancer> I enjoy the explicitness of the VHDL way
<d1b2>
<OmniTechnoMancer> whitequark: clearly we require a FORTH HDL
<whitequark>
those exist i think
<d1b2>
<OmniTechnoMancer> I think I had heard of one before but do not remember what it is
<whitequark>
think i'll try to finish cxxsim today
<whitequark>
there's only one major bug left
emeb_mac has quit [Quit: Leaving.]
<d1b2>
<Hardkrash> If FORTH then we can make the programs readable sentences. Ahh FORTH, to update our dictionary!
jeanthom has joined #nmigen
electronic_eel has quit [Ping timeout: 240 seconds]
<lkcl>
whitequark, cr1901_modern: i'm doing a lot of translation between VHDL and nmigen, it gets quite mind-bending. Cat is the one we have to pay attention to.
<lkcl>
what really does my head in is that the numbers in VHDL concatenation (e.g. 2#010110) are specified in standard numerical order (MSB first) yet the concat is often the reverse :)
<lkcl>
urrr
<lkcl>
that, now that i think about it... no it's the other way round, isn't it? VHDL if concatenated left "downto" right would be MSB downto LSB which matches the Consts
<lkcl>
and it's nmigen where it's the other way round.
<lkcl>
but
<lkcl>
remembering that Cat() is just a list, and lists are numbered from 0 to mean LSB, this is "natural"
<lkcl>
it works :)
chipmuenk1 has joined #nmigen
chipmuenk has quit [Ping timeout: 240 seconds]
chipmuenk1 is now known as chipmuenk
<d1b2>
<benzn> hi folks, I'm debugging a puzzling scenario with nMigen/LambdaSoC/Minerva/OrangeCrab, curious if folks have ideas given the following sequence of events: - When I flash the bitstream via JTAG and then load my code over serial, I can read any CSR repeatedly (i.e. the UART divisor or a dummy counter that I've implemented in an extremely basic wishbone peripheral). - When I reset the device by toggling PROGRAMN over JTAG, the bootloader restarts and I can
<d1b2>
reload my code over serial. I can read the UART divisor CSR, but my dummy counter CSR hangs -- the read strobe never pulses (as confirmed by my logic analyzer) - This leads me to believe something is wonky in the reset logic, so I'm trying to expose a reset signal to verify that it's been tripped by my PROGRAMN toggling, but when I do m.d.comb += platform.request('debug_out').eq(ResetSignal("sync")) I get Signal (rst sync) refers to reset of reset-less domain
<d1b2>
'sync' which has me all confused. If I dump verilog for everything, I see a rst signal going into my wishbone peripheral. What am I missing?
<agg>
PROGRAMN force resets everything in the FPGA, irregardless of any reset signal you might or might not have in your clock domain
<agg>
after PROGRAMN is released, the whole FPGA configuration is re-read from the SPI flash, and everything is at its power-up default
<d1b2>
<benzn> Ah yeah, that makes sense. For some reason I has assumed I wasn't writing the SPI flash because the OrangeCrab bootloader still works (I guess there are multiple levels of bootloaders here)
<agg>
when you say you toggle PROGRAMN over JTAG, do you mean your programming probe has a GPIO output that it toggles, or you're sending a command to the ECP5 over JTAG?
<agg>
I don't know anything about the orangecrab specifically, but the SPI flash can hold multiple boot images and also you could load code data to one bit of it without touching a gateware image elsewhere in the flash
<agg>
(there's a JTAG command called LSC_REFRESH which should be identical to toggling PROGRAMN in hardware)
<agg>
when you flash your bitstream via JTAG, are you flashing it to the ECP5 SRAM (volatile) or to the SPI flash and then triggering the ECP5 to load it (non-volatile)?
<d1b2>
<benzn> I'm doing the following via OpenOCD reset_config srst_only; init; jtag_reset 1 1; sleep 100; jtag_reset 0 0; exit
<d1b2>
<benzn> (to pulse PROGRAMN, as confirmed by a logic analyzer observing the JTAG SWD reset pin)
<d1b2>
<benzn> And to load the bitstream, I'm doing the naive thing of loading the svf that's spit out by nMigen
<d1b2>
<benzn> Too much of a noob to really know what that's doing under the hood
<d1b2>
<benzn> opens up the svf and tries to figure out which register determines SRAM vs SPI flashing
<agg>
how is the svf generated?
<agg>
i think that's not built in to nmigen (maybe it is?) but often an external ecp5 tool that takes the bitstream binary that ecppack produces and creates an svg
<agg>
svf
<agg>
oh, ecppack is probably what's producing the svf, in fact
<d1b2>
<benzn> I'm calling platform.build
<d1b2>
<benzn> let me look what that actually does
<whitequark>
yep, ecppack
<d1b2>
<benzn> in this case
<agg>
as far as I know ecppack's svf is only for sram configuration?
<agg>
so I suspect at some point d1b2 you programmed the spi flash with an image which is what's loading every time you reset
<agg>
which has some sort of serial bootloader that you're sending your code to
<agg>
(maybe it even came pre-loaded)
<agg>
and every time you program the ecp5 with your new bitstream, it runs in sram
<agg>
but as soon as you reset, it's always reloading the original configuration that's on the spi flash
<agg>
sorry, benzn*
<agg>
I need to stop tagging the bot, hah
<agg>
I think orangecrab ships with a usb bootloader configuration you can use to program your new configuration bitstream to the spi flash?
<agg>
(rather than using openocd+jtag)
<agg>
(or you could use that gist whitequark linked to create a new SVF which programs the SPI flash instead, or if you have an FTDI-based JTAG probe you could use ecpprog to program the SPI flash over JTAG with it)
<d1b2>
<benzn> ah wow yes, you're absolutely right
<agg>
if your jtag probe is ftdi-based i'd definitely try using ecpprog
<d1b2>
<benzn> i've confused myself by programming a stale bitstream into spi flash
<d1b2>
<benzn> wow, thanks so much!
<d1b2>
<benzn> orangecrab does ship with a usb bootloader, but i've been trying to get a setup wherein i can reload the gateware and/or software without plugging/unplugging things
<d1b2>
<benzn> and the usb bootloader requires (as I understand it) that I powercycle the board while holding down the button on the board
<agg>
hmm
<agg>
on the orangecrab, pin V17 (PB15B) is connected to PROGRAMN, so you could trigger a reset from your own gateware
<agg>
but not sure if you can trigger the bootloader to do its thing, I don't know how that works
<d1b2>
<benzn> so it seems like if my dreams of "handsfree" loading requires that (1) i just constantly reload into SRAM before reloading the software (2) i modify the SVF workflow to program the SPI or (3) I expose a CPU reset that I trigger from JTAG perhaps
<agg>
if it's just the USER_BUTTON you could _probably_ drive it low in your gateware to discharge its 10n capacitor, then toggle a reset, at which point the bootloader would probably still see it as low
chipmuenk1 has joined #nmigen
<agg>
hmm, no, it would take about 80µs to recharge the capacitor and it's probably way longer between programn and the bootloader looking at it
<agg>
benzn: you should be able to use your jtag probe to program the spi flash, one way or another
<agg>
and then toggling programn will reload it
<d1b2>
<benzn> yeah, i wonder if ECPPACK has a flag to do that
<agg>
ecppack won't create an svf that programs the spi flash
<agg>
what jtag probe do you have?
<d1b2>
<benzn> sad face
<d1b2>
<benzn> i have a jlink mini
<d1b2>
<benzn> and although i also have a million ftdi widgets laying around and a SWD breakout that I suppose I can breadboard up into an FTDI-based JTAG probe
<agg>
you could probably also add a reset peripheral to your SoC so that your software can trigger the reset
chipmuenk1 has quit [Ping timeout: 240 seconds]
<d1b2>
<benzn> cool, I'll try this
chipmuenk has joined #nmigen
<d1b2>
<benzn> Yeah, when I first dropped in I was trying to figure out how to expose a reset signal
<d1b2>
<benzn> Does nmigen by default have reset-less sync domains?
<agg>
for ecp5, yes
<agg>
but if you create your own sync domain, the default won't be created for you
<agg>
so e.g. `cd_sync = ClockDomain("sync"); m.d.comb += cd_sync.clk.eq(platform.request("clk20"))`
<agg>
`m.domains += cd_sync`
<d1b2>
<benzn> makes sense
<agg>
(or, I guess, `m.domains += ClockDomain("sync"); m.d.comb += ClockSignal("sync").eq(platform.request("clk20").i);`
<d1b2>
<benzn> Is there any way to add a reset signal to the default domain?
<d1b2>
<benzn> Or perhaps replace the default domain
<d1b2>
<benzn> I feel like I might've done this when I was trying to drive logic via a PLL output
<agg>
the "default" sync domain is only created when you don't make one yourself
<d1b2>
<benzn> ah, gotcha
<agg>
so if you just create your own `sync` with a reset (as above), there's no other "sync" domain created (the names are globally unique by default)
<agg>
that said
<agg>
there are platform-specific concerns - the comments in nmigen/vendor/lattice_ecp5.py explain it around L305
<agg>
if you just assign platform.default_rst, it looks like that will sort of do what you want too
<agg>
hmm, no, ignore that, it needs to be the name of a resource
<d1b2>
<benzn> hmm yeah i set platform.default_rst earlier but that had no effect, trying with a resource named default_rst now...
<agg>
this is really only for an external button/signal to trigger reset, rather than something from user code
<agg>
you could also try using the SGSR primitive, but it's used for you if the default clock gets created
Asu has joined #nmigen
<d1b2>
<benzn> good news is that i've got the sync domain with reset configured and connected as an output to an external pin
<d1b2>
<benzn> default_rst doesn't seem to be sticking, but let me wrap my head around this ecp5 vendor code around reset logic...
<d1b2>
<benzn> oh wait, specifying a sync domain short circuits all this vendor specific logic
<d1b2>
<benzn> indeed, using the default one with default_rst does work 🥳
<agg>
that logic is mainly for 1) synchronising an external default_rst signal (e.g. a button) to the clock properly and 2) setting up OSCG as an internal clock for you, if the platform calls for it
<agg>
so if you're not using an external button or the built-in oscillator, it's ok to just make your own sync domain with reset.. but if using the default one plus default_rst works for you, that should be fine too
<d1b2>
<benzn> right, so next I should figure out if I can trigger this reset signal via JTAG, perhaps by setting up a JTAG tap that twiddles the it (or I suppose I could use a GPIO from an FTDI chip laying around)
<d1b2>
<benzn> but the JTAG tap seems more educational
peeps[zen] has quit [Remote host closed the connection]
mimir_ is now known as XMPPwocky
<XMPPwocky>
For FSM code, is there a smarter way to handle "on entry to state foo, do (xyz) for 1 cycle"? i have a big state machine where most of the states have timeouts where the timeout length is dependent on the state
<XMPPwocky>
so i'd *like* to say "on entry to TX_SYNCWORD, set timer.count_in = 0xdead and timer.arm = True for one cycle"
<XMPPwocky>
atm i just put all that in the states that transition *to* TX_SYNCWORD, which i guess also reduces latency by a clock, but...
<agg>
i also need to do that a lot and so far also usually put that in the previous state in the same condition that sets m.next
<XMPPwocky>
suppose i could just `def transition_to_tx_syncword(): m.next = "TX_SYNCWORD"; m.d.sync += [timer stuff]"
<agg>
yea, at least that stops you accidentally having different timer values depending on where you enter it from
<agg>
though it does already talk a bit about the old `before_entering` methods that were in omigen, and calls them "an attractive nuisance" :p
<XMPPwocky>
well, that's on before_entering, while i'd be fine w/ after_entering too
<XMPPwocky>
or really even just a way to express "if previous_state != current_state"
jeanthom has joined #nmigen
<agg>
indeed. i'd certainly have found it useful for things.
<agg>
even like `fsm.entering()` to go with `fsm.ongoing()`
<agg>
then you could have `with m.FSM() as fsm: with m.If(fsm.entering("x"): m.d.sync += timer.eq(0x1234); with m.Elif(fsm.entering("y"): m.d.sync += time.eq(0x4321);`
<XMPPwocky>
yeah, although i guess i was imagining almost more along the lines of just having some "fsm.state_entered" you can If() on
<XMPPwocky>
then again, being able to read .next would make that trivial to do w/o other language support
<awygle>
i agree that adding it to the fsm enhancement issue is the best way to make sure we don't drop it
<agg>
yea, probably fsm.state_entered that's just 0 or 1 would be super convenient
<agg>
whereas what you do now - setting timeout alongside m.next, with one cycle less latency - would do the right thing
<agg>
kind of annoying/weird to have the entire body of the state be gated on state_entered, suggests it should just be two states :p
<agg>
i.e. have a state before each state which sets it up and then transitions on the next cycle
<agg>
same resulting latency, clearer state machine
<XMPPwocky>
i guess some of the weirdness for me comes from the fact that my mental model of a FSM includes the ability to talk about transitions as first-class objects - otherwise it's just a spicy switch-case
<awygle>
i agree with that, fwiw. in my mind the first and least controversial change to the fsm model would be "on transition" actions of some kind.
<agg>
heh, my point of view is totally the opposite, i first formally dealt with FSMs in the mealy/moore context
<agg>
you get to either depend _only_ on the state, or if you're lucky, on both the state and the input
<awygle>
"depend on both the state and the input" is equivalent to "on transition actions"
<awygle>
.. i shouldn't throw around words like "equivalent" but they're at least deeply related and similar
<awygle>
because the (state, input) tuple is how you determine if there's a transition happening
<XMPPwocky>
i mean, sure, but in the way conway's game of life is equivalent to e.g. javascript - they may be able to express the same computations but there sure is a usability difference
<awygle>
sure, otherwise we wouldn't be talking about changing the fsm model
<agg>
awygle: I guess so long as you also add a memory element that's true
<agg>
but then you have another state bit
<agg>
and now it's the same as having multiple states
<agg>
the proper formalism for a mealy machine is it depends on the _current_ state and _current_ inputs
<agg>
if you cheat by remembering the previous inputs (which is how you know you just transitioned), that remembering is more state, so you just have more states in the state machine now
<agg>
but yes, it's just a formalism and we're trying to be useful here
<awygle>
sure. i wasn't talking about the backwards-looking thing, i was talking about the "i could just def transition_to_tx_syncword" thing, which is what we're currently doing manually
<awygle>
("add a memory element" is the _next_, and more controversial, change i'd like to see to the fsm model :p)
<agg>
i don't think that's the same as "on transition actions" exactly
<agg>
or, well, having "fsm.state_entered" is not
<awygle>
well there's at least four versions of an "on transition action", which omigen called "before_leaving", "after_leaving", "before_entering", "after_entering"
<XMPPwocky>
well it'd be redefining what transitioning *means* such that saying "i'm going to state foo" means something beyond "i'm setting the state signal to foo"
<agg>
I guess if you put all the after_leaving actions separately in all possible next states, and all before_entering in all possible previous states, it can work out without extra state bits
<awygle>
mhm. all this stuff is why we haven't "just fixed it" wrt fsms. even simple stuff is subtle.
<agg>
yea..
<awygle>
someday (TM) we'll have time to really dig in on it
<agg>
i think the formalisms can be quite useful to help catch subtle details
<XMPPwocky>
this is probably my rust background coming through but i almost feel like this should just be my problem - i.e. let the community try out different approaches and see what catches on
<agg>
once you consider 'all storage registers in the module are part of its state' and 'all outputs need to either depend only on that state, or on that state and current inputs'
<agg>
XMPPwocky: oh, yea, you can totally do that already though
<XMPPwocky>
this is all python, i can subclass or whatever
<agg>
there's loads of fun metaprogramming possible with fsm today
<awygle>
XMPPwocky: that's basically what i'm doing, i have (someplace) a draft implementation of statecharts
<XMPPwocky>
yeah, the other problem i have is i also have to deal with the spec's idea of various FSMs - which, though it's clearly designed to be implemented in hardware, rarely maps exactly to a practical HDL implementation
<agg>
yea..
<awygle>
which spec?
<agg>
sometimes you can find a nice python abstraction that lets you write down the spec's detail and then generates the useful hdl
<XMPPwocky>
i.e. "oh, there's this cool state machine, look, here's a diagram, you get an ID packet and then you go from PAGE_SCAN to SLAVE_PAGE_RESPONSE"
<XMPPwocky>
oops, no, i need like 4 states to represent that
<XMPPwocky>
awygle: bluetooth br/edr
<awygle>
oh ok. i was imagining an fsm "spec" and got confused lol
<awygle>
yeah that's why i like statecharts, they map much more naturally to what i want to do most of the time
<awygle>
although, that might just be because i learned them in college almost a decade ago
<awygle>
sapir-whorf and all that
EmilJ has quit [Remote host closed the connection]
<agg>
heh, indeed
<agg>
a regular worry i have with my nmigen is it's very hard to be sure if it's idiomatic/good in both a "generated hdl" sense but also a "is nice nmigen" sense, not least due to relative sparsity of big examples/established ways of doing things
<agg>
like baby sapir-whorf... need to have structures to even start doing cognition
<XMPPwocky>
yeah i'm considering trying to find somebody who i can just pay to do a decent code review of some of this stuff before i release this project
<XMPPwocky>
because there are definitely some real stinkers in here
<agg>
at least with verilog you know it's all bad anyway so you don't have to worry :p
* awygle
slides a business card across the table subtly
<XMPPwocky>
noted, heh
chipmuenk1 has joined #nmigen
chipmuenk1 is now known as chipmuenk
chipmuenk has quit [Ping timeout: 240 seconds]
<XMPPwocky>
agg: yeah this is especially tricky because i have no prior hdl experience except for messing around briefly with a devboard probably 8 years ago now
<agg>
i've also found big fpgas will hide a lot of sins
<agg>
at least with the tiny fpgas you sometimes have to care a bit about whether your solution is literally 100x more gates than necessary :p
<XMPPwocky>
i can believe *that*
<agg>
and finding out how good or bad bits of your design is could be easier
<agg>
between no_flatten and reading the yosys synthesis report you can do reasonably well at least
<XMPPwocky>
i have a 250-tap FIR filter in here to do something where a ~50-tap would be just fine...buuut because of how i designed my interpolating FIR, the number of taps must be a perfect square * the interpolation ratio
<tpw_rules>
that sounds like several FPGAs worth of DSP blocks
<XMPPwocky>
nah, it's running at 1msps but clocked at 100mhz
<XMPPwocky>
so
<tpw_rules>
so just a really long sequence
<XMPPwocky>
ends up being 5 non-interpolating FIRs that i just mux between
<XMPPwocky>
er, 10msps*
chipmuenk1 has joined #nmigen
chipmuenk1 is now known as chipmuenk
<XMPPwocky>
tpw_rules: yeah, and it does cut my latency budget more than it really needs to- but for the current attacks i don't really care. i have 100+ microseconds to spare
<XMPPwocky>
agg: ooh, that IP stack's approach is very very appealing
<agg>
thanks! I really liked it, not sure what I'd change 2 years later
<agg>
it was getting hard to maintain timing at 100MHz, I think just so many big state machines
<agg>
but in retrospect probably didn't need to run the packet processing logic at 100M for a 100Mbps link, heh
moony has quit [Quit: Bye!]
jeanthom has quit [Ping timeout: 240 seconds]
moony has joined #nmigen
jeanthom has joined #nmigen
jeanthom has quit [Remote host closed the connection]
jeanthom has joined #nmigen
jeanthom has quit [Ping timeout: 268 seconds]
emeb has joined #nmigen
jeanthom has joined #nmigen
emeb_mac has joined #nmigen
EmilJ has joined #nmigen
EmilJ has quit [Remote host closed the connection]
EmilJ has joined #nmigen
chipmuenk has quit [Quit: chipmuenk]
felix_ has left #nmigen ["WeeChat 2.3"]
jeanthom has quit [Ping timeout: 240 seconds]
alexhw has quit [Remote host closed the connection]
alexhw has joined #nmigen
<lkcl>
wow long conversations :)
<lkcl>
XMPPwocky: going back to your original question: a trick that i've deployed is, rather than have the FSM "polluted" with extra state names, is to set one combinatorial variable within the FSM, and have that go into a function which edge-triggers for a single cycle
<lkcl>
that way you can leave the FSM in the one state (for several cycles)
<lkcl>
when the FSM exits that state, the combinatorial signal will drop low, and on next entry to that same FSM state the "rising_edge" detection will fire again (for one cycle)
<lkcl>
effectively you have a FSM-within-an-FSM
<lkcl>
if you wanted to use this library feel free, it's LGPLv3+
<lkcl>
or, yeah, just have two FSMs, the first one changes a combinatorial signal which the second one looks for. it's equivalent to that rising_edge function.