<awygle>
whitequark: your comment is of course correct, do you want ValueCastable to be an ABC? i think we want to avoid polluting the metaclass so that method should throw NotImplementedError or something
moony has quit [Remote host closed the connection]
<whitequark>
yep, iirc we discussed it and decided against ABCing
<whitequark>
hm, Elaboratable *is* an ABC
<whitequark>
that was a mistake I think
moony has joined #nmigen
<awygle>
k I'll make it throw
<awygle>
and put in a test
<awygle>
whitequark: lol actually the abstractmethod is superfluous
<awygle>
since as_value isn't @lowermethod in the base class
<awygle>
if you don't override you get the @lowermethod error in __new__
<whitequark>
excellent
<awygle>
do we want to just remove as_value from the base class so that we can properly detect the difference between "no override" and "no @lowermethod decorator"?
peepsalot has joined #nmigen
<whitequark>
sounds good; there's no elaborate() in the Elaboratable base class either
<whitequark>
I think it can still appear in the docs in spite of that
<_whitenotifier-f>
[nmigen] DaKnig commented on issue #492: How do you make a bounded up-down counter without modulo? - https://git.io/JUsf2
<DaKnig>
whitequark: would be cool to be able to hold the fragment that represents m.If, m.Switch...
<whitequark>
hold?
<DaKnig>
I mean , assign it to a python uh... name? how was that called technically in python?
<DaKnig>
like `a= Signal() + Signal()`
<whitequark>
`a` is a Python variable
<DaKnig>
`a` is now the fragment that represents the operation
<whitequark>
anyway, there's no fragment that corresponds to m.If in isolation
<DaKnig>
I can use it however I want
<DaKnig>
oh?
<whitequark>
a Fragment is a specific nMigen class that doesn't even exist until the Module is elaborated
<whitequark>
`a` contains an AST for that expression
<whitequark>
but there are no ASTs that represent an If statement alone
<whitequark>
because If/Elif/Else lowers to an ast.Switch (which is not generally used directly)
<DaKnig>
ok I was confused. I meant AST.
<whitequark>
the point of a Module is to hold an FSM and bits of intermediate state that determine how If/Elif/Else is eventually transformed to a Switch
<DaKnig>
ah.
<DaKnig>
I thought that was simple.
<DaKnig>
that's why it's so ... out of place and weird.
<DaKnig>
by default, `m.next` in `m.FSM` is "stay in the current state", right?
<whitequark>
yeah
<DaKnig>
generally speaking, a Memory unit with multiple write ports would be slower than a Memory unit with one write port, right?
<whitequark>
a Memory with multiple write ports isn't synthesizable
<whitequark>
well, not as BRAM with most (all?) commercial an OSS tools
<whitequark>
i'm not sure which tools can synthesize it as FFRAM
<DaKnig>
.. crap.
<DaKnig>
well I guess I can run the logic at x2 slower clock rate
<DaKnig>
I can use write ports and read ports at different clock domains , right?
<whitequark>
there is a trick to get multiple write ports
<DaKnig>
whitequark: what about the question with different domains?
<DaKnig>
thanks for the article! will read
<whitequark>
re half rate: this is also a valid technique! Xilinx UltraRAM works that way
<whitequark>
well, they run the memory at 2x the logic rate instead, but same idea
<DaKnig>
so they have a PLL inside wach BRAM?
<whitequark>
i don't know how it's implemented, actually
<yuriks>
DaKnig: still working on that queue stuff?
<DaKnig>
yuriks: the one with multiple producers?
<yuriks>
mhm
<DaKnig>
I think I solved it ; kinda.
<awygle>
it's probably multi-edged
<awygle>
at least that's my guess
<yuriks>
just curious about how you end up doing it
<whitequark>
DaKnig: re different domains: you can do that as long as you synchronize things somehow
<whitequark>
you can add some logic that prevents simultaneous reads and writes
<whitequark>
or, you can add a 2FF synchronizer to the read port
<DaKnig>
I just have a FIFO where producers write to a temp thing, then in order they get into the fifo.
<whitequark>
oh
<whitequark>
try an AsyncFIFO then?
<DaKnig>
whitequark: I dont care about simultaneous reads and writes tbh.
<whitequark>
awygle: yeah that's my guess too
<DaKnig>
this never happens.
<awygle>
Probably asyncfifo is what you want DaKnig
<yuriks>
DaKnig: so each producer has a fifo, then you round-robin feed those into another single fifo for the consumer?
<DaKnig>
wait; there are two things I am asked about at the same time.
<awygle>
whitequark: this is not a pressure thing just a "you didn't get notified last time" thing - I did submit updates to the value castable pr
<DaKnig>
yuriks: turns out (after some prototyping) that in my problem the data is produced very slowly. and is consumed equally slowly. what I decided to do is to have a buffer for all the producers, then round robin write em into a fifo, then round robin read from fifo into the consumers
<DaKnig>
... is that even sensible lol
<DaKnig>
I hope so
jeanthom has joined #nmigen
<DaKnig>
async fifo is a fifo where both sides have different clock domains, is that correct?
<awygle>
yes
<awygle>
it's the closest thing to a "fire and forget" way to cross clock domains that i'm aware of
<whitequark>
awygle: yup, seen it
<whitequark>
going to merge soon, i think; there's some docs that aren't clearly worded but i'll just rephrase them myself
<awygle>
mk, sounds good
<awygle>
like i said just making sure
<awygle>
once that goes in i'll rebase and wrap up my "move record to valuecastable" pr
<whitequark>
yup, sounds good
<DaKnig>
I have now multiple clock domains in the same module; what's the way to pass those around?
<DaKnig>
to allow me to connect them correctly from the outside
<whitequark>
by default, clock domains are global to the entire design
<DaKnig>
well I guess the guide calls them "control domains"; my question stands
<whitequark>
you can use them anywhere
<DaKnig>
wdym "global to the entire design"?
<whitequark>
say you do `m.domains += ClockDomain("foo")`
<whitequark>
you can use `m.d.foo +=` or `ClockSignal("foo")` or anything else that *refers* to `foo` anywhere in the design
<whitequark>
as long as the module which *adds* `foo` is somewhere in the hierarchy
<DaKnig>
so when a submodule is added, the "parent" adds all the missing clock domains to itself?
<DaKnig>
is that correct?
<whitequark>
mm, you could describe it that way
<DaKnig>
ok then how does it actually work inside?
<whitequark>
after elaborating the design, all clock domains are propagated "down" (to submodules), and non-local clock domains are propagated "up" (to parent modules)
<whitequark>
(a local clock domain is created as ClockDomain(local=True))
<DaKnig>
so technically I could add `m.domains += ClockDomain("foo")` to a higher module and then in a module that is lower just use `m.d.foo` without declaring it?
<whitequark>
not just "could"; you have to do that
<whitequark>
otherwise it'd be two different domains
<awygle>
the convention is to have submodules use sync for everything and then use DomainRenamer to connect them to different clock domains higher up the hierarchy
<DaKnig>
awygle: in my case a domain uses two clocks.
<DaKnig>
whitequark: ok thanks!
<yuriks>
DaKnig: I think that's essentially what I said? unless I misunderstood the buffers (I'm assuming they're local to each producer?)
<yuriks>
also are you doing strict round-robin or are you doing a priority thing where you consume/feed to any available one but use the round-robin order as tie breaker? you should probably do that
<DaKnig>
I dont care about the order :)
<yuriks>
mhm, I just mean, if you're using strictly round-robin then you're wasting a bunch of cycles where you could be pushing or popping something instead
<DaKnig>
any examples for async fifo with nmigen?
<awygle>
from nmigen.lib.fifo import AsyncFIFO, AsyncFIFOBuffered
<awygle>
i don't know of any particular examples for usage
<awygle>
at least not in the examples/ directory or anything
jeanthom has quit [Remote host closed the connection]
jeanthom has joined #nmigen
<lkcl>
whitequark: that's a fascinating resource on multiple write ports.
<DaKnig>
the xor trick is very interesting!
jeanthom has quit [Ping timeout: 256 seconds]
<awygle>
xor best gate, don't @ me
<DaKnig>
I agree wholeheartedly
<DaKnig>
if somebody can send me code that uses AsyncFIFO in nmigen, I'd really appreciate that.
<_whitenotifier-f>
[nmigen] BrettRD commented on issue #492: How do you make a bounded up-down counter without modulo? - https://git.io/JUsZn
<_whitenotifier-f>
[nmigen] BrettRD closed issue #492: How do you make a bounded up-down counter without modulo? - https://git.io/JUII0
<DaKnig>
so basically when the reading side from an AsyncFIFO wants to read, they just read the `AsyncFIFO(...).r_data` and `AsyncFIFO(...).r_en.eq(1)`, right?
<DaKnig>
this means one can "peek" without actually reading the value
<awygle>
yep
<awygle>
r_en is basically "consume this value"
<DaKnig>
awygle: looking at the example code you provided, it looks like all the wires are driven in comb; so what clock domain does the AsyncFIFO update on?
<DaKnig>
can I specify this in some way?
<vup>
DaKnig: you give it a r_domain and a w_domain parameter
<awygle>
yeah you pass them in, r_domain and w_domain
<vup>
the read side lives in r_domain, the write side in w_domain
<awygle>
idk why i don't have that in that example
<DaKnig>
isnt it better to specify this explicitly?
<vup>
well it defaults to read and write, if those suit your needs its probably fine to not specify them
<DaKnig>
defaults to read and write?
<vup>
r_domain defaults to "read" and w_domain defaults to "write"
<DaKnig>
ah domains with those names... ok
<vup>
yes
<yuriks>
huh, the way that clock domains have dynamic scope (as opposed to signals which have static scope since you need to pass them into the module) is kinda weird now that I think of it