<whitequark>
note that Pin() is a bit of a misnomer, it's really a bus
<whitequark>
(but most Pin instances are 1-bit wide, hence the name)
<whitequark>
let me try to recap it, and then I'll add some docs...
<whitequark>
awygle: imagine something like a paralell flash
<whitequark>
it has an address bus (input), strobes (input), ready (output), data bus (bidi)
<whitequark>
resources are described from the FPGA perspective, so there is an address bus (20-bit, output), strobes (many 1-bit, output), ready (1-bit, input), data bus (16-bit, bidi)
<whitequark>
so it'd look something like this in the platform file:
<whitequark>
awygle: the idea is that you describe and use an external device in a similar way to how you'd describe and use an Instance of some FPGA block
<whitequark>
when you do platform.request("pflash", 0), you get a structure with cs, we, a, d fields, each of which is a Pin
<whitequark>
a Pin always has an uniform format; that is, if that Pin has an output capability, it has a .o field
<whitequark>
if it has dir="o", then it won't have i or oe fields
<whitequark>
if it has dir="io", then it will
<whitequark>
this means that e.g. input from open drain pins (dir="oe") and from normal input pins (dir="i") can be handled the same way
<whitequark>
there's more. this layer also handles XDR input (that is, registered, DDR, QDR+ I/O)
<whitequark>
you still have the Pin() you request, but it additionally has i_clk and o_clk
<whitequark>
and in the DDR+ case, it has, instead of i, i0, i1, i2, etc
<whitequark>
the platform re-registers the input when necessary so all those signals are already in your domain
<whitequark>
does this make sense?
<awygle>
sorry, had a meeting
<awygle>
what is the difference between Pins and PinsN?
<awygle>
how do i communicate "this is a DDR Pin"? when you say "registered", do you mean "a register is packed into the IOB" or "this comes in synchronous to an external clock and needs to be synchronized into the domain"?
<awygle>
other than those three, yes, it makes sense
<ZirconiumX>
awygle: PinsN is negative-true
<ZirconiumX>
Or equivalently negated/inverted
<awygle>
oh, i see. does that affect output as well? i.e. writing a 1 to "cs" in the above example puts a 0 on the line?
<ZirconiumX>
Yep
<ZirconiumX>
awygle: As for DDR, there's the DiffPairs resource and you can give it an attribute
<whitequark>
the idea with the resource layer is that all pins use logical directions
<whitequark>
er
<whitequark>
DDR doesn't have anything to do with diffpairs?
<ZirconiumX>
...Okay, sorry
<ZirconiumX>
I got mixed up
<whitequark>
awygle: "registered" means "a register is instantiated at a defined phase relationship and probably packed into IOB"
<whitequark>
not all platforms have IOB registers, eg some Cyclone FPGAs don't
<whitequark>
the gearboxing decision for any given pin is made at the point of *use*, not the point of *definition*
<whitequark>
that is, the board file describes electrical behavior of pins
<whitequark>
logic polarity, differential vs single ended, direction
<whitequark>
things you can't really change
<whitequark>
your actual gateware decides how exactly to instantiate it
<whitequark>
for example, it can downgrade dir="io" to dir="o"
<whitequark>
similarly, it can request xdr=0 (comb), xdr=1 (sync), xdr=2 (ddr)
<whitequark>
this is because in some cases you have to use DDR for reasons other than using a DDR protocol
<whitequark>
such as trying to align the phase correctly
<awygle>
okay, so this is when you call `platform.request()`?
<whitequark>
yep
<awygle>
and by "xdr" you mean "this is sampled x times per clock edge"? so like a 7:1 SERDES would be xdr=7?
<whitequark>
correct
<whitequark>
right now those aren't actually supported in platforms that have them because the phase relationship in different SERDES blocks differs, and there's no way to communicate that via Pin
<whitequark>
but I do plan to support those
<awygle>
ah, i see
<awygle>
and for a module which needs to communicate to an I/O pin, i can either take a Pin instead of a Signal for the `self.field` in the constructor, or make three Signals for i, o, oe, and hook them up at the top level?
<whitequark>
the idiomatic approach as I see it is to take a Pin or a Record of Pins in the constructor in that case
<awygle>
can i use a Pin for simulation?
<awygle>
(suspect answer is "yes")
<whitequark>
sure, it's just a bunch of signals
<whitequark>
there is no magic to it, like there wasn't any for TSTriple
<awygle>
tbf there is some magic :p it's just in the platform layer sounds like, rather than Pin proper
<whitequark>
yes
<whitequark>
the platform layer does have a bunch
<whitequark>
it's mostly just indirection, but I do agree it's kinda opaque
<awygle>
okay, thank you, i understand now (well, moreso :p)
<awygle>
i do have one other question, if you have a moment. last night i wrote this code: https://gist.github.com/awygle/ffa01cfea33a61d24e9936fd29a8222f . this is obviously invalid, because i assign to m.next outside of an FSM context, but is there a way to make something like this work? (in this instance I rewrote the state machine so that it included both RX and TX)
<whitequark>
mhm, yes, this is one of the more problematic cases
<whitequark>
right now the FSM syntax isn't flexible enough and I agree it should ideally be improved
<awygle>
fair 'nough, i've already commented on that issue lol
<awygle>
oh, is there a convenient utility way to do the rising/falling edge detection i've done there? i was looking for a .rose() equivalent or something, didn't find it, and just did it "the verilog way"
<whitequark>
there's Rose(signal)
<whitequark>
and Fell()
<whitequark>
they're in nmigen.formal but they simply generate some logic, there's nothing inherently formal-specific in them
<whitequark>
maybe they should be moved
<awygle>
ahh, okay
<awygle>
i look forward to trying out nmigen.formal
<whitequark>
:D
<awygle>
i am starting to get to the point where most nmigen design decisions make sense to me, but every time i have to learn a new concept my brain still feels like it's physically rejecting understanding. pretty sure that's a "me problem" and i have to unlearn stuff
<whitequark>
it could be, but i also do make mistakes
<whitequark>
for example, initially I insisted there will be no x (without unsafe opt-ins)
<whitequark>
turns out it's literally impossible
<whitequark>
even on ice40, the initial value of BRAM output register is undefined
<awygle>
oh sure. and once i'm confident i understand what's going on, if i think it's the wrong thing, i'll let you know :p. just gotta figure it out first so i'm not bringing you useless complaints, i'm sure you get enough of those
<whitequark>
not really, so far the feedback has been very good
<whitequark>
in general that is, yours too
<whitequark>
I'll dedicate Q1 2020 to writing docs so it should solve many of the problems that currently exist
<whitequark>
with teaching nmigen
<awygle>
that would be swell
<awygle>
as part of those docs perhaps, i'd also enjoy reading about why certain choices were made. for instance, the context managers used throughout, that kind of thing
<awygle>
"x looks like x because y"
<whitequark>
yes, absolutely
<whitequark>
design rationales are an important part of documentation
<awygle>
glad you agree (sadly not everyone does)
<whitequark>
understanding why something is designed the way it is helps people use it correctly
<whitequark>
cf. "idiomatic code"
<whitequark>
personally, i can't really use something that i don't understand the rationale for
<whitequark>
both because i refuse, and because, even if i force myself to do it, i usually miss something important
<whitequark>
this comes up a lot with silicon
<whitequark>
"this decision looks stupid" (proceeds to make a faulty design)