<Guest30>
Hi! learning amaranth. ran up_counter example did output the .vcd file but sim.run() shows no output anyone here who could help
Guest24 has quit [Ping timeout: 250 seconds]
<Guest30>
anyone here at all?
<Guest30>
all seems quiet on the amaranth front
<Guest30>
ok, bye all
Guest30 has quit [Quit: Client closed]
isabelburgos[m] has joined #amaranth-lang
<isabelburgos[m]>
It sounds like the simulation ran, all assertions passed, and the simulation terminated. Try putting print statements in bench() if you want to see something when the simulation runs
Degi has quit [Ping timeout: 260 seconds]
Degi has joined #amaranth-lang
MuddassirAli[m] has quit [Quit: Idle timeout reached: 172800s]
notgull has joined #amaranth-lang
notgull has quit [Ping timeout: 268 seconds]
notgull has joined #amaranth-lang
notgull has quit [Ping timeout: 252 seconds]
<Wanda[cis]>
<isabelburgos[m]> "It sounds like the simulation..." <- unfortunately, they left (after like 5 minutes)
<isabelburgos[m]>
goodbye Guest, i hope you find the answers some day
Raito_Bezarius has quit [Ping timeout: 240 seconds]
<bl0x[m]>
When compiling with amaranth commit fc85feb I get block RAM properly inferred, with commit 8c4a15a I get distributed RAM.
<bl0x[m]>
Aha, or could this be due to running an old yosys version (0.30) perhaps? Oops
<bl0x[m]>
Hm, same with yosys 0.40.
<jn>
bl0x[m]: can you export the verilog/rtlil in both versions and compare?
<jn>
and also what would be interesting is whether both versions of amaranth use the same yosys (not entirely sure how to find out, perhaps with strace)
<bl0x[m]>
yosys version is mentioned at the top of top.v, so that should be the one that is used, no?
<jn>
probably
<bl0x[m]>
how do I export the rtlil? verilog is written in any case.
<jn>
not sure (and i'm also not sure whether it's used in your synthesis flow at all, so it might be irrelevant)
<Wanda[cis]>
I claimed earlier that the relevant commit (8c4a15ab92af10d5640be4d15f27f0e8843ec154) should be effectively NFC as far as synthesis is concerned
<Wanda[cis]>
this turns out to be not quite true (how surprising)
<Wanda[cis]>
but the change is subtle
<Wanda[cis]>
since that commit upgrades RTLIL emitter from v1 memory cells (that have no read port initialization support) to v2 memory cells (that do), we need to emit something as the initial value of the memory read port
<Wanda[cis]>
and that something is an all-0 value
<Wanda[cis]>
we could've emitted an all-x value instead, except... the RTLIL backend doesn't even have a way to represent a constant involving x bits, and I sure as hell didn't want to add one just for this
<Wanda[cis]>
on yosys side, this interacts with a particularly cursed part of memory support in verilog backend
<Wanda[cis]>
it used to be (before I have completely overhauled yosys memory support in 2021) that a transparent read port would be represented in Verilog by a pattern involving effectively an async memory read port + a register on the address input
<galibert[m]>
and the bram does not support initialization?
<Wanda[cis]>
which 1) didn't have any way to support read port initial values and resets, 2) didn't support actual per-port transparency, 3) doesn't actually match the semantics of a sync read port when you think about it for more than 3 seconds
<Wanda[cis]>
but I also was very worried about potentially breaking things, because memory inference stuff is incredibly fragile
<bl0x[m]>
How come this didn't surface earlier? I don't exactly see myself as a power user.
<galibert[m]>
intel fpgas at least supposed init of rams
<galibert[m]>
s/supposed/support/
<Wanda[cis]>
so yosys still emits the old shitty pattern, as long as 1) you're not using any features that require the more general pattern, 2) there isn't a semantics mismatch (ie. all write ports are in the same domain)
<Wanda[cis]>
and now that amaranth started (accidentally) using memory initialization, it effectively forced the use of the more general pattern
<Wanda[cis]>
which ... is not exactly well-supported by toolchains
<Wanda[cis]>
galibert: the xilinx BRAMs do support initialization; pretty much everything does
<Wanda[cis]>
the problem is that verilog is a shit language that doesn't actually define memory inference in any way
<Wanda[cis]>
so there are no standard code sequences to represent eg. memory transparency
<galibert[m]>
Ok, I don't remember which fpga does not have init (which eventually will require supporting X in sim somehow)
<Wanda[cis]>
the yosys support for Verilog is only good enough to mostly round-trip with itself
<Wanda[cis]>
but recognition of its idioms by other software is uhh
<Wanda[cis]>
a different matter
<galibert[m]>
r/FPGA has some.. harsh words towards official fpga synthesis suites on a regular basis
<Wanda[cis]>
it's not about synthesis suites!
<Wanda[cis]>
it's the language that sucks
<galibert[m]>
Why not both?
<bl0x[m]>
Should I create an issue for this on gh?
<Wanda[cis]>
because right now we are discussing a specific issue and its causes, not pointlessly complaining about shit into the ether
<galibert[m]>
Ok, but I would have hoped vivado could have recognized both patterns as memories
<Wanda[cis]>
I literally just said that verilog doesn't have well-defined patterns
<galibert[m]>
32x8000 should ring a ton of bells, that should be entry point #1 of the heuristic
<Wanda[cis]>
yes, and?
<Wanda[cis]>
have you ever given a thought to how you'd actually implement memory inference in a toolchain?
<Wanda[cis]>
of course a 32×8000 array is recognized as a memory
<Wanda[cis]>
but to actually implement it, you need to match the pattern to the hardware
<galibert[m]>
But identifying structure and ports in the hard part?
<Wanda[cis]>
specifically, the read and write ports, yes
<galibert[m]>
or, well, projecting it on the hardware
<Wanda[cis]>
I spent a fucking year on it
<Wanda[cis]>
it is not trivial
<Wanda[cis]>
and Verilog doesn't help with it at all
<Wanda[cis]>
I also don't think I did a particularly good job at it
<bl0x[m]>
You still did it, is what counts though.
<galibert[m]>
Would that be an argument to have the platform python Instance memory blocks?
<Wanda[cis]>
Vivado does recognize the memory as a memory
<galibert[m]>
using what blocks exist on a given fpga?
<Wanda[cis]>
the problem is that it cannot match it to block RAM
<Wanda[cis]>
so it uses distributed RAM
<galibert[m]>
(altsyncram on intel)
<Wanda[cis]>
yes
<Wanda[cis]>
there are two possible answers to this mess
<Wanda[cis]>
hm
<Wanda[cis]>
three actually
<galibert[m]>
Which one does not require societally-unacceptable amounts of alcohol?
<Wanda[cis]>
1) we add code to amaranth platform support to perform memory inference in amaranth
<Wanda[cis]>
2) we add code to amaranth platform support to call the *yosys* memory inference pass (and add support for it on platforms currently missing it, like *sigh* altera)
<galibert[m]>
I think m10k and mlab are inferred
<Wanda[cis]>
3. we sit down with every proprietary toolchain and suffer until we figure out the exact verilog patterns to give it to make it infer memory correctly in all cases, then make yosys verilog backend emit it (perhaps by making it aware of the toolchain that will be reading its verilog)
<Wanda[cis]>
galibert[m]: by yosys? no, they are not.
<Wanda[cis]>
the memory inference support in synth_intel_alm is a fucking disaster
nyanotech has quit [Remote host closed the connection]
<galibert[m]>
I've seen it do it
<Wanda[cis]>
I absolutely refuse to use it in its current state
<galibert[m]>
may have been a special branch though
<Wanda[cis]>
for one, it only supports mistral, which makes it completely useless for our purposes
<galibert[m]>
I think 3) hits the "alcohol" criteria
nyanotech has joined #amaranth-lang
<Wanda[cis]>
second, it's tied to the old memory inference pass by its design
<Wanda[cis]>
it's actually the only target in yosys that still uses the old memory inference pass
<Wanda[cis]>
because lofty, over my objections, tied mistral design to the internals of the old pass
<galibert[m]>
that's annoying
<Wanda[cis]>
and when I was converting all targets to the new pass, I simply had no way to change this
<cr1901>
I'm mainly passively reading, but... Amaranth doesn't support mistral?
<bl0x[m]>
gotta go, thanks everyone
<galibert[m]>
mistral is not reliable at this point, I need to solve a bunch of problems before it can be
<cr1901>
ahhh
<cr1901>
machxo2 didn't have any memory support when I did the original PR; Wanda[cis] said memory inference rework was imminent, so I (correctly!!!) didn't think it was worth the time sink to learn how to add the old inference support. So she just did it instead lol
<Wanda[cis]>
huh
<Wanda[cis]>
I did?
<Wanda[cis]>
... sounds like something I'd do, I guess
<cr1901>
Well I certainly didn't do the memory support
<Wanda[cis]>
anyway.
<Wanda[cis]>
we have 3 options
<Wanda[cis]>
tbh I don't really like any of them
<Wanda[cis]>
the problem with option 1 is that we just plain don't have infrastructure for that
<Wanda[cis]>
there's the Platform.get_memory hook, but it's just plain not good enough to give platform the information it needs to perform memory selection
<Wanda[cis]>
(specifically, with the current approach where a read/write port is a read port + a write port that happen to have the same address, the platform has no way to ... well, actually notice that fact)
<Wanda[cis]>
(that plus it has no way to verify the set of possible read enable / write enable combinations, something that yosys uses a SAT solver for)
<Wanda[cis]>
even if we had that infrastructure (the obvious way to do it is to make a platform hook that runs on NIR level instead), it's a rather heavy chunk of work replicating a large chunk of yosys memory inference functionality
<Wanda[cis]>
the problem with option 2 is that using the yosys memory inference code would require lowering processes first, and that'd absolutely kill readability of the resulting verilog
<Wanda[cis]>
and the problem with option 3 is ... I'm not sure it's actually possible
<galibert[m]>
Would you actually have to infer? I mean, if someone doesn't use Memory and friends they're welcome to keep all 256 pieces
<galibert[m]>
or it's to notice that for instance a read and a write port are linked and they can be tucked into one physical one?
<Wanda[cis]>
galibert[m]: yosys memory inference code is what convers a Memory to actual vendor primitive
<Wanda[cis]>
yes.
<Wanda[cis]>
this is the hard part
<galibert[m]>
That could be an argument for explicit rw ports
<Wanda[cis]>
... and that brings us to option 4
<Wanda[cis]>
yes
<galibert[m]>
In a number of ways amaranth wants to be lower level than verilog for good reasons
<Wanda[cis]>
honestly, after dealing with all the bullshit involved in yosys memory inference, I just plain ... don't like the resulting design
<Wanda[cis]>
it's fragile and not very good
<galibert[m]>
Honestly I see inference with great trepidation
<Wanda[cis]>
it kind of had to be that way, because of the constraints of 1) verilog, 2) yosys verilog frontend specifically, which is an absolutely horrible piece of code
<Wanda[cis]>
like. I use a freaking SAT solver to infer things about the code.
<galibert[m]>
Yeah, that's a red flag right there
<Wanda[cis]>
which sounds very smart until you realize that I had to do this because the verilog frontend destroys the information I actually wanted to use in the first place and I have to do it all ass-backwards
<Wanda[cis]>
so, option 4: explicit rw ports
<Wanda[cis]>
this is tricky, since this thing is more complicated than you think and there are several variants of those with varying support
<Wanda[cis]>
further, this still doesn't solve the problem
<galibert[m]>
true, and even the ones I know are annoyingly complicated
<Wanda[cis]>
this simplifies any inference pass you can do, but... you still actually have to do it
<Wanda[cis]>
so actually it's like two options
<Wanda[cis]>
option 4: explicit rw ports and inference in amaranth platform code, which now becomes significantly easier
<Wanda[cis]>
or option 5: explicit rw ports and using this to make sure verilog output is acceptable to quartus / vivado / ...
<Wanda[cis]>
which are easier versions of option 1 and option 3 respectively
<galibert[m]>
option 5 is intriguing
<galibert[m]>
5 seems a lot less fragile than 3 somehow
<Wanda[cis]>
it does, yes
<Wanda[cis]>
for good reason
<Wanda[cis]>
(it still is somewhat fragile)
<Wanda[cis]>
(the difference is that now you'll only get bitten in weird cases, not in common cases)
<galibert[m]>
it tries to model code you don't control and have no insider view on, so it can't not be fragile
<Wanda[cis]>
there's also another problem with options 1, 2, and 4 which is that we never actually came up with good heuristics for choosing between various ways of implementing memories
<Wanda[cis]>
I implemented some simple algorithm that I essentially pulled out of my ass and tweaked a little until it seemed to do something somewhat reasonable on my testcases
<Wanda[cis]>
the intent was to invent some better heuristic later, once the core code got merged, but ...
<Wanda[cis]>
well
<galibert[m]>
It's hard to define "better"
<Wanda[cis]>
yosyshq is a dysfunctional company and I got completely burned out and quit instead
<galibert[m]>
Heh, there's some people I like there, or at least there was
<galibert[m]>
Never knew them personally though, no sure how they are in an actual work context
<Wanda[cis]>
I got screamed at in a meeting for, specifically, trying to make infrastructure for implementing better memory implementation selection heuristic.
<galibert[m]>
ouch
<galibert[m]>
that sounds kind of counter-productive
<Wanda[cis]>
the infrastructure in question being FPGA resource usage tracking
<galibert[m]>
isn't that, like, a basic necessity?
<Wanda[cis]>
so we can know how many BRAMs the target actually has, and tune memory implementation decisions to make best use of them
<Wanda[cis]>
well, yosys currently makes do without that
<galibert[m]>
in mistral-the-library I've been careful to make that kind of information easily accessible
<Wanda[cis]>
even so, having this information where we need it is a logistical mess
<Wanda[cis]>
lugging around a database of all supported FPGA part numbers and their BRAM count in amaranth is ... well, possible, but incredibly annoying
<galibert[m]>
there's... seven for cyclone V, but 425 different SKUs, each being one of the seven
<Wanda[cis]>
then there's the other obvious problem
<Wanda[cis]>
you may actually create that database, without effort
<Wanda[cis]>
but your amaranth design may not be the only thing on the FPGA
<galibert[m]>
True that, even if personally I tend to try to be in a world where there's amaranth only :-)
<Wanda[cis]>
so you'd need some way to actually adjust the limit when you're emitting a subcomponent or something
<Wanda[cis]>
and there we get to the real messy part.
<Wanda[cis]>
because we just plain don't have infrastructure for all that
<galibert[m]>
even counting the amount of brams used in the subcomponent is problematic
<Wanda[cis]>
it was already a problem for my yosys proposal, which has much better chances of actually having the whole design available
<Wanda[cis]>
so — I think memory mapping should happen as close to the back end as we can manage (since there we can, in principle, have the most information), making me lean towards option 3 or 5
<Wanda[cis]>
a hybrid approach is also possible
<Wanda[cis]>
where platform doesn't do full memory mapping
<Wanda[cis]>
but takes a coarse look at the memory, and emulates some features that it knows the backend cannot handle
<Wanda[cis]>
(like read port resets and inits, wide ports, ...)
<galibert[m]>
Interestingly when you use an altsyncram you can use the (default) type "AUTO" to let quartus choose what kind of memory it wants to use (m10k, mlab, possibly even FFs)
<galibert[m]>
that would be quite hybrid indeed
<Wanda[cis]>
yeah, altera is pretty unique in that
<Wanda[cis]>
which unfortunately means we cannot base our approach on that.
<galibert[m]>
too bad
<Wanda[cis]>
anyway, as for the original issue reported by bl0x
<Wanda[cis]>
in a way, the solution is obvious
<Wanda[cis]>
just plain revert the part causing problems, by switching to all-x init values
<galibert[m]>
Isn't Cat going to say you're breaking the amaranth semantics by not initing to zero?
<Wanda[cis]>
sure, this goes directly against rfc 54, but also we did commit to defering that
<Wanda[cis]>
for the explicit reason of not wanting to break inference
<galibert[m]>
Ah
<Wanda[cis]>
ship this in 0.5, worry about proper solution (for this and for rfc 54) in 0.6
<galibert[m]>
makes sense
<Wanda[cis]>
it doesn't even break all that much; it's in fpga, in practice it's going to be initted to 0 anyway