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 · play https://amaranth-lang.org/play/ · code https://github.com/amaranth-lang · logs https://libera.irclog.whitequark.org/amaranth-lang · Matrix #amaranth-lang:matrix.org
lf has quit [Ping timeout: 260 seconds]
lf_ has joined #amaranth-lang
<whitequark[cis]> <cr1901> "It may be niche enough that..." <- ok so... the whole point of View is to autogenerate properties for fields
<whitequark[cis]> if you are willing to write them manually you can literally just write a class
<whitequark[cis]> that is a 100% acceptable and completely reasonable thing to do. your own ValueCastable
<cr1901> I inherited from View for the actual code I used b/c Insn "almost looks" like a View (I'm gonna apply Wanda's suggestion to get rid of _Imm): https://github.com/cr1901/sentinel/commit/f6b747d85fd4103fa605a03f609a921e5236af65#diff-7cb08eb6fc7e04658a3445e76a567693bc038d49b5a9209ac029a271aca805c9R10-R92
<cr1901> Btw, why do enums not require you to use "()" to get a ShapeCastable, but my _ImmShape ShapeCastable does? https://github.com/cr1901/sentinel/commit/f6b747d85fd4103fa605a03f609a921e5236af65#diff-7cb08eb6fc7e04658a3445e76a567693bc038d49b5a9209ac029a271aca805c9R91 (Metaclasses, I guess, but Idk how it works)
<whitequark[cis]> <cr1901> "I inherited from View for the..." <- I mean, a View's sole purpose is to be generic over any layout
<whitequark[cis]> if you always have a specific layout you don't really need Viee
<whitequark[cis]> s/Viee/View/
<whitequark[cis]> you can literally have a few one line methods each returning a Cat
<whitequark[cis]> you don't even need it to be a ValueCastable tbh
<cr1901> you said earlier "so this kind of stuff is exactly what FlexibleLayout was designed for". How do I get access to the layout without a View(layout, target)?
<cr1901> And now you're saying I could've just used "a few one line methods returning a Cat". I mean fine, but do you want me to use lib.data or not? Because right now, this is the extent I can think of a use case beyond the trivial Struct/Union cases.
<cr1901> (I _really_ don't understand what you mean "if you always have a specific layout you don't really need View". Do you mean "Views are meant if you need to attach more than one layout to a given Signal?"
<cr1901> (If Views are meant to attach more than one layout to a given Signal/Value, then that means I've been abusing the Signal(Layout) functionality, because that returns a View(), and not once have I tried attaching more Views to any of those Signal(Layout)
<whitequark[cis]> sorry, will clarify once i have a full size keyboard
<cr1901> whitequark[cis]: That's fine, I'll just say I'm a bit reflexively defensive rn. "You: introduce a data structure library for aggregating data. Me: Shows how I'm using it, confident that I'm on the right path. You: No, not like that." I don't think that's your intent, but it's how I reacted
<whitequark[cis]> short answer: it's the right way to use lib.data for this, but doing this without lib.data while considering riscv instructions as something that needs less flexibility than your typical data structure is slightly more elegant
* cr1901 nods
<whitequark[cis]> and, since you're no longer using a specialized tool but the most generic one (the language itself) the immediates are now easy to express no matter the swizzle
<cr1901> Okay, I can see that; I am using FlexibleLayout as a crutch to avoid a bit (not much) of boilerplate.
<cr1901> And when you put it that way, I agree w/ both you and Wanda. And it should be easy to change
<whitequark[cis]> and since you probably just want to decode them rather than e.g. nest them into other data structures and such, it doesn't even need to be a ValueCastable
<whitequark[cis]> just a wrapper
<whitequark[cis]> so no need to care about .const, etc
<cr1901> I _might_ want to pass an Insn back to the formal module that wraps the CPU. But there's also nothing stopping me from passing back the raw bits and then instantiate another Insn with those bits.
Degi has quit [Ping timeout: 260 seconds]
Degi has joined #amaranth-lang
<cr1901> For type safety purposes, if I have a self.raw[2:7], how do I convert self.raw to an Insn.OpcodeType without creating a new signal?
<cr1901> "View(Insn.OpcodeType, self.raw[2:7])", doesn't work (TypeError: View layout must be a layout, not <enum 'OpcodeType'>)
<cr1901> Wait... I tried the cast earlier and it errored... hmmm https://amaranth-lang.org/rfcs/0031-enumeration-type-safety.html
<cr1901> Insn.OpcodeType(self.raw[2:7]) "TypeError: Attempted to convert Amaranth value to Python boolean" The hell?
<cr1901> enum.EnumView(Insn.OpcodeType, self.raw[2:7]) "TypeError: EnumView type must be an enum with shape, not <enum 'OpcodeType'>" What the fuck are you talking about?! (Probably bitching that I passed the enum class, not an instance of the class)
<cr1901> https://github.com/amaranth-lang/amaranth/blob/main/amaranth/lib/enum.py#L92-L111 Found it (You need "Foo(enum.Enum, shape=unsigned(1))")
jn has quit [Ping timeout: 256 seconds]
jn_ has joined #amaranth-lang
jn_ has joined #amaranth-lang
jn_ has quit [Changing host]
<cr1901> http://gopher.wdj-consulting.com:70/paste/8b8046cf-f8d4-425a-a4bd-f5415d548f06.txt Why does Bar not have as_shape()? Under what condition would as_shape() be callable from a plain enum? (__new__ uses py_enum.EnumMeta if a shape wasn't provided)
<Wanda[cis]> well you didn't give it a shape
<cr1901> Then why does as_shape()'s comments imply that as_shape can be called on enums that werent given shapes?
<Wanda[cis]> the lib.enum.Enum has a core property of becoming a plain Python Enum when you don't use shape, this includes not having as_shape
<Wanda[cis]> hm
<Wanda[cis]> Catherine: okay I think we have a documentation problem here
<Wanda[cis]> specifically, a bunch of stuff wasn't changed to account for 1c3227d95626f9c7bd11c82da9d2f760113a4589
<cr1901> I'm gonna try to sleep for now, but ack on possible doc issue. At least this let me refresh a bit on metaclasses (which I am baaaaaaad with)
notgull has joined #amaranth-lang
notgull has quit [Ping timeout: 260 seconds]
notgull has joined #amaranth-lang
notgull has quit [Ping timeout: 268 seconds]
<_whitenotifier-5> [rfcs] wanda-phi opened pull request #59: RFC 59: Get rid of upwards propagation of clock domains. - https://github.com/amaranth-lang/rfcs/pull/59
<_whitenotifier-5> [rfcs] wanda-phi edited pull request #59: RFC 59: Get rid of upwards propagation of clock domains. - https://github.com/amaranth-lang/rfcs/pull/59
<_whitenotifier-5> [rfcs] whitequark reviewed pull request #59 commit - https://github.com/amaranth-lang/rfcs/pull/59#discussion_r1527558412
<_whitenotifier-5> [rfcs] wanda-phi reviewed pull request #59 commit - https://github.com/amaranth-lang/rfcs/pull/59#discussion_r1527558690
<_whitenotifier-6> [rfcs] whitequark reviewed pull request #59 commit - https://github.com/amaranth-lang/rfcs/pull/59#discussion_r1527560617
<_whitenotifier-6> [rfcs] whitequark commented on pull request #59: RFC 59: Get rid of upwards propagation of clock domains. - https://github.com/amaranth-lang/rfcs/pull/59#issuecomment-2002535600
<_whitenotifier-6> [rfcs] whitequark reviewed pull request #36 commit - https://github.com/amaranth-lang/rfcs/pull/36#discussion_r1527567417
Chips4MakersakaS has quit [Quit: Idle timeout reached: 172800s]
galibert[m] has quit [Quit: Idle timeout reached: 172800s]
Lunaphied[m] has quit [Quit: Idle timeout reached: 172800s]
<whitequark[cis]> zyp: thanks! aside from one minor comment (which doesn't affect RFC semantics) I think this is now well-defined!
<whitequark[cis]> PSA: agenda for Monday meeting is RFC 36, RFC 55, RFC 54, RFC 56 (in this order)
galibert[m] has joined #amaranth-lang
<galibert[m]> So 36=async testbench, 55=lib.io components, 54=reset values on memports, 56=assymetric memory ports width
<galibert[m]> About #54, hardware actually supports that? I'm not at all sure the cyclone v does
<whitequark[cis]> some does, where it doesn't, it can be easily polyfilled
<tpw_rules> cyclone v seems to allow async reset to 0
<tpw_rules> i was digging into that. i kind of doubt it would be inferred though
<tpw_rules> galibert[m]: we probably need to work on a platform-specific memory implementation
<galibert[m]> "While it can be reasonably cheaply emulated, in the author's experience, any amount of emulation circuitry inserted automatically by the toolchain to ensure well-defined behavior results solely in complaints." -- Poor Wanda
<tpw_rules> i'd be okay with that so long as it didn't break inference. but i expect it will so that's why i suggested the opt-out
<Wanda[cis]> galibert[m]: I literally put a list of hardware support in the RFC
<Wanda[cis]> I'm almost sure cyclone v supports some of it too, but I only looked at the stuff supported by yosys
<galibert[m]> Yeah, I saw that after, sorry
<tpw_rules> that's also why i wanted to give it a whirl
<Wanda[cis]> (while cyclone v is kinda supported by yosys, the support is bad enough (particularly the memory support), that I just plain refused to deal with it when I wrote memory_libmap; it'd require nextpnr modifications to fix it)
<galibert[m]> Yeah, I'm going to go back to that at some point, sorry about it
<whitequark[cis]> fwiw, my position on RFC 54 is that it's not really optional
<whitequark[cis]> and the discussion will be about what will be merged rather than if it'll be merged
<tpw_rules> also by platform-specific i mean for quartus
<galibert[m]> "it" = the rfc?
<whitequark[cis]> closing the soundness hole
<tpw_rules> whitequark[cis]: does that mean no opt out? i was confused by "I do want to exclude the uninitialized register hole one way or another.".
<whitequark[cis]> tpw_rules: no, I mean the default behavior must be sound
<whitequark[cis]> we allow a wide range of opt-outs in the language, that's not going anywhere
<tpw_rules> okay, that makes sense
<galibert[m]> tpw_rules: default probably means init 0?
<whitequark[cis]> the default behavior as in the behavior without an opt-out being explicitly requested
<galibert[m]> Not UB in any case, which is the point
<whitequark[cis]> what happens if someone just reads the docs and uses a memory must be completely deterministic
<tpw_rules> the rfc does not seem to have an opt out as written. reset_less=True still means an init in my mind
<galibert[m]> rp = mem.read_port(domain="sync", hurt_me_plenty=True)
<whitequark[cis]> tpw_rules: so, `init=` and `reset_less=` are expected to behave exactly the same as they do for `Signal`
<Wanda[cis]> my notes on Altera memories seem to imply that the native behavior is "initialize to 0, plus optional async reset to 0" for most (all?) of their reasonably recent FPGAs
<whitequark[cis]> since read_port is basically a funny Signal
<Wanda[cis]> so sync reset, if any, will have to be emulated
<tpw_rules> Wanda[cis]: this is what i understood from reading their docs after reviewing the RFC
<Wanda[cis]> and so will non-0 init values
<galibert[m]> About 55, the ports have a direction now, why put one in the buffers, can't they just look at the one the port has?
<Wanda[cis]> galibert[m]: you literally asked for a safety mechanism, and you got one
<galibert[m]> And I'm very happy with it, because the platform can give the direction, and the platform has the information
<Wanda[cis]> direction is on the buffer, because you may legitimately want to use an inout as an input-only or output-only
<tpw_rules> whitequark[cis]: hm, looking at that, Signal has init=None but then the constructor checks and assigns it to 0 if None. i guess this is because of the compatibility with reset=?
<galibert[m]> so that's very good
<whitequark[cis]> galibert: this comes up in SPI flashes, so it's a very common thing
<Wanda[cis]> tpw_rules: this is for compatibility with various `ShapeCastable`s, where 0 may not be a valid init value
<whitequark[cis]> an SPI flash driver (not QSPI) will want to have three outputs and one input. a (Q)SPI flash platform resource has four inouts
<Wanda[cis]> so None just means "default"
<galibert[m]> ok, reduction makes sense. Very good reason. Is it possible to omit it when you want the direction of the port?
<tpw_rules> Wanda[cis]: ah, i see. so overloading init=None for memory would not necessarily work
<whitequark[cis]> galibert: no, and I want it to be explicit in the driver code
<Wanda[cis]> tpw_rules: it cannot possibly work, because it's already taken, yes
<whitequark[cis]> among other things, this will make SimulationPlatform possible without explicitly defining resources
<whitequark[cis]> but even if not that: resources and drivers are basically completely decoupled, as in they will often be made by different people at different times
<whitequark[cis]> each of them should specify a direction explicitly for it to work well as a safety mechanism
<galibert[m]> Catherine: interesting, ok, makes perfect sense. I'm merge on 36, 55, 54, 56 in case I'm late at the meeting
<whitequark[cis]> thanks
<tpw_rules> did github implode or my internet
<whitequark[cis]> works for me
<galibert[m]> works for me too
<whitequark[cis]> Wanda: slightly cursed: platform allows `dir="oe"`
<whitequark[cis]> would that create a SingleEndedPort with direction=Direction.Output?
<Wanda[cis]> oh right, I was wondering what to do about it, but then forgot
<Wanda[cis]> well
<Wanda[cis]> given our definitions, Direction.Output actually corresponds to 'oe', so yes
<whitequark[cis]> sgtm
<tpw_rules> Wanda[cis]: is there an implementation of rfc 54 available to try now?
<Wanda[cis]> or do you think there are usecases for enforced always-on outputs?
<whitequark[cis]> Wanda: not on FPGAs I think
<whitequark[cis]> all of them are tristated anyways while the bitstream is being loaded
<whitequark[cis]> so it's not like you can guarantee that
<Wanda[cis]> tpw_rules: not yet; I think I can cook one up reasonably quickly though if you want it soonish
<galibert[m]> For the internal ports which could make sense to be published by the platform as a port, there are a numbers that don't have an enable
<Wanda[cis]> (there's a bit of a problem in that it's not implementable properly right now, in that we don't really have a good way for them to respect ResetInserter yet)
<whitequark[cis]> galibert: by internal ports do you mean like HPS?
<Wanda[cis]> galibert[m]: what internal ports? because if you're talking about HPS things again, I'd very much argue they are not I/Os and should not be treated as such
<tpw_rules> Wanda[cis]: i'm concerned that accepting it without having a method of specifying the old behavior (an undefined initial value) will break my quartus stuff. i wanted to try an implementation to see if that concern was founded
<whitequark[cis]> tpw_rules: note: we do not plan to merge the implementation of RFC 54 in Amaranth 0.5
<whitequark[cis]> just to avoid unnecessary disruption
<galibert[m]> HPS sure, but there are others around fpga init, jtag connection, other stuff of that kind
<Wanda[cis]> tpw_rules: okay I can cook something testing-grade up
<tpw_rules> whitequark[cis]: i see, okay. that would give time to offload to a platform-specific memory implementation
<tpw_rules> is there a wish at least for the 0.5 release? i'm still keeping the DSP stuff in the back of my mind and would like to see that fixed before then
<tpw_rules> wish of a date
<galibert[m]> There is a bunch of hard blocks in the cyclone that are not hps
<Wanda[cis]> galibert[m]: what others? because JTAG is definitely not accessed in an I/O-like way
<galibert[m]> and a tend to be just a collection of... stuff
<galibert[m]> lemme check more precisely then
<whitequark[cis]> tpw_rules: no specific dates
<Wanda[cis]> so what? RFC 53 is specifically about I/Os, it's not replacing normal ways of making components such as, you know, Components
<whitequark[cis]> I don't think we have any way to stick to a specific date anyway, given how much we rely on volunteer labor
richardeoin has quit [Ping timeout: 252 seconds]
<tpw_rules> there are those bizarre RGB LED pins in some of the ice40 variants
<whitequark[cis]> galibert: any hard IP should be wrapped in a `Component` and, probably, get its own non-`request` function on the platform
<whitequark[cis]> that is by far the most reasonable option
<Wanda[cis]> tpw_rules: I think those don't qualify as general enough to use `lib.io.*Buffer` anyhow?
<whitequark[cis]> yeah, those RGB LED pins are OE-only I think?
<whitequark[cis]> which we can't actually express with the current platform layer either iirc
richardeoin has joined #amaranth-lang
<tpw_rules> they say they can be used as user i/o but i think that's the case
<tpw_rules> (oe only)
<Wanda[cis]> wait, oe only? wtf
<galibert[m]> Catherine: ok. I was thinking about that block that's pretty much "everything we didn't put anywhere else", but I barely RE-d it. It's weird.
<whitequark[cis]> is it documented?
<Wanda[cis]> galibert: name?
<galibert[m]> It's exploded into multiple Instance in quartus, which is a good idea
<galibert[m]> "CTRL" is the underlying name, you have it in the mistral doc
<Wanda[cis]> and which, if any, features of it actually deal with controlling external I/O pads in ways that would make sense to connect to a *Buffer?
<galibert[m]> But yeah, putting a buffer about it probably doesn't make any sense
<galibert[m]> s/about/around/
<galibert[m]> Yeah, I agree with you, I get your point now
<galibert[m]> thanks
<Wanda[cis]> the question here is: are there platforms where having separete "always-on output" and "output with enable" kinds of buffer makes sense?
<tpw_rules> galibert[m]: random q: do you know of a secret way to change the MSEL strapping from the HPS
<Wanda[cis]> relating to actual, you know, pads
<galibert[m]> tpw_rules: no, msel happens before any bitstream is loaded
<tpw_rules> galibert[m]: basically i want to have the HPS boot from FPGA then change things so the HPS can reload the FPGA. but it seemed not possible because of MSEL
<tpw_rules> unless i somehow rewired the board to attach pulls to user i/o or something
<Wanda[cis]> I find it not out of the question; I do know of one FPGA platform that can do output-only but not output-enable, but it's... uhhh I'm not sure it actually exists
<galibert[m]> the hps can't reload the fpga if it was booted from there?
<Wanda[cis]> specifically, it's the FPGAcore from Xilinx
<tpw_rules> galibert[m]: well the fpga needs to boot from flash so the HPS can boot from it
<tpw_rules> but they have conflicting MSEL settings
<galibert[m]> Wanda: do you want to be able to express "In this specific implementation of the fpga in context of this platform board, that pin is open-collector, you control oe only"?
<Wanda[cis]> I was also wondering how to deal with open collector, yeah...
<Wanda[cis]> the thing is... it's not clear how to deal with it
<Wanda[cis]> Xilinx has a dedicated OPEN_DRAIN mode
<galibert[m]> I thought the hps had memory-mapped ports to reload a bitstream?
<Wanda[cis]> wherein you actually control the O pin, not OE
<tpw_rules> galibert[m]: it does, but they require the MSEL pins to be in a not-active-serial state
<Wanda[cis]> (it simply disables the P transistor of the output buffer with some config bits (or N, I forgot which is which))
<galibert[m]> tpw_rules: I didn't know that, it's weird
<whitequark[cis]> the P one
<galibert[m]> N connects to gnd, P to +
<tpw_rules> galibert[m]: so you can have MSEL set so the fpga can boot off a serial config memory in active serial mode, OR have it so the memory mapped ports work (which sets some parallel load mode i think). i'd really like to be able to switch from the FPGA or HPS
<Wanda[cis]> ie. I don't consider this matter to be an easy decision, so I left it off the RFC
<Wanda[cis]> I'm open to adding output-only mode because effectively we already had this functionality and it's easy to add; addint open-collector support in an RFC that's about refactoring things is out of question
<whitequark[cis]> I actually feel that removing the dedicated output-only mode improves things
<galibert[m]> Could we ask the next evolution of the platform to do OPEN_DRAIN on xilinx and setup o=0, oe=o on Altera (and most others)? And have the pin appear as i+o without oe on the other side?
<galibert[m]> e.g. normalize in the platform to something that makes sense?
<galibert[m]> (not for this version of the rfc of course)
<whitequark[cis]> what is the point?
<whitequark[cis]> it does the exact same thing as OPEN_DRAIN
<whitequark[cis]> I mean, o=0, oe=o does
<galibert[m]> that you can use the same code on Xilinx and Altera and sim?
<whitequark[cis]> but you can already use o=0,oe=o on Xilinx
<whitequark[cis]> it drives the buffer in the same way
<galibert[m]> So OPEN_DRAIN has no good reason to exist in fact?
<Wanda[cis]> good question
<Wanda[cis]> I think its selling point is that you can use SERDES on o, but you cannot on oe
<whitequark[cis]> oh, it looks like they removed OPEN_DRAIN in Spartan 7
<Wanda[cis]> or at least not the fastest modes
<Wanda[cis]> yeah, I recall it was supported only on some FPGAs
<Wanda[cis]> very hw-specific
<Wanda[cis]> don't remember which ones though
<whitequark[cis]> that seems like a support nightmare tbh
<whitequark[cis]> if you have that specific hw and need that particular serdes config, instantiate them directly
<whitequark[cis]> if you have serdes you probably won't use lib.io buffers anyways
<Wanda[cis]> (but also, I'm pretty sure that the underlying hardware does actually support it on ~all FPGAs more recent than OG virtex; it's literally setting one half of drive strength to 0ma)
<whitequark[cis]> huh
<Wanda[cis]> like, the IOB has a set of variously-sized P and N transistors, and you can select an arbitrary subset of them to fine-tune the drive strength; setting the set of enabled P transistors to "none" is how this thing is implemented
<galibert[m]> It still could be interesting eventually be able to say "That port is open collector", so that stuff like i2c can be sure they're talking to a correct pin
<whitequark[cis]> Wanda[cis]: not a set of identically sized P/N transistors? (also I guess the P ones are bigger)
<Wanda[cis]> no, they're different sized
<whitequark[cis]> interesting
<Wanda[cis]> like a progression of powers of two, I think?
<Wanda[cis]> roughly
<galibert[m]> So every pin is a DAC?
<whitequark[cis]> current mode DAC
<galibert[m]> yeah
<Wanda[cis]> it can be a voltage mode DAC!
<Wanda[cis]> you can enable the same transistors as termination when the IOB is in input mode
<Wanda[cis]> and then you get to enable both P and N transistors simultanously
<galibert[m]> annoyingly I don't know any fpga that allows to change the drive strength live
<Wanda[cis]> (note: of this part I am only sure on Spartan 6)
<whitequark[cis]> Xilinx does, via the DRP
<Wanda[cis]> galibert: Spartan 6 can
<galibert[m]> Cute
<Wanda[cis]> via the really annoying serial-based DRP
<Wanda[cis]> that is S6-specific
<galibert[m]> Is spartan 6 able to change voltage on sd cards on the fly that way?
<Wanda[cis]> the feature is actually used in their hard memory controller block
<galibert[m]> that would be... probably extremely cursed
<Wanda[cis]> no; output voltage is determined by the external VCCIO rail
<Wanda[cis]> you could manipulate that via external circuitry and reconfigure IOBs to match though
<Wanda[cis]> (this is absolutely unsupported by Xilinx, but the hw could do that in theory)
<galibert[m]> It's sad that the fpgas I see have no provision to do the sd card voltage change dance
<whitequark[cis]> re open drain (not open collector please, we don't use TTL for a while) pins: while it looks reasonable for simple cases like I2C, things get more complicated elsewhere
<whitequark[cis]> for example, consider an SPI resource. it's fairly unambiguous that you would have COPI and CIPO as output and input, right?
<galibert[m]> at first sight, yes
<galibert[m]> but then somebody committed crimes?
<whitequark[cis]> well... maybe not. it's actually pretty reasonable for an SPI controller to enable COPI only when it's actively pushing data to the device, rather than just clocking data out
<whitequark[cis]> because there are devices where you basically connect COPI and CIPO and then you can save a wire by connecting them together
<whitequark[cis]> so a generic SPI controller could conceivably support this by enabling COPI iff you are doing a write
<galibert[m]> yeah, crimes
<whitequark[cis]> basically, I feel like "output" and "input" should be about electrical rules
jfng[m] has quit [Quit: Idle timeout reached: 172800s]
<whitequark[cis]> because in that case, yes, there is a good argument about safety. a well designed board won't give up smoke in any case but it's no good to have outputs fighting
<whitequark[cis]> logical rules however can get really complicated. also, for an SPI peripheral implemented in an FPGA, it should definitely tristate CIPO when not selected at least
<galibert[m]> yeah, shorts are bad (on boards, your clothes are your problem)
<whitequark[cis]> since then you can parallel devices with one-hot multi-bit CS, which is very widely recognized
<whitequark[cis]> so what direction should CIPO be, with fine grained directions? right now we actually don't have a platform dir="?" for it at all
<whitequark[cis]> for "output that can also be tristated"
<whitequark[cis]> "o" suggests "always output", "oe" doesn't let you drive high
<galibert[m]> o+oe, no i?
<whitequark[cis]> yeah
<galibert[m]> that would be the semantics
<whitequark[cis]> RFC 55 does say that "o" gives you "oe" also (default active)
<whitequark[cis]> s/"o"/`Direction.Output`/
<galibert[m]> So Direction.TristatableOutput, and how ine do we want to cut all that
<galibert[m]> s/ine/fine/
<galibert[m]> That can get annoying fast
<whitequark[cis]> I don't want fine-grained directions for exactly that reason
<galibert[m]> Yeah
<whitequark[cis]> a low-effort, high-reward ERC mechanism? sure. trying to enforce semantics? probably not
<galibert[m]> I think the current directions currently added to port are good enough to catch 99% of the typos
<zyp[m]> <whitequark[cis]> "I mean, o=0, oe=o does" <- shouldn't it be `o=0, oe=~o`?
<galibert[m]> yeah it should
<Wanda[cis]> anyway, to get the discussion back on track
<zyp[m]> question regarding RFC #55, DDRBuffer.Signature is using ArrayLayout; wouldn't it make just as much sense to use Member.array()?
<zyp[m]> i.e. i: Out(width).array(2)
kralya[m]1 has joined #amaranth-lang
kralya[m]1 has left #amaranth-lang [#amaranth-lang]
<Wanda[cis]> I think the core question here is: are there output-no-enable buffers that we wish to support?
<Wanda[cis]> because if so, we need a Direction that doesn't include 'oe', because otherwise the *Buffer implementation would somehow have to verify that the oe passed to it is always-1 for correctness, which it cannot really do in Component model
<Wanda[cis]> Catherine: you mentioned that such things exist in ASICs?
<zyp[m]> zyp[m]: or more generally, when do we want to use `Member.array()` vs `ArrayLayout` in a signature?
<zyp[m]> (interface members naturally have to be the former, port members can in practice be either)
<Wanda[cis]> zyp: I believe `ArrayLayout` is strictly superior to `lib.wiring` array, since you can eg. assign to the whole thing at once
<Wanda[cis]> and you'd usually only use member arrays for signature members
<zyp[m]> I think that's a fair argument, I just find it a bit iffy that we've got two incompatible solutions to the same problem
notgull has joined #amaranth-lang
<whitequark[cis]> <Wanda[cis]> "Catherine: you mentioned that..." <- in ASICs you basically never want `lib.io` buffers
<whitequark[cis]> you only want digital signals at the toplevel for... ASIC reasons
<whitequark[cis]> so all of this is irrelevant, neither the current platform objects, nor lib.io is going to be used at all
<whitequark[cis]> (chipflow currently replaces the platform wholesale for that reason, and uses a weird hack that IOValue is going to fox)
<whitequark[cis]> s/fox/fix/
<Wanda[cis]> huh.
<whitequark[cis]> <zyp[m]> "I think that's a fair argument..." <- these are solving different problems
<whitequark[cis]> .array in lib.wiring is for making arrays of interfaces, where the direction can vary
<whitequark[cis]> .array in lib.data is just for grouping stuff
<whitequark[cis]> there is a degenerate case where you make an array of a port member (or single-port interface member), but it's no worse than having both the ability to have an interface with only Out members, and lib.data
<whitequark[cis]> whether you want one or the other depends on whether you want the additional typechecing provided lib.wiring
<Wanda[cis]> hrm
<Wanda[cis]> I wonder if there are obscure cases in which, essentially, OBUF is valid but OBUFT is not
<Wanda[cis]> like weird IOSTANDARDs
<Wanda[cis]> there's definitely IOSTANDARDs where xilinx wants you to use either an output or an input, but not both; still, OBUFT seems to be valid for those
<Wanda[cis]> so... my concern here is that if it turns out that we actually do need a distinction between Output and TristateOutput after all, retrofitting it will be really messy
<Wanda[cis]> (the MIPI D-PHY IOSTANDARD on Ultrascale cannot support tristate for output, but it doesn't count since it has weirdass buffer primitives anyway that cannot be handled by generic code)
<whitequark[cis]> we don't expect this to somehow turn out to be *common*, do we?
<Wanda[cis]> common? not really
<galibert[m]> Insanity in hardware is uncommon, right? Right?
<Wanda[cis]> the possible impact I expect is "you cannot use LVDS on this FPGA family in generic code"
<Wanda[cis]> or something like this
<Wanda[cis]> ... huh, lattice also has this weird OPENDRAIN thing
<zyp[m]> I suspect there might be some special IO primitives that are output only, like ECP5's USRMCLK (which itself is moot since it's tristateable)
<Wanda[cis]> those... ehh
<Wanda[cis]> those are incredibly annoying and arguably shouldn't really be exposed as normal I/O
<zyp[m]> IMO it's valuable to have the platform handle the special casing for it, so the SPI code doesn't have to
<Wanda[cis]> like, yeah, I get what you mean, but ugh
<whitequark[cis]> I think the platform code should special-case those uncommon outputs, personally
<Wanda[cis]> special-case, as in?
<Wanda[cis]> USRMCLK is the only one for Lattice devices?
<Wanda[cis]> oh right, here is a use case: for ice40, you want to know whether oe is in fact used or not, since you need to set this in PIN_TYPE, and connecting a constant to OUTPUT_ENABLE instead wastes routing
<Wanda[cis]> I guess it can also potentially save a flop on other platforms?
<Wanda[cis]> ... flimsy reasons so far
<Wanda[cis]> ... wait, SB_IO has independent input clock and output clock, but tied input/output clock polarity? this is .... rather annoying
<Wanda[cis]> (but if I understand it correctly, we can trivially implement separate input clock polarity anyway by simply swapping D_IN_0 and D_IN_1
<Wanda[cis]> * (but if I understand it correctly, we can trivially implement separate input clock polarity anyway by simply swapping D_IN_0 and D_IN_1)
<Wanda[cis]> wtf is SB_IO_OD, why does this thing exist
polysci_00232[m] has quit [Quit: Idle timeout reached: 172800s]
<Wanda[cis]> ... oh, it replaces those high-drive pins when they're not high-driving
<Wanda[cis]> ugh.
nyanotech has quit [Remote host closed the connection]
nyanotech has joined #amaranth-lang
notgull has quit [Ping timeout: 264 seconds]
notgull has joined #amaranth-lang
<whitequark[cis]> yep