Catherine[m] changed the topic of #amaranth-lang to: Amaranth hardware definition language · weekly meetings on Mondays at 1700 UTC · code https://github.com/amaranth-lang · logs https://libera.irclog.whitequark.org/amaranth-lang · Matrix #amaranth-lang:matrix.org
urja has quit [Read error: Connection reset by peer]
urja has joined #amaranth-lang
Degi_ has joined #amaranth-lang
Degi has quit [Ping timeout: 250 seconds]
Degi_ is now known as Degi
urja has quit [Read error: Connection reset by peer]
urja has joined #amaranth-lang
urja has quit [Read error: Connection reset by peer]
urja has joined #amaranth-lang
urja has quit [Read error: Connection reset by peer]
urja has joined #amaranth-lang
d1b21 has joined #amaranth-lang
d1b2 has quit [Read error: Connection reset by peer]
d1b21 is now known as d1b2
jjsuperpower_ has quit [Ping timeout: 245 seconds]
<robtaylor> cool: https://librecar.dev/
<_whitenotifier-6> [amaranth] whitequark commented on issue #834: the recommended way of adding metadata to _AggregateMeta fields? - https://github.com/amaranth-lang/amaranth/issues/834#issuecomment-1638522354
<whitequark[cis]> it is time for our weekly Monday meeting
<whitequark[cis]> who's attending today?
<jfng[m]1> o/
<Chips4Makersaka4> me
<povik> where do you meet?
<cr1901> I'm here in the BG, probably read-only mode. I forgot about the meeting save for an alarm and am deeply distracted.
<Wanda[cis]> povik: right here, it's an irc / matrix meeting
<povik> ah, so i happen to be in the meeting too!
Pat_D has joined #amaranth-lang
<povik> no agenda from me though :)
<whitequark[cis]> the meetings are open for participation
<whitequark[cis]> the agenda is determined in advance, it's issues tagged meta:nominated
<whitequark[cis]> however if we have spare time, we can discuss anything people raise
<whitequark[cis]> jfng: is the RFC in a state ready for discussion yet, or are you still working on it?
<jfng[m]1> we should be able to pick up where we left of last time
<jfng[m]1> iirc, we were about to discuss register storage
<whitequark[cis]> ah, yes
<whitequark[cis]> jfng: I talked to you about it in a call following the meeting, right?
<jfng[m]1> yep, we talked about use cases for reserved fields
<whitequark[cis]> I remember very little of it, I was very tired; I think you have it written down though?
zyp[m] has left #amaranth-lang [#amaranth-lang]
zyp[m] has joined #amaranth-lang
<galibert[m]1> I’m vaguely here :-)
<jfng[m]1> the result of our talk was that i should rewrite the "reserved fields" section of the RFC based on example use cases, rather than presenting mechanisms (write 0, write last read), as it is currently unclear in what situation they apply
zyp[m]1 has joined #amaranth-lang
<jfng[m]1> eg, ResRW0 can be useful for chicken bits, ResRWL may be inappropriate in cases where read values are undefined (we didn't talk about it, but e.g. Phillips LPC2000 mcus have such reserved fields)
<galibert[m]1> Please define stuff, always
<jfng[m]1> i haven't found time to properly rewrite the reserved fields section, though
<galibert[m]1> 0,1,memory,configurable, whichever, but no X
<whitequark[cis]> I don't think that's always viable considering we want to make it feasible to implement peripherals compatible with 3rd party ones
<jfng[m]1> a sticking point last meeting was the necessity of doing RMW cycles when dealing with a reserved field with a write-last-read policy
<galibert[m]1> Defining something undefined should not cause incompatibilities?
<whitequark[cis]> it can cause incompatibilities across versions
<jfng[m]1> when going through datasheets of e.g. STM32, reserved fields are noted "reserved, must be kept at reset value", and have a defined reset value most of the time
<zyp[m]1> I think what we arrived at last meeting is that there ought to be three kinds of reserved fields, since they have different tradeoffs and different reasons for existing
<jfng[m]1> now the question would be, "will the vendor promise to keep the same reset value in future revisions", or at least give it a sensible behavior (e.g. no-op)
<Chips4Makersaka4> Reserved means that in future the bit may get functionality.
<Chips4Makersaka4> IMHO
<jfng[m]1> zyp[m]1: what was the third already, ResRW1 ?
<zyp[m]1> a reserved field has two properties; what you can assume about the value when you read it, and what you are expected to do when you write it
<zyp[m]1> the third was read as zero, write any, used for defined but unimplemented fields
<galibert[m]1> Note that I essentially never seen real reserved stuff to work as memory
zyp[m] has left #amaranth-lang [#amaranth-lang]
<galibert[m]1> Undocumented registers yes, reserved meh
<zyp[m]1> whether a reserved field actually holds state or not is orthogonal to the read/write policy
<galibert[m]1> Really?
<zyp[m]1> naturally, the whole point of a write policy is that even if it ignores writes now, it might not in the future
<whitequark[cis]> ^ yes.
<galibert[m]1> Random vendor can do anything in the future, you have zero way to control that
<jfng[m]1> <zyp[m]1> "the third was read as zero..." <- so for example, two different timer peripherals, where both would use registers with the same layout, except some fields may or may not be unimplemented
<cr1901> I'm not convinced backwards compat is worth it. Could there be a way to detect that reg fields have changed and do a recompile cycle?
<zyp[m]1> no, it should be possible to decouple software from gateware completely
<galibert[m]1> huh? That's essentially not possible, or it would have been done ages ago
<galibert[m]1> Pretty sure I don't really understand what you mean
<cr1901> I don't typically recompile gateware but not the software
<zyp[m]1> what I mean is that you can't expect that software and gateware are always built together in an integrated build process
<jfng[m]1> oh yeah, so if you remove a field in a silicon revision, you could replace it with a ResRWA placeholder, to avoid recompiling
<zyp[m]1> and it should be possible to revise gateware without breaking existing software builds
<cr1901> Also remind me: Is "writing a reserved bit that becomes defined" the only problem, or can it also be "reading a reserved bit that eventually becomes defined"?
<Chips4Makersaka4> Isn't that the point of a reserved field ? E.g . possibility to allow to give the bit a function without breaking backwards compatiblliity with existing software ?
<cr1901> Yea, that makes sense in C world where libraries are worth a damn. My impression is amaranth will be mostly Rust-based, where a recompile cycle happens, oh, every six weeks. And you can't really distribute libraries if they have generics
<cr1901> jfng[m]1: I understand if this is a lot of work/can't be done right now, but I'd love to see a matrix of "failure modes" for "what happens when a bit pattern is written/read to/from a field that changed meaning between versions"
<jfng[m]1> zyp[m]1: i'll add this example to the RFC, as rationale for a `reserved, read 0/write-any" field
<whitequark[cis]> cr1901: if you recall, Chipflow, which is currently sponsoring most of Amaranth development financially, is a company that produces ASICs for customers
<whitequark[cis]> and of course you cannot guarantee that all of the software is built at the same time as the ASIC
<whitequark[cis]> in fact you may not even always know that a new revision has shipped and is being installed at the assembly line
<galibert[m]1> Personally I'd tend to simplify all that as in "reserved fields are read 0/read 1 and write ignored, if you want memory behaviour present it as a register and just don't use the written value"
<galibert[m]1> Amaranth does not have the "undefined" concept in any case
<whitequark[cis]> your frustrations about Rust are not welcome to be aired during Amaranth meetings discussing unrelated matters
<zyp[m]1> and yes, reserved fields have a read policy as well
<zyp[m]1> in practice there's two options; either you can assume that the register will read as 0 or you're not allowed to assume anything at all and have to mask it out
<zyp[m]1> the former goes for fields that are expressly reserved, and fields that could be added with a reset value of 0
<whitequark[cis]> cr1901: (responding to "I understand if this is a lot of work...") this is essentially what I proposed JF add to the RFC the last time we talked about it, two weeks ago or so
<whitequark[cis]> galibert: Amaranth will definitely gain an "undefined but specific bit value" at some point, this is required for simulating ASIC memories
<whitequark[cis]> (also for some other things, but ASIC memories are the place where you can't avoid it)
<galibert[m]1> Catherine: I hope that will be an initialization state and not something that you can write to a signal
<jfng[m]1> yeah, the reserved field section must be turned upside-down, to provide solution to specific scenarios, rather than just listing features
<whitequark[cis]> galibert: there is no real difference between the two besides "how easy it is to make such a write as a user" since you can always just make an uninitialized (i.e. reset_less) register and assign from it
<whitequark[cis]> nonexistent .eq('x) becomes .eq(Signal(reset_less=True))
<galibert[m]1> Catherine: lalalalala I can't hearrrrrrr you
<galibert[m]1> (you right, but still :-P )
<whitequark[cis]> no, we should not put 'x in the prelude of course
<cr1901> Fine re: frustrations. And recompiling indeed doesn't help w/ the ASIC case.
<galibert[m]1> * (you're right,
<whitequark[cis]> cr1901: the whole compatibility story is solely for the ASIC case, practically speaking; for FPGAs you almost always do want an unified build process just because it's so hard to keep track of versions otherwise, and because the bitstream builds the longest
<whitequark[cis]> even with C, the BSP will be generated, and if you're using a non-hermetic system like, say, make, that's bad news for you
<galibert[m]1> Feels annoying like a NaN actually, but anyway, it's not the primary topic of discussion
<whitequark[cis]> it is behaving almost exactly like NaN in terms of its truth table, actually
<galibert[m]1> Yup, I noticed :-)
* cr1901 learned the term non-hermetic
<whitequark[cis]> there is nothing you can do about it unless you can come up with SRAMs that have the same area but can magically be reset, and implement this in the OSHW memory generators
<galibert[m]1> | 1 and & 0 de-NaN
<galibert[m]1> Catherine: so... magic?
<jfng[m]1> do you have other thoughts wrt register fields, or should we move on to register storage ?
<jfng[m]1> (or lack-thereof, btw)
<cr1901> I still don't think "force RMW for compat" is... great. Maybe the failure mode matrix diagram would help me get my bearings. But I don't have any better ideas, so no more comments.
<galibert[m]1> Just one: reserved fields should not be over-thinked
<whitequark[cis]> I actually think the backwards compat story is pretty important, considering how spectacularly wrong vendors tend to get it
<jfng[m]1> i think that the most important point is that every usecase that we care about is identified, and properly handled
<whitequark[cis]> yeah
<galibert[m]1> True, but most of the compatibility story is out of the hands of the CSR layer
<galibert[m]1> So give the tools, sure, try to force it on, won't work
<zyp[m]1> compatibility is a matter of having reasonable read and write policies, and the policies have effects on the generated BSP
<cr1901> "I don't particularly like the cost, but it works, and it's more care than most vendors put into their libraries. Getting rid of the r/w policies that cause RMW to be required probably limits the API too much. I don't have any better ideas."
<jfng[m]1> i think we should rediscuss compatibility, reserved fields etc, next meeting, once we have iterated on the RFC in this regards
<jfng[m]1> and move on to registers, as they are a cornerstone of this RFC
<galibert[m]1> Agreed
<whitequark[cis]> cr1901: I don't think that quite makes sense? the cost is paid by the software, but the presence of the policy does not require the cost to be paid, only to allow the designer to require so
<whitequark[cis]> * cr1901: I don't think that quite makes sense? the cost is paid by the software, but the policy exists in gateware and does not require the cost to be paid, it only allows the designer to require so
<cr1901> whitequark[cis]: I'm not sure I follow rn. I'll get back to you after the meeting. I want to let jfng[m]1 finish
<whitequark[cis]> sure
<galibert[m]1> Just something unclear to me, is the csr (possibly) targetting Memory-equivalent objects?
<zyp[m]1> as a designer that cares about efficiency, I'll pick the policy that says «I promise that any fields I add here have a reset value of 0, so you can just write 0 and expect it to read back 0»
<whitequark[cis]> note that we only have 5 minutes left of this meeting
<whitequark[cis]> galibert: not currently no
<whitequark[cis]> at most you could have an ArrayLayout stuck somewhere
<jfng[m]1> galibert[m]1: you may create an array of CSR registers, that you could use as a memory
<galibert[m]1> Ok, so I don't see where rmw could be needed, but I'm listening
<whitequark[cis]> sorry, do you mean Memory as in the Amaranth Memory class?
<galibert[m]1> yeah, as a representative of mlab, m10k and equivalents in other fpgas are even asics
<galibert[m]1> s/are/and/
<jfng[m]1> whitequark[cis]: oh well, so be it then..
<galibert[m]1> in contrast to "pile of FFs with bit-level granularity"
<whitequark[cis]> I think there's a misunderstanding somewhere
<whitequark[cis]> CSRs are not bit addressable
<galibert[m]1> sure, but backing storage is
<whitequark[cis]> actually, an important part of the proposal is that a single register is always read or written as a whole, atomically, no matter what interconnect exists in between
<whitequark[cis]> does that matter at all?
<whitequark[cis]> (also I don't see why you'd connect a Memory to CSRs considering that CSRs themselves are memory mapped...)
<galibert[m]1> I mean having the backing-store for a set of CSRs being a Memory
<jfng[m]1> galibert[m]1: on the peripheral side, each field can be individually written at the bit granularity (using a mask insert)
<jfng[m]1> but on the bus side, it's all or nothing
<whitequark[cis]> galibert[m]1: that's not something that is proposed or AFAIK considered at all
<galibert[m]1> Good, but then I don't see when a RMW is needed
<galibert[m]1> like, ever :-)
<whitequark[cis]> how is RMW related to the backing store of CSRs?
<galibert[m]1> Ok, I need to re-read the rfc is a working brain this time
<galibert[m]1> I must be missing a bunch of stuff
<galibert[m]1> s/is/with/
<galibert[m]1> Just ignore me for now :-)
<jfng[m]1> RMW is needed when you need to modify a single CSR field from the bus side
<jfng[m]1> as you are forced to write to the entire register, from the bus point-of-view
<galibert[m]1> ahhh, you mean rmw in the software side then?
<jfng[m]1> yep
<galibert[m]1> you usually don't even R it, you have a mirror in ram instead
<whitequark[cis]> that's not really something we can put in the BSP
<jfng[m]1> from the hardware/peripheral side, you can modify any bit without touching the others, using w_mask and w_data
<galibert[m]1> and if you don't need the full mask resolution you can always wire the bits together at the source at no cost
<Chips4Makersaka4> How far do you want to go with compatibility with odd old hardware? AFAICR the Amiga chipset had R and W register wrapped in same memroy address, E.g. if you wrote to a register it was actually a different as if you read from the location. E.g. you could not read back the register you wrote.
<cr1901> 8250 UART has the same problem
<Chips4Makersaka4> * a different register as if
<galibert[m]1> You see that annoyingly often in serial chips
<whitequark[cis]> Chips4Makers (aka Staf Verhaegen): we have discussed that with JF as something we want to support
<galibert[m]1> and in floppy drive controllers (old you said?)
<galibert[m]1> there's often a status(r)/command(w) register
<Chips4Makersaka4> whitequark[cis]: +1
<jfng[m]1> but the RFC currently doesn't support aliased registers
<jfng[m]1> but it doesn't prevent them either, at least
<Chips4Makersaka4> Maybe add to future possibilities section
<jfng[m]1> hmm, i wonder if we should support them in this RFC, or do it in a future one ?
<jfng[m]1> it would be a matter of how likely are we to paint ourselves in a corner if we don't, and how much complexity this would add
<whitequark[cis]> let's come up with an MVP and then add that
<jfng[m]1> i guess, and amaranth-soc doesn't have any release yet, so breaking changes are somewhat ok
<whitequark[cis]> I'm thinking if we could all agree on a minimum feature set in an RFC, it's easy to add minor things to it before we merge it
<whitequark[cis]> such as aliased registers
<jfng[m]1> ah, right, also fine by me
<galibert[m]1> Interfaces is going to be the big breaking change, not because it breaks things but rather because the way -soc is currently written is going to be obsolete
<whitequark[cis]> yeah
<jfng[m]1> it's going to impact most of the codebase, except the memory map stuff
<cr1901> whitequark[cis]: Mulled over your policy comment, and you're right. I've no complaints on the RFC then (other than still wanting a matrix of failure modes :P).
Pat_D has quit [Quit: Client closed]
urja has quit [Read error: Connection reset by peer]
urja has joined #amaranth-lang
Sarayan has quit [Ping timeout: 240 seconds]
<d1b2> <tannewt> @ravenslofty I'm here too if you want me to elaborate (heh) on my refactor suggestion
<d1b2> <ravenslofty> Go ahead, I suppose
<d1b2> <tannewt> So python self.i_tri_xy_a = Signal(32) self.i_tri_xy_b = Signal(32) self.i_tri_xy_c = Signal(32) self.i_tri_wz_a = Signal(32) self.i_tri_wz_b = Signal(32) self.i_tri_wz_c = Signal(32) self.i_tri_rgba_a = Signal(32) self.i_tri_rgba_b = Signal(32) self.i_tri_rgba_c = Signal(32) self.i_pnt_xy = Signal(32)
<d1b2> <tannewt> can use a list of variable names: python SIGNALS = ["tri_xy_a", "try_xy_b"] for signal_name in SIGNALS: setattr(self, i + signal_name, Signal(32))
<d1b2> <tannewt> then you can reuse it for output too
<d1b2> <tannewt> and the eq portion
<d1b2> <tannewt> you'd still need to make all of the state but it'd condense the code
urja has quit [Read error: Connection reset by peer]
urja has joined #amaranth-lang
Sarayan has joined #amaranth-lang