ChanServ changed the topic of #nmigen to: nMigen hardware description language · code at · logs at
<awygle> whitequark: are there guarantees/expectations on clocks of write-to-read latency for the various FIFOs?
<whitequark> sync or async?
<awygle> both, async in the case of equal clock frequencies
<awygle> trying to write a test without just increasing numbers until i get "pass"
<whitequark> sync: it's um, documented in the docstring
<awygle> ah, i misinterpreted that line, i see now
<whitequark> async: I think it was never explicitly guaranteed and there's one concern related to it, moment
<whitequark> #217
<whitequark> do you think you could look into it? I looked into it a few times but never quite managed to fix it in a nice way
<whitequark> I *think* it can be fixed without increasing latency
<awygle> i'll add it to my list, but idk when i'll get to it
<whitequark> it's a soundness issue that seems pretty worrying conceptually
<whitequark> I know Xilinx FIFOs actively avoid hitting it
<whitequark> I think it'd be really hard to hit it in practice but it is definitely unsound in theory.
<awygle> yeah
<whitequark> the reason I'm mentioning it now is that besides #217 I see no reason that FIFO latencies would change from their current values
<whitequark> Cliff's design is extremely well tested and it's unlikely the stdlib will ever switch from it
<whitequark> so we can set its latencies in stone I think
<awygle> mk, that makes sense
<whitequark> (although I was surprised he doesn't consider the BRAM a part of CDC..)
<awygle> yeah there are a few assumptions in that paper that could be better elucidated
<awygle> the reset discussion is another one
<whitequark> yeah... and another thing we really need to fi
<whitequark> *fix
<awygle> tyep
<whitequark> I'm still not entirely sure how, or rather, not entirely sure I fully understand the solution
<awygle> i'm pretty sure Cliff's assumption is that anytime the write domain is reset, the read domain is also reset (and vice versa)
<whitequark> right
<whitequark> in principle we could document that and punt on finding the solution for non-simultaneous resets to a wrapper
<whitequark> but it seems footgunny to just allow stale reads.
<whitequark> it's not *unsafe* per se
<awygle> yeah
<awygle> my feeling is that we can synchronize a reset signal from the write domain into the read domain which resets _just_ the read pointer, but i'd want to reaaaaaally work that out before i pushed it to production
<whitequark> the problem is when there are two FIFOs in either direction
<whitequark> in both directions that is
<whitequark> like if you have an Ethernet MAC+PHY running in a separate domain
<awygle> i'm not sure that's actually a problem. it's a bit footgunny but... CDC is like that sometimes. the read domain will come back up and there will already be data in the FIFO, that's not intrinsically undesirable
<whitequark> that's fine if the stream in the FIFO is self-synchronizing
<whitequark> actually, not quite
<whitequark> the problem isn't that there's already data in the FIFO
<whitequark> the problem is that there is data in the FIFO that *you have already read*
<awygle> if you're coming out of reset i'd argue you haven't read anything, by definition
<whitequark> you have read before the reset
<whitequark> like, resetting it shouldn't replay the last packet
<awygle> but "you", in this case, have no memory
<whitequark> sure, you could argue for that position philosophically, but i'm thinking practically in terms of entire system
<awygle> actually i don't even think that would happen
<awygle> (again, would have to work it out to be 100% sure)
<awygle> because i think the read pointer wouldn't reset on a read-domain reset
<whitequark> i reset the Ethernet PHY, its read pointer resets to 0, and the last packet I (the CPU) sent is replayed
<whitequark> oh
<whitequark> hang on it could be just a simple missing reset_less
<whitequark> ok now I feel kind of dumb for not noticing it this whole time
<awygle> well we still need to reset the read pointer on a _write_ domain reset
<whitequark> hmm
<awygle> otherwise the fifo doesn't become empty when it's reset
<whitequark> that's actually something i have far fewer issues with because it's not violating the FIFO invariants
<whitequark> like, missing reset_less makes the FIFO... not actually "FIFO"
<awygle> so you're proposing to not reset the write pointer _either_?
<whitequark> I'm actually not sure.
<whitequark> I'm not proposing anything for it right now because that wasn't the thing I was concerned about.
<awygle> if you reset one but not the other you'll potentially read "uninitialized" memory i think
<whitequark> yes, there are two options I see:
<whitequark> - both write and read pointers become reset_less
<whitequark> - write domain reset empties FIFO
<awygle> yeah, agreed
<whitequark> both of thse preserve FIFO invariants, but have different usability.
<whitequark> I'm completely open to arguments on which one is best.
<awygle> my major issue with the first option is that if you hit a global chip reset, when you come up there will still be things in the fifo
<awygle> which seems counterintuitive
<whitequark> agreed
<whitequark> so let's go for the second one
<awygle> my major issue with the second option is proving it correct :p which we have the tools to do
<whitequark> let me summarize it in the issue
<awygle> (actually idk if the yosys formal tools can handle proving something like that but :shrug:)
<awygle> i guess they should be able to? run the "formal" clock at at least 4x the higher of the write and read clocks, prove the three-edge rule and some other useful invariants hold
<whitequark> I think that's what clk2fflogic does
<whitequark> awygle: hm, on write domain reset, what should happen exactly?
<whitequark> the write domain reset is synchronized to the read domain and then the read pointer is altered?
<awygle> Yes, that's my thought
<whitequark> and the empty flag is forcibly asserted while that's happening, too
<awygle> Yes
<awygle> Which I think is in the original paper
<awygle> I gotta go play golf, I'll be back later this evening
<whitequark> o/
<_whitenotifier-3> [nmigen] whitequark commented on issue #181: Reconsidering AsyncFIFO and resets -
<whitequark> does anyone here have opinions on what a redesigned litex simulator should look like?
<whitequark> I've did a large part of that redesign as cxxrtl, but there's still integration with the host code left, like an Ethernet PHY that uses a host tap interface
<whitequark> cc _florent_
<whitequark> the general idea is that cxxrtl would generate a class definition with the interface it wants to see (which has 1:1 correspondence to the Instance in nMigen or Verilog) and user code would provide an implementation
<zignig> whitequark: when you say "class" is that c++ or python or both ?
<whitequark> c++
<zignig> I suppose a SWIG (et al.) wrapper around that could be possible
<whitequark> why would you need SWIG?
<zignig> to expose the c++ interface back into python.
<whitequark> that'll be a part of nmigen eventually
<whitequark> no SWIG necessary though, just a few structures and ctypes
<zignig> aaah, if it is all Signals, I suppose there is a small number of types.
<whitequark> there's essentially one type, but it's variable length
<zignig> I was thinking in terms of nmigen-stdio , where the cxxrtl can have a i2c , spi , uart exposed.
<zignig> and you can just glue your external code to that.
<whitequark> sure, but you probably want that code to be in C++ anyway
<whitequark> since it's likely doing something like creating a tap interface
<whitequark> if it's just pure Python stuff then you could use the existing simulator interface
<zignig> indeed.
<zignig> finally managed to wrap my head around the FSM , managed to get an WARMBOOT instance that I can activate from the DTR pin on an FTDI.
<zignig> it minimises the number of times I have to go to the workshop to press reset on the FPGA when i'm on my laptop.
<whitequark> nice!
<zignig> The code is janky but it works inside my Boneless as code _and_ muxes the signals to external reset.
<awygle> Boneless doesn't have a c compiler does it?
<whitequark> nope
<zignig> awygle: I've been building some python generators, but it's WIP.
<zignig> read _borked_ :)
<awygle> K that's what I thought. How does it compare LUT wise to PicoRV or Minerva?
<zignig> awygle: ICESTORM_LC: 786/ 7680 10% , with some periph. ~600 ish with just the core.
<awygle> Seems comparable to PicoRV then
<whitequark> 600 is kinda high
<whitequark> the LUT target is 300 but that might be unrealistic, 400 is closer to what I think I can do
<zignig> correction , ripping out some debug devices and other bits, currently SB_LUT4 = 495
<awygle> i know ZirconiumX told me how big Minerva was a while back but i can't remember... let's see if i can find those numbers
<emily> probably not that hard to just clone and measure
<awygle> i feel emotionally that it will be, but you're probably right :p
<awygle> SB_LUT4 2526
<whitequark> b i g
<zignig> whitequark: phat? ;P
<emily> see, if nmigen is good for one thing it's making the FOSS EDA toolchain experience not too horrible.
<emily> python dependencies are pretty easy.
<zignig> emily: and catching those stoopid verilog footguns.
<whitequark> emily: uhm.
<emily> tbh if supported verilog that'd probably be pretty popular.
<whitequark> it does.
<emily> til.
<whitequark> you can add any verilog files.
<emily> what was the uhm?
<whitequark> the toplevel still has to be in nmigen, but, hm
<awygle> it is indeed beeg cpu
<whitequark> i think you can just return an Instance and it'd just work
<awygle> but it has a 6 stage pipeline, so that's not unreasonable
<whitequark> i think.
<zignig> it would be cool to have a automagic verilog wrapper for nmigen. Scan and parse the verilog files and Instance them up.
<whitequark> emily: python's package manager is the single worst of all major post-1990 languages
<whitequark> well
<emily> why have an automagic verilog wrapper when you could have an automagic verilog translator :3
<whitequark> python's package... management
<emily> i wonder if that's feasible.
<emily> like. you just need a yosys backend that writes nmigen.
<emily> nmigen->rtlil is designed to be trivial so how bad can rtlil->nmigen be.
<zignig> emily: eww. ;)
<whitequark> i think lkcl said he made a sv->nmigen converter
<emily> hot take: verilog machine-translated to python eDSL is still better than verilog. fight me.
<whitequark> you'd have to materialize clock domains from thin air
<whitequark> zignig: awygle also wanted this automatic wrapper thing
<zignig> with all the verilog out there , it would be kind of cool to say ... use this in nmigen please.
<whitequark> i mean you can already do it, you just have to do a bit of manual work
<zignig> I did find a verilog EBNF for lark-parser that could extract (i|o)_signal from the module defs
<emily> to be clear, I only mean the synchronous verilog subset ofc
<emily> and not handling x
<zignig> emily: one of the things that I like about nmigen is that I can write RTL with _no_ verilog at all.
* zignig is wrapping FIFOs around a uart to stop overrun interlocks.
<_whitenotifier-3> [nmigen-soc] zignig commented on issue #10: Peripheral API design: exposing bus interfaces -
<zignig> whitequark: can I please get 3 commits on Boneless, updated to the new instruction set (@tpwrules) I reckon it would be possible to boot it on _every_ nmigen-board ... with blinky and switches.
<whitequark> zignig: please be patient
<zignig> whitequark: np, I am going transdimesional atm. sorry :(
* zignig has dropped the ball again.
* zignig lookw for the ball.
Asu has joined #nmigen
* zignig has found others to help me find the ball.
mszep has joined #nmigen
mszep has quit [Remote host closed the connection]
thinknok has joined #nmigen
mwk_ has joined #nmigen
mwk has quit [Ping timeout: 246 seconds]
* zignig has walked 8769m , is feeling better.
mwk_ is now known as mwk
_franck_ has joined #nmigen
<vup> for wrapping verilog instances I found using yosys json output to be quite useful:
<vup> (the strange SignalProxy stuff is mainly there to avoid adding all the inputs and outputs to the nmigen instance in the case of huge verilog blackboxes like the PS7 thing for zynq's)
<awygle> so I have a basic stream implementation. other than my ILA port and a UART, are there things I should try to implement with it to see how it holds up? What are the utility modules you'd expect to be supported?
Sarayan has quit [Ping timeout: 272 seconds]
Sarayan has joined #nmigen
electronic_eel has quit [Ping timeout: 240 seconds]
electronic_eel has joined #nmigen
<awygle> Can I put nmigen formal asserts in a module without doing anything special? Will they be ignored for non-formal synth/sim?
<thinknok> awygle, as a workaround you can use an "if" statement to remove formal asserts/assumptions when doing synthesis (
<awygle> thinknok: thanks
thinknok has quit [Ping timeout: 272 seconds]
<awygle> what's the convention on parameters vs. inputs/outputs for a module? for a while i was saying "anything that's taken by the constructor is a parameter" but now i'm questioning whether that's correct
<ZirconiumX> It's what I use as a convention
<ZirconiumX> And inputs/outputs have i_/o_ prefixes
<awygle> What's pushing me away from this is something like a stream connecter which buffers the stream (for timing). It seems natural for it to take the stream it's buffering as a constructor argument
<awygle> Especially since I can't in python reserve space for an "upstream" field without putting something in there now, even if it's None
<Sarayan> what's a stream and how different is it from a signal?
<ktemkin> yeah, I don’t view constructor arguments as param-only
<awygle> Sarayan: it's a signal (or record) plus a ready/valid handshake, plus maybe some other stuff depending on the variant
<Sarayan> funky
<awygle> LiteX has this concept, and wq wants it as part of the interface to nmigen-stdio modules
<ktemkin> especially while we’re lacking sane semantics for something like .connect(), it doesn’t necessarily make sense to squish everything through Signal-like IO boundaries
<ktemkin> and there are some particularly nice patterns that come with “pass a bus-like object in as a constructor argument”
<awygle> mhm
<awygle> i think i'll go with that, but it is a bit challenging that it makes it difficult to look at a module and go "x is a parameter"
<awygle> guess that's what docstrings are for
<awygle> or typing annotations maybe? not sure how useful those would be for this tbh
<ktemkin> I mean, often the delineation between a Parameter and a piece of I/O isn't all that rigid to begin with
<awygle> hmmm i find that statement challenging, but it could easily be verilog braincruft. lemme sit with it a bit lol
<ktemkin> sometimes it Very Much Is ("I want a memory bank that's <this> big")
<awygle> "this memory bank is too small" "this memory bank is too large" "this memory bank is juuuuuuuuust right"
<ktemkin> but e.g. most inputs conceptually reduce to parameters if you tie 'em to a constant
<awygle> Sarayan: for further reading
<Sarayan> awygle thanks
<ktemkin> My point is mostly that you'll need to scope what can be passed to each of your arguments anyway; so I don't think it's unreasonable to expect the documentation to specify where a Signal/Value is acceptable
<ktemkin> and thus the thing to think about becomes less "is this an IO element I'm going to connect to, or a parameter I'm going to set on instantiation?" and more a question of what you expect to be resolvable at elaboration time vs a signal that'd exist in the created hardware
<ktemkin> [that said, I'm in the phase of sleep deprivation where I keep having to wonder if I'm speaking English intelligibly, so take my thoughts with a grain of salt]
<_whitenotifier-3> [nmigen] awygle commented on issue #317: Stream Abstraction for nmigen.lib -
<ktemkin> <-- I tend to stick a big header explaining my interface in the class docstring
<awygle> yeah wq does that too
<awygle> i am not a fan of docstrings in general but i will follow that convention (if nothing else we obviously need _something_ to serve the roll of explaining the interface)
<ktemkin> I mean, docstrings are just fancy comments
<ktemkin> for these purposes, anyways
<ktemkin> one thing I very much like about accepting I/O in the class constructor is that it allows one to do some interface duck-typing, which can be _very_ nice when working with adapter hardware
<ktemkin> for example, I might have a USB module that works with a UTMI interface; if it accepts that interface as a constructor argument, it be used in the typical way (e.g. grab the bus from platform.request and pass it in)
<awygle> yup. python 3.8 is supposed to get structural typing? which would be really useful for that kind of thing
<ktemkin> or, I can take a piece of adapter hardware that e.g. converts from ULPI <-> UTMI, and pass that _whole module_ in as the argument
<ktemkin> so, either `MyModule(utmi_bus)` -or- `my_adapter = ULPIUnwrapper(ulpi_bus); MyModule(my_adapter)`
<ktemkin> I could also see that being abused; but for things like bus translators, I think I enjoy that duck typing enables that kind of pattern
<awygle> i miss strongly typed languages :(
Asuu has joined #nmigen
Asu has quit [Ping timeout: 240 seconds]
tcmichals has joined #nmigen
tcmichals has quit [Remote host closed the connection]
Asuu has quit [Remote host closed the connection]