adamgreig[m] has quit [Quit: Idle timeout reached: 172800s]
mcc111[m] has joined #amaranth-lang
<mcc111[m]>
I am on Ubuntu 23.10. I am trying to use my terasic USB blaster with Quartus Prime Lite, which currently is showing "no device is selected" but no error message more specific. Trying to look this up, I find multiple sources explaining this device must be specially set up to grant non-Root user permissions to it. I find very specific instructions from Intel for Fedora
<mcc111[m]>
I acknowledge I would not be having this problem if I'd just got a glasgow, lol
<galibert[m]>
Try openFPGAloader?
<galibert[m]>
You just need the bitstream to not be compressed
<mcc111[m]>
I am using Quartus Prime Lite's debugging features so I do not think the openFPGAloader chain can replace it. Moreover, if Intel's support page is correct, I will need to fix the permissions even if using openFPGAloader (unless I run openFPGAloader as root, which feels unncessary)
<galibert[m]>
Ah, I see
<galibert[m]>
Well, at least you can check the permissions with openFPGAloader
<mcc111[m]>
That's a good point
<mcc111[m]>
I think I got instructions from a quartus-specific chat.
<mcc111[m]>
* quartus-specific chat so my problem may be resolved.
electronic_eel has quit [Server closed connection]
electronic_eel has joined #amaranth-lang
<mcc111[m]>
OK, I now have a udev script that worked great on my ubuntu.
<mcc111[m]>
I probably SHOULD try openfpgaloader just for practice.
<tpw_rules>
error in quartus, the timing analyzer will warn you that your max frequency possible is less than the frequency you are trying to run at
<tpw_rules>
it will still compile though
<tpw_rules>
and then you'll sort of get number 3, but really that's inviting nasal demons of the highest order because the logic circuits won't operate properly anymore
<mcc111[m]>
error in quartus not warning in quartus?
<tpw_rules>
a warning
<mcc111[m]>
cuz quartus spits what feels like over a hundred warnings per compile and i don't look at them
<tpw_rules>
it's in its own separate section. do you use the gui or cli?
<mcc111[m]>
is there an equivalent of -Werr for certain critical warnings such as "max frequency wrong"?
<mcc111[m]>
I usually use the CLI but I can use the GUI if it helps.
<tpw_rules>
i don't think so. i've seen people handle that in build scripts by grepping...
<tpw_rules>
iirc it's called a "critical warning"
<mcc111[m]>
ok. so just look for the word "critical" i suppose
<tpw_rules>
can you paste a build log?
<tpw_rules>
i'll show you where it is
<mcc111[m]>
uh, yeah i'll make one 1sec
<mcc111[m]>
sighs it did an incremental build and didn't give me any warnings. is there a way to force non-incremental from the command line? I build with quartus_sh --flow compile ap_core
<tpw_rules>
i just remove the build dir and stuff
<galibert[m]>
timing is done with quartus_sta, not the normal building
<tpw_rules>
the flow should run the timing analyzer
<galibert[m]>
and you need to have told it your frequencies, with a sdc(?) file
<galibert[m]>
dunno is amaranth generates that one and if yes how
<mcc111[m]>
I have an apf_constraints.sdc and a core_constraints.sdc
<mcc111[m]>
amaranth is not generating my project file
<tpw_rules>
yeah the analogue pocket stuff probably handles all that
<mcc111[m]>
rather, i have an existing project, handed down to me from God (analogue.co), and amaranth builds a single verilog module part thingy which inserts into that project
<mcc111[m]>
i will try a git clean xffd and build again, one second
<tpw_rules>
those Info (332119) describe the timing under various conditions and for various clocks
<mcc111[m]>
tpw_rules: what should i be looking for in there?
<tpw_rules>
if any numbers are negative the timing has failed
<tpw_rules>
there should be a message but it's not failing now
<mcc111[m]>
okay. so look for the number 332119, specifically, and if there is a line that says something other than "loading constriants file" then I have a timing overflow issue?
<tpw_rules>
quartus has a pretty good GUI that can help you debug why it has failed too
<mcc111[m]>
that's good
<tpw_rules>
no?
<mcc111[m]>
if i had built in quartus, would the critical errors be like… a particular color, or in a particular tab?
<tpw_rules>
they're purple
<mcc111[m]>
i mean, it's good if quartus has a good GUI for this
<galibert[m]>
if you change the name of the qsf, and the name of the dat (I guess your part is 8_slow_1100mv_85c since it's C8) you'll get a web page with all your timings analyzed
<tpw_rules>
it is warning that your video clock is not timing constrained
<mcc111[m]>
It was pointed out to me you could get an effect like this if you were writing the 24-bit register at the same time the receiving end were reading it.
<tpw_rules>
you'd have to share the code but i don't personally have time to sniff it at the moment
<mcc111[m]>
tpw_rules: What does that mean? Does that mean it failed the time constraint or that no constraint was set?
<galibert[m]>
the latter
<tpw_rules>
Warning (332060): Node: core_top:ic|amaranth_core:ac|amaranth_core.video_clk_div:video_clk_div|clk_reg[0] was determined to be a clock but was found without an associated clock assignment.
<mcc111[m]>
The suggested way to do the clock is to do a PLL, but in our first attempt at a analogue core she instead put a divider (current divider value is 60) on the master clock. This made running the simulator easier.
<mcc111[m]>
The last time this was discussed in here, several people said "do not build a clock out of logic, use [some library class]" (I think it was either ClockDomain, ClockSignal or EnableInserter, possibly DomainRenamer). However, because those library classes are not documented, I cannot use them.
<mcc111[m]>
is the idea that because we have built the clock out of logic, the analyzer does not have a way to know whether we are meeting its deadlines?
<galibert[m]>
yeah
<galibert[m]>
it is not able to see it's a divider
<galibert[m]>
or by how much
<tpw_rules>
it sort of can, enough to be suspicious
<tpw_rules>
but if you do a PLL that stuff is handled automatically
<galibert[m]>
well, it has a 'posedge on it, so it sees it's used as a clock
<galibert[m]>
s/'/@/
<mcc111[m]>
I see. Catherine was talking about upgrading to a PLL but ofc there are many demands on her time.
<mcc111[m]>
What is the class I would need to look at to get confidence the timing analyzer can do its job? Is it ClockDomain/ClockSignal?
<mcc111[m]>
I guess in a pinch I could understand what it's doing by reading the source?
<Wanda[cis]>
hm
<tpw_rules>
do you grok clock domains in general?
<Wanda[cis]>
so there are two ways
<galibert[m]>
you need to add a sdc to indicate the period of your generated clock
<Wanda[cis]>
you could just go with the PLL
<Wanda[cis]>
in which case you'd create an Instance of the vendor primitive
<Wanda[cis]>
which, in case of altera, I have no idea how to do
<tpw_rules>
litex has some code to do it but it's not great™
<Wanda[cis]>
or you could go with EnableInserter to use the same clock, but only on 1 out of every 60 cycles or something
<mcc111[m]>
Or, put a different way: Can a divider/"clock made of logic" be legible to the compiler/timing analyzer, or is a PLL the only option? The reason I resist a PLL is that I am running amaranth in some degraded mode where there is "no platform". This is due to Analogue's batshit build method where you do not control the toplevel, instead they provide a toplevel consisting of several dense verilog files with no comments and no stated
<mcc111[m]>
license, and the only way to use amaranth is to create a module and thread it into their sample code.
<mcc111[m]>
adamgreig[m]: Hm, and therein lies the problem. "Platform".
<tpw_rules>
frankly since you are already in the batshit analogue case, i would just use quartus's gui to generate a PLL megafunction and then feed the clocks into the amaranth toplevel
<mcc111[m]>
s/Platform/platform/
<tpw_rules>
mcc111[m]: ok to be honest i think we need to start there before continuing on with whether to use a PLL or not
<adamgreig[m]>
ah, you're just outputting verilog with no platform, so amaranth isn't generating your constraint file, so it won't work, fair enough
<tpw_rules>
particularly because that's what amaranth is centered around and what really separates it from verilog and assorted nonsense
<mcc111[m]>
tpw_rules: that's the recommended approach that the other analogue developers (who are writing in systemverilog anyway) are using
<galibert[m]>
that pll invocation has been tested on a mister and a c5g (two cycloneV, it works)
<tpw_rules>
(and what FPGAs need you to keep track of anyway)
<mcc111[m]>
tpw_rules: Is it documented?
<mcc111[m]>
In the current amaranth-lang tutorial, I find documentation of *how to use* default clock domains such as the builtin m.d.sync and m.d.comb domains. I also find explanations that you *should* use the Synchronizer objects to cross clock domains.
<galibert[m]>
either synchronizer objects or dual-port, dual-frequency rams
<tpw_rules>
that's just general educational material about FPGAs, not amaranth specific
<tpw_rules>
do you like documentation and writing? if i ramble here for 30 minutes can you help clean it up?
<tpw_rules>
(that = what clock domains are). i can explain application to amaranth too
<Wanda[cis]>
mcc111[m]: so, about that: yeah you can manually add a constraint, but... manual clock dividers are generally not considered good practice since this involves using general interconnect for clock signals, which should generally use special clock networks (with better skew and jitter characteristics)
<mcc111[m]>
I am happy to volunteer to help with the Amaranth documentation, and was going to block out some time later this month to do that exclusively for some days, if I can get "yeah we'll accept that PR" approval.
<galibert[m]>
Wanda: if quartus is not a dumbass (heh) it should route the generated signal to the clock buffer of one of the 80+ clock nets
<tpw_rules>
i'm not immediately sure it has a place in the amaranth documentation, but it could in general
<Wanda[cis]>
however, you can go with EnableInserter, which is logic-only, and relies on instead using the full-speed clock but effectively skipping cycles on it
<mcc111[m]>
I'm also happy to read whatever exists but it seems a lot of the amaranth theory/stdlib is "well we inherited that from migen, and everyone in the community came over from there"
<Wanda[cis]>
this has it's own problems, in that you still need to meet the faster clock constraints for timing analysis purposes
<Wanda[cis]>
galibert[m]: it should, yes; still, it will have to go through some of the shit interconnect before it gets to a clock root
<galibert[m]>
Wanda: at one point we need to tell the analyzer about the duty cycle of enable signals. Not going to be in quartus though...
<mcc111[m]>
tpw_rules: My knowledge on that front is very limited. The reason I am picking up this amaranth/pocket project is to learn that material.
<galibert[m]>
Wanda: sure, but at least you don't get skew
<tpw_rules>
mcc111[m]: ok. well i can ramble about it and maybe we can figure out where it might fit. i have a bunch of people here at uni i need to teach too but it's hard for me to prepare material, i like to talk and dialogue
<tpw_rules>
would you like to do that sort of now?
<mcc111[m]>
tpw_rules: It seems like at least *linking* a general explanation from the amaranth documentation would be worth it. At minimum, the fact the ClockDomain, ClockSignal, EnableInserter classes are entirely missing from the stdlib documentation seems must-fix (this is on my todo list to fix if I start writing docs myeslf)
<tpw_rules>
idk if there's a good one out there already, the textbooks i've seen aren't great.
<mcc111[m]>
tpw_rules: you are making a generous offer so i feel bad making demands but uhh would it be ok if we did it in like an hour, or at 4 PM ET or something
<mcc111[m]>
if not i can make time to do it right now
<tpw_rules>
an hour is totally fine. i'm just sitting here waiting for programs to crunch
<mcc111[m]>
ok. i will be right back. when i dropped this question i was about to go do a chore because I expected I'd get responses trickling in over following hours whereas I got many helpful responses right away lol
<mcc111[m]>
thanks fvery much
<galibert[m]>
that's a matter of luck :-)
<galibert[m]>
really depends on who happens to be there
<mcc111[m]>
indeed.
<mcc111[m]>
well, luck and current time in europe i think
<galibert[m]>
don't hesitate to use my pll code
<tpw_rules>
galibert[m]: do you happen to have amaranth blocks for the cyclone v DSPs
<mcc111[m]>
galibert: will that work "without a platform"?
<tpw_rules>
yes
<mcc111[m]>
Cool.
<galibert[m]>
mcc111: yes it will
<mcc111[m]>
brb
<galibert[m]>
tpw_rules: not yet, there are details that don't work very well yet
<mcc111[m]>
oh , access to the cyclone v dsp blocks would make me very happy, although i may not be able to make use of it before we enter amaranth-soc world
<galibert[m]>
It's just an Instance too
<galibert[m]>
over cyclonev_mac
<tpw_rules>
quite rankled by the documentation being like "use our megafunctions or just infer it lamo"
<galibert[m]>
really? I've seen better docs, one second
<tpw_rules>
that's what the cyclone v device handbook says
<tpw_rules>
i mean they explain the internal details. but they don't connect it to the megafunction generator or have any way to manually instantiate a block
<galibert[m]>
it's not as good as a real doc, but it helps
<tpw_rules>
hrm
<galibert[m]>
(it's not necessary to be insane to use quartus, but it helps)
<tpw_rules>
have you used those models for simulation in a third party program or were you just curious
<galibert[m]>
I'm very, very curious
<tpw_rules>
curious to the point of trying to use them for simulation in a third party program? :D
<galibert[m]>
Nope
<galibert[m]>
Did you hear of mistral?
<tpw_rules>
yes
<galibert[m]>
I'm the main author
<tpw_rules>
ah
<galibert[m]>
Hence, curious
<galibert[m]>
Unhealthily curious some would say :-)
<galibert[m]>
in any case, a problem with the dsp is how flexible it is. It makes the interface definition complicated (should there be one or five is the first question)
<mcc111[m]>
<tpw_rules> "an hour is totally fine. i'm..." <- okay if you would be willing to ramble at me for a while about clock domains I can take notes and later synthesize it into a blog post or something
<tpw_rules>
let me finish this commit
<mcc111[m]>
sure
<mcc111[m]>
incidentally you can assume I have the EE 201 level basic understanding of the difference between synchronous/clock and asynchronous logic
<mcc111[m]>
But I did not take EE 202
nyaanotech is now known as nyanotech
<tpw_rules>
ok. i also assume that you are a competent software programmer
<tpw_rules>
ftr i like combinatorial more than asynchronous
<mcc111[m]>
sure
<mcc111[m]>
and yes fair assumption
<tpw_rules>
have you ever seen the inside of an fpga? the logic cells themselves?
<tpw_rules>
(or a diagram thereof)
<mcc111[m]>
i've seen the diagrams, but i didn't internalize them much better than "here are your LUTs" "here are some bags of dsp units and fft units and other taskable Widgets"
<tpw_rules>
ok, it's good to internalize a little more
<mcc111[m]>
I know one of the taskable Widgets is the PLLs or the thing that PLLs are built from
<mcc111[m]>
(I have worked professionally in an environment where I was writing the software on the other side of a DMA wall from some FPGA programmers)
<tpw_rules>
the second diagram is the place to start with really
<mcc111[m]>
okay.
<mcc111[m]>
this section suggests the DSPs and memory units are distributed across the chip rather than being (physically) all in one place— is the same true of the PLLs?
<tpw_rules>
yes
<galibert[m]>
yes, but they're on the border
<tpw_rules>
and when you have like two distribute is a bit of a vague term
<mcc111[m]>
I think the cyclone has two master clocks but many more PLLs than that. unless the PLLs are built out out of logic somehow
<tpw_rules>
but anyway the key things from that second diagram are that each LUT can be paired with a flop (using that mux on the far right), the clock is a semi-global entity, and all the inputs and outputs come from the amorphous "routing"
<tpw_rules>
i think it's only got two or possibly four PLL units, but each can generate five output clocks
<RobTaylor[m]>
Does anyone have an example of you you handle multi cycle paths in amaranth?
<mcc111[m]>
1.1.4 there says each ALM register has data, clock, clear and load. people talking about amaranth have frequently referred to an "enable". is that something else or at a different level or?
<galibert[m]>
e50f has four
<galibert[m]>
it comes associated with the block
<mcc111[m]>
tpw_rules: okay, i see.
<mcc111[m]>
so if i create a PLL in a quartus "megafunction", that's consuming an output clock from one of those 2/4 PLL units?
<galibert[m]>
the enable, that is
<tpw_rules>
yeah i don't think they've drawn it there, but the enable is sort of in tandem with the clock and affects all the registers in a block simultaneously
<galibert[m]>
a pll can output up to 9 clocks, with only 4 iirc really usable for you
<tpw_rules>
no, the megafunction consumes an entire unit. you can configure multiple clocks on it though
<tpw_rules>
each unit (and the megafunction) can only have one input clock
<mcc111[m]>
so a LAB contains several ALMs which contains several LUTs?
<galibert[m]>
A lab contains 10 ALMs which contains 6 luts
<tpw_rules>
the lab/alm/lut distinction isn't mega relevant
<galibert[m]>
2 lut4, 4 lut3
<mcc111[m]>
tpw_rules: it matters if i need to think about enables. someone said above the enable is associated with a "block", where is a "block" relative to lab/alm/lut?
<galibert[m]>
with a lot of inputs shared though
<tpw_rules>
the ALM i think
ravenslofty[m] has joined #amaranth-lang
<ravenslofty[m]>
galibert: you could have phrased that a lot better >.>
<galibert[m]>
The lab generate three clock/enable combo lines shared by all ten cells in it
<tpw_rules>
so decent size groups of LUTs and flops all need to share a small number of clocks and clock enables, so that's one motivation to think about a small number of clock domains
<tpw_rules>
does the phrase metastability mean anything to you? setup and hold times? did they cover them in your EE 201?
<mcc111[m]>
Yes.
<mcc111[m]>
But they mostly explained them and said "and that's why you have a clock and you simply put it after everything's settle time"
<tpw_rules>
i mean that is pretty much it
<ravenslofty[m]>
galibert: that assumes you don't have things like resets, iirc
<tpw_rules>
even in FPGAs, if you don't want to drive yourself crazy
<ravenslofty[m]>
I work for YosysHQ, of course I'm crazy
<tpw_rules>
but that means the timing analyzer's job is to make sure you haven't violated the setup and hold time
<ravenslofty[m]>
It's quite hard to cause a hold time violation, to be fair, and the tooling {can, should} fix that
<mcc111[m]>
right
<tpw_rules>
and two physical things matter here: the fabric's description of "interconnects of variable speed and length", the fastest speed and longest length ones are the clock networks. they're designed to go across the whole chip and make sure you have as much time as possible. you've got a small number of them so you want clocks to end up on them
<ravenslofty[m]>
I say this fully aware of the hypocrisy that nextpnr can neither detect nor fix hold time violations
<tpw_rules>
and the second thing is that means whenever you have a flop from one clock domain generating a signal latched by another domain, odds are you need special circuitry to avoid metastability because unless the clocks are exact multiples of each other there will be times when you'll have 0ps of timing and your circuit will fail
<tpw_rules>
s/timing/slack/
<mcc111[m]>
That makes sense
<galibert[m]>
ravenslofty: it can't in general, or it's just missing information?
<mcc111[m]>
(In my current design I'm happy to have all clocks be exact multiples of each other)
<ravenslofty[m]>
galibert: there is no code to detect hold time violations and no code to fix them.
<tpw_rules>
so in verilog you can do whatever the hell you want. you can @Posedge anything or if () whatever you like. and then the poor FPGA tool has to allocate slow routes and you get a lot of jitter running clocks through logic and it generally sucks
<tpw_rules>
but you can do it. you shouldn't but you can
<galibert[m]>
I thought it was at the core of pathfinder?
<ravenslofty[m]>
This could be implemented, but realistically you might as well rip out and replace nextpnr's timing analysis code with something smarter
<ravenslofty[m]>
galibert: eh? no?
<tpw_rules>
because @posedge means it has to be fed to a flop's clock input and if (in some cases) means it's an enable
<tpw_rules>
(same with rest for that matter)
<galibert[m]>
I thought it was directed by the timing constriants
<galibert[m]>
s/constriants/constraints/
<mcc111[m]>
tpw_rules: Catherine has repeatedly claimed that the @edge primitives in verilog have "race conditions" and some of the apparent limitations in amaranth are to avoid doing things of this sort that verilog supports but which doesn't actually work
<galibert[m]>
Read that paper a while ago at this point though
<tpw_rules>
mcc111[m]: afaik that's more to do with simulation than the physical hardware, but i could be wrong
<ravenslofty[m]>
galibert: and if nextpnr does not consider hold timing as a constraint?
<tpw_rules>
but in any case, amaranth very wisely codifies a clock, its (possible) reset, and its (possible) enable into a single Domain concept
<tpw_rules>
because all those are tied together in the FPGA's circuitry and all those are something you have to be very careful when mixing two of together
<mcc111[m]>
okay. so enables are reified on LABs (fairly low level) but amaranth associates it with an entire clock domain (shared among many LABs) at a time?
<galibert[m]>
ravenslofty: heh
<tpw_rules>
amaranth can. enables are sort of a mid level. clocks and resets are pretty 1:1, but there can be situations where the enable might have extra logic in its path and the fpga tool can choose to do that. it's also a convenient way to do clock gating
<ravenslofty[m]>
mcc111: galibert may well correct me here, but I believe they can be done at higher levels as well
<tpw_rules>
you simply add an AND to everybody's enable instead of having to create a new clock domain and consume a precious clock net
<ravenslofty[m]>
(I'm thinking of the RCLKs/GCLKs here)
<mcc111[m]>
clock gating meaning, the thing that verilog calls @posedge?
<tpw_rules>
not really, that's clocking
<ravenslofty[m]>
clock gating would be if (condition)
<tpw_rules>
gating would be if you wrap everything within an @posedge (some_clk) to be if(cond)
<mcc111[m]>
oh, i guess clock gating is a Vocabulary Word
<mcc111[m]>
ok
<tpw_rules>
(and across all such @posedges, that's where it's likely to be converted into an enable vs. if you have 10 @posedge (the same clock) and only one if (a cond))
<mcc111[m]>
okay. so I might be implicitly making use of enables already if I'm just using m.If in amaranth?
<tpw_rules>
the downside of gating like that, is that you've still gotta meet the timing for your fast clock even if your circuit is only enabled 1 out of every 1000 cycles
<tpw_rules>
yes
<galibert[m]>
the clock buffers are the root of the clock nets in the cycloneV have the capability to gate it with an enable. There are roughly 80 of them, so that's a lot of possibilities
<tpw_rules>
(this can be worked around with custom constraints but that's Non Trivial)
<mcc111[m]>
ok.
<mcc111[m]>
the reason i'm asking about enables a lot is I have an assumption (?) i will eventually need to understand them if I want to optimize for power consumption.
<galibert[m]>
smaller, non-intel fpgas may have like two :-)
<ravenslofty[m]>
If you're using them in combination with the `sync` domain to, say, conditionally update a value, then it'll likely be mapped to an enable
<tpw_rules>
so back to what amaranth does. you have these Domains which encompass a clock, a reset, and an enable you can define
<tpw_rules>
(you can define all there)
<tpw_rules>
three
<tpw_rules>
idr if there's a specific domain datatype, but we'll just say they are strings for now
<mcc111[m]>
ok
<tpw_rules>
there's comb which is its own thing and really doesn't participate except that you can't call a domain comb
<tpw_rules>
domains are also (afair) Module-specific, so each Module has its own view of the domains, which we'll get to in a second. the default domain for a module is always "sync"
<galibert[m]>
It's class ClockDomain
<ravenslofty[m]>
I have a mental model for when something might be mapped to an enable or not, but I feel that model only makes sense to me >.>
<mcc111[m]>
comb is ClockDomain or something else?
<tpw_rules>
ClockSignal(domain) is the clock signal for that domain. iirc speaking a domain will bring it into existence (unlike migen)
<tpw_rules>
so you can say ClockSignal("sync").eq(my_cool_signal) if you need to inject a clock signal
<tpw_rules>
or my_out.eq(ClockSignal("sync")) though that's not amazing practice because of bleh delays through i/o pins
<tpw_rules>
(not specifying a domain just implies "sync")
<galibert[m]>
It's useful when you need to pass a clock to an Instance though
<tpw_rules>
yes
<mcc111[m]>
Please clarify: ClockSignal("syncq") will create a new domain with name "syncq", or it will connect to some sort of global namespace and fetch-or-instantiate a domain with name "syncq"?
<tpw_rules>
the second
<tpw_rules>
and it's not really global, it's module-local
<tpw_rules>
there's also ResetSignal for the domain's associated reset, but there's as of yet no EnableSignal
<tpw_rules>
so with reference to the module-local-ness
<tpw_rules>
there's DomainRenamer("blah")(module) which means that when that module asks for "sync" it will instead get "blah"
<mcc111[m]>
tpw_rules: Wait. But I thought EnableInserter existed in Amarnath. People have recommended I use it
<tpw_rules>
there's no EnableSignal. EnableInserter is a separate thing
<mcc111[m]>
or does "it is not possible to write an equivalent of EnableInserter" in that issue mean "only the builtin EnableInserter is EnableInserter"?
<tpw_rules>
(instead of "blah" you can also pass a dict which maps `module`'s names to the ambient names)
<tpw_rules>
maybe that's out of date and google failed me
<mcc111[m]>
tpw_rules: okay… I assume this is a convenience and cannot be used to bridge domains between modules?
<tpw_rules>
(i think EnableInserter uses case (a) because it knows all about amaranth)
<tpw_rules>
DomainRenamer? yes it can be. what do you mean by bridge?
<ravenslofty[m]>
mcc111: I read it as "you cannot express EnableInserter inside pure Amaranth"
<tpw_rules>
that post was also specifically within the context of Instances
<tpw_rules>
which bring stuff from outside of amaranth
<mcc111[m]>
ravenslofty[m]: ok
<galibert[m]>
EnableInserter is equivalent to add a with m.If(enable_signal) on all m.d.domain += ...
<ravenslofty[m]>
Yes, but to actually do that transform you must mutate the Amaranth AST or whatever the equivalent is
<tpw_rules>
and that's what the code does it looks like
<mcc111[m]>
tpw_rules: well, you said ClockSignal("blargarg") will get you the clock signal for the blargarg domain, name scoped to your module. i could imagine wanting the "blargarg" domain used by some other module
<tpw_rules>
it's global so long as nobody else has DomainRenamered it
<tpw_rules>
there's no like hierarchy
<mcc111[m]>
earlier you said: "and it's not really global, it's module-local" . what did that mean
<tpw_rules>
so you can have in your module ClockSignal("blargarg") and that'll get the blargarg domain
<tpw_rules>
but if someone else does DomainRenamer({"blargarg": "foobaz"})(your_module) it will instead get the foobaz domain
<tpw_rules>
(and so too will any modules your module instantiates)
<ravenslofty[m]>
I mean that sounds suspiciously like a hierarchy to me, but what do I know
<crzwdjk>
The _domains_ are global, the view of their _names_ depends on the module
<tpw_rules>
i don't know that there's a way to get The Official blargarg is what i'm saying. it's not like you can do super.blargarg in your_module if you want to escape renaming
<tpw_rules>
crzwdjk: that's a good way to put it. and that view is a hierarchy
<tpw_rules>
(which you can't really navigate around)
<tpw_rules>
i mean 99.9999% of the time it's used to take a module which is written for the "sync" domain and you put it in some sub-domain
<mcc111[m]>
okay, i might have to ask followups the first time i use it but I thiiiink I get it
<mcc111[m]>
One other question
<mcc111[m]>
This notion of a "Clock Domain" we've been using in this immediate discussion. This is *a notion internal to Amaranth?* correct? this is not a general thing users of other HDLs will recognize?
<galibert[m]>
It's a well-known notion
<tpw_rules>
it's a thing they should, but their HDLs don't formalize it
<galibert[m]>
Especially when you start looking for "clock-domain crossing"
<tpw_rules>
like, in proper written verilog, you would only ever @posedge something that's a clock domain clock. how do you define that? a text file somewhere i guess...
<mcc111[m]>
ok. so other HDL users will have a notion of a clock domain, and it will encompass the same three things it does in Amaranth, but it will probably not be a first-class entity in their HDL
<tpw_rules>
and imho amaranth's substantial innovation over verilog is that it does formalize a ClockDomain notion that matches the hardware and correct use of HDL in general
<tpw_rules>
correct
<tpw_rules>
now, finally, EnableInserter(sig)(module) and ResetInserter(sig)(module). those, in essence, create a new domain with the specified enable/reset signal (but same clock and non-inserted signals) and replace the "sync" domain of module with it. (alternately sig can be a dict of domain names to signals to insert)
<galibert[m]>
yeah. Being explicit about clock domains is one of the big strengths of amaranth
<mcc111[m]>
huh, ok
<tpw_rules>
(DomainRenamer is in essence a ClockInserter, but the enable/reset are subordinate to a clock as they must be synchronous to it so you wouldn't really just insert a clock)
<tpw_rules>
and as a final statement, an amaranth Instance just instantiates an arbitrary verilog module. in essentially every synthesis tool there are global names for the various chip blocks you can instantiate that way and use directly
<mcc111[m]>
tell me if this is correct: +='ing something to an EnableInserter'd domain with enable Q is potentially the same as m.If(Q): m.d.sync +='ing it, because Ifs are often implemented with Enables, but it is not guaranteed to be the same, so things like Quartus wil probably not do the right thing wrt timing analysis and such
<tpw_rules>
both are the same with quartus
<mcc111[m]>
tpw_rules: okay
<mcc111[m]>
is a Memory the same as an Instance but amaranth knows it's a memory unit?
<tpw_rules>
they'll generate the same verilog
<galibert[m]>
this is abstract. Nothing tells the synthesizer whether to use an enable or a loop, it decides itself
<tpw_rules>
it's up to quartus's PnR to decide if it wants to upgrade that if from a mux to an enable. then the timing analyzer decides if that circuit, in either case, will pass the timing
<galibert[m]>
(possibly badly, but that's another story)
<tpw_rules>
iirc, Memory is an Instance to yosys
<ravenslofty[m]>
mcc111: well, "amaranth knows it's a memory unit" means that it gets handled differently to Instances, where Amaranth has no idea how to simulate them, for example
<tpw_rules>
but what yosys does when you try to write out a memory module it recognizes is to make verilog that looks enough like a memory that quartus will pick up on it and map it to a memory block
<tpw_rules>
(hdl inference)
<mcc111[m]>
yikes, okay
<tpw_rules>
yeah. another thing amaranth is nice is that it is less likely to generate code quartus won't pick up on
<ravenslofty[m]>
Although, um, I think Quartus struggles with Memorys that are initialised because of limitations in how Amaranth communicates with Yosys
<mcc111[m]>
so i think after this discussion i now have a conceptual understanding of the six "mystery classes" that are not in the stdlb docs
<tpw_rules>
if it's not something most physical memory supports you probably can't do it with Memory
<galibert[m]>
Quartus (at least my version) struggles with Memory in general as soon as it's a little big
<mcc111[m]>
I think I still have three questions:
<ravenslofty[m]>
(Amaranth uses a pipe to communicate with Yosys, so when it asks for Yosys' `write_verilog`, it has to send everything as one file, which means that memory initialisation has to use a format that Quartus handles **really badly**)
<mcc111[m]>
1. In order to use Memory/Instance/EnableInserter/DomainRenamer/ClockDomain/ClockSignal, even if I understand them conceptually, I must know (say) the signatures of their constructors. In a worst case scenario, how would I extract that information from the Python? like where in the repo file tree are they
<galibert[m]>
hdl.py usually
<ravenslofty[m]>
except for Memory, which is in hdl/mem.py
<galibert[m]>
sorry, hdl/ast.py
<crzwdjk>
The renamers and inserters are in hdl/xfrm.py I think
<crzwdjk>
Some of the classes even have documentation. Some do not.
<mcc111[m]>
Once I have the signature for EnableInserter I bet I could use it to divide a clock, although "clock divider div 90" is harder.
<mcc111[m]>
If your suggestion is "Just go use a PLL like a normal person" that might be viable too :P
<mcc111[m]>
Although if by moving to keying off a PLL megafunction I lose the ability to use the amaranth simulator that would be too bad
<ravenslofty[m]>
I do think a PLL is probably the most practical way to do this
<tpw_rules>
really all you would need to do is take all the video junk, put it in a submodule, and use the enable inserter to set the strobe to that module's enable
<tpw_rules>
but i'm not sure it's necessary for a simple demo unless you are violating timing, which you aren't
<mcc111[m]>
wait, how do you know i'm not violating timing? some of my logic trees are kinda deep.
<tpw_rules>
well the example outputs you showed earlier weren't
<galibert[m]>
deep doesn't actually matter, wide does
<mcc111[m]>
… I think that makes sense
<ravenslofty[m]>
no, deep matters
<mcc111[m]>
tpw_rules: The "clock" in question is consumed externally. So I think (?) I need my bytes ready and stable *before* the clock rises.
<galibert[m]>
ravenslofty: if you have 6 inputs or less, the speed will be the same whatever the complexity of your expression is
<ravenslofty[m]>
but an expression which has 6 inputs or less is not going to be complex, so it's not going to be deep
<ravenslofty[m]>
that's...one level deep
<tpw_rules>
mcc111[m]: in an ideal world the strobe would occur at the last cycle of the rotation rather than the first (so just before the output clock is asserted). in fact that could be your problem
<mcc111[m]>
This is the timing diagram I'm trying to match https://www.analogue.co/developer/docs/bus-communication#timing-information notice they do not anywhere say something specific like, "we consume the vid_rgb bits on the rising edge of clk_90" or "you can safely scribble over vid_rgb whenever clk is low". If I can frame the question in non-amaranth terms though I can get the more experienced analogue programmers to give me information
<mcc111[m]>
like that probably
<galibert[m]>
ravenslofty: there are 2**64 expressions possible, they don't all take the same size of verilog/amaranth expression to implement it, yet they're equivalent in the end
<mcc111[m]>
tpw_rules: It occurs at the last cycle of the rotation. Unless I broke something since Catherine gave me the code
<tpw_rules>
oh so it says
<tpw_rules>
then it should just work™
<tpw_rules>
your output clock value and the computed results should be latched on the same (main clock) cycle
<tpw_rules>
stupid question
<mcc111[m]>
she set this up with that particular timing and then I fiddled with it and then I realized that was a bad idea and fiddled it back
<tpw_rules>
is that outputting clock inverted from what it describes
<mcc111[m]>
tpw_rules: uhhh… one second, i have a gtkwave
<mcc111[m]>
barring something absurd like "the signal is positive-low and no one told me" that looks correct to me vs the official timing diagram
<tpw_rules>
can you get a change of video_rgb in the first screenshot?
<galibert[m]>
Did you try with a simple video signal rather than the complex one?
<mcc111[m]>
tpw_rules: can you clarify what you mean by this. you want a change of video_rgb soon after boot, or you want a change of rgb at the zoom level of the first screenshot?
<tpw_rules>
the second
<mcc111[m]>
uhh… yeah, one minute
<mcc111[m]>
well, maybe more like 2, i'm waiting for a simulate to finish
<mcc111[m]>
part of the problem is the video signal begins and ends with "porches" which means there's an actually quite long gap after the thing boots up before it generates a nonzero pixel
<mcc111[m]>
galibert[m]: "simple" how?
<mcc111[m]>
my current program, the first line is always pure white with a single black pixel in the middle, which i think is pretty nicely simple
<mcc111[m]>
<ravenslofty[m]> "I do think a PLL is probably the..." <- incidentally, just a note: the only way I know to task a PLL is to use a megafunction. this is a problem because the PLL megafunctions are done in the quartus GUI. at the moment, I can change resolutions by just altering a single text file (resolution.py, which contains porch sizes and a clock divisor) which is nice.
<mcc111[m]>
this is a big part of why i am resisting the PLLs even though I know it would solve problems
<tpw_rules>
you could use galibert[m]'s Instance code
<ravenslofty[m]>
I don't disagree that it's a pain in the ass, and also that it's not portable
<tpw_rules>
but i think there's something other than clock problems going on
<ravenslofty[m]>
But what the Quartus GUI is doing is instantiating a cell with some Verilog glue code
<ravenslofty[m]>
and you can do that with Instance
<mcc111[m]>
someone earlier tossed up some code for tasking the PLLs without touching megafunctions, which may be worth exploring, but then I run into the other problem, which is that the "weirder" the thing I am doing is from the perspective of the verilog-only programmers who comprise the rest of the Pocket community, the less likely they are to help me with things (because they cannot know if whatever problem I am having is actually caused by
<mcc111[m]>
my atypical python toolchain)
<tpw_rules>
yes, galibert[m]'s stuff lets you dyamically recalculate the things
<tpw_rules>
>_>
<tpw_rules>
things = pll constants to get a desired resolution
<mcc111[m]>
although if Instance(the pll) turns into legible verilog then that removes that issue
<tpw_rules>
it won't be legible to them
<galibert[m]>
tpw_rules: I didn't implement the on-the-fly pll reprogramming though :-)
<mcc111[m]>
tpw_rules: i see. by comparison if i say "i used the megafunction, here's what it looks like in the ide" they'll be confident it's correct
<tpw_rules>
"The phase shifted clock is used by the framework HDL to convert the pixel data into 12-bit DDR for consumption by the System FPGA."
<tpw_rules>
that could be the problem
<tpw_rules>
i forgot about that quirk
<tpw_rules>
those signals don't go directly to the i/o pins, they pass through more logic. so you're violating the @posedgeing a clock domain clock thing and that's where the timing might be screwed up
<tpw_rules>
in litex i used the ddr primitives specifically
<mcc111[m]>
also jeepers is there a way to get gtkwave on linux to show me real scrollbars. My scrollwheel is doing nothing, arrow keys do nothing, if I scroll to a particular point and then zoom it resets to the far left. it is nearly impossible to scrub to a particular point wihle zoomed in
<mcc111[m]>
tpw_rules: I don't know how to interpret this last sentence
<tpw_rules>
according to the pocket documentation, what you're doing matches it
<tpw_rules>
but i remembered The Catch where the problem quite possibly is
<mcc111[m]>
okay. and would you worry there might be a difference between simulation and reality
<tpw_rules>
can you link again the code that's messing up, your x ^ y example?
<tpw_rules>
not there
<tpw_rules>
The Catch is that there's more logic between the simulated data you generated and what gets sent to the other FPGA to drive the video
<tpw_rules>
and idk if you or catherine picked up on that
<mcc111[m]>
what are you looking for specifically?
<tpw_rules>
what do you mean
<mcc111[m]>
I have several demos based on the same root Catherine code (there is a newer root Catherine code I haven't moved to yet because I need a day both Catherine and I are available to talk about it). In general, my current bug (the pixel color smear) seems to happen, but it seems to happen much more on some demos than others, I believe because the clock divisor is different in different demos depending on what screen resolution I needed
<mcc111[m]>
(but it could be some other reason)
<mcc111[m]>
"can you link again the code that's messing up, your x ^ y example?"
<mcc111[m]>
What code, exactly?
<tpw_rules>
in your toy demo, that you're only updating the video_rgb_out when strobe is asserted
<tpw_rules>
which seems to be true
<tpw_rules>
is that the demo which is the worst problem? and the demo you shared the build log from?
<mcc111[m]>
this is the demo code
<mcc111[m]>
branch cellular_toy. that is the demo which is the worst problem, the one both the build log and the screenshot I posted earlier come from.
<tpw_rules>
you need to cut it out and implement it manually, or switch to a PLL so the DDR blocks are getting legit clocks
<tpw_rules>
it's possible adding the appropriate clock constraint might fix it but i wouldn't bet that way
<mcc111[m]>
anything in the apf/ directory can't be touched. it is Handed Down From The Heavens
<tpw_rules>
why do you say that
<tpw_rules>
is that in their agreement
<mcc111[m]>
tragically, there is no agreement, and in fact no license of any kind, such that it's entirely unclear whether even one single third-party Analogue Pocket core exists legally
<tpw_rules>
well do they say "NO TOUCHY TOUCHY" in the block of crap at the beginning of the file
<tpw_rules>
i mean mine does cause it uses 0% of their apf junk ;)
<tpw_rules>
(well "exists" might be a strong word)
iposthuman[m] has quit [Quit: Idle timeout reached: 172800s]
<mcc111[m]>
apf stands for Analogue Platform Framework. Analogue is bad at communicating and they have given us this sample code repository, with this specific project file, and this directory named apf/ containing stuff that they say, this is what you need to talk to the other parts of the system. they also say: don't touch anything in apf/, instead edit core_top.v. What are the consequences for editing apf/? We don't know. The invariants that
<mcc111[m]>
apf/ satisfies wrt the other parts of the system are not documented, so if we change apf/, we might break those invariants. But we don't know. The one thing that's for certain is if a new version of apf/ is released in future (likely), if you have made changes to apf/, the new version will have to stomp yours.
<mcc111[m]>
tpw_rules: you mean, your experimental linux core?
<mcc111[m]>
that just talked out through the serial port tho right? so it didn't really communicate with the things apf/ are designed to communicate with.
<mcc111[m]>
i forgot that was yours.
<tpw_rules>
it does video
<mcc111[m]>
interesting.
<tpw_rules>
you can get a terminal on the screen
<tpw_rules>
even a game™ but i never got around to getting the joystick back input
<mcc111[m]>
okay. and a logic-based clock, or even a enable-based clock, is not "clean"?
<tpw_rules>
in your core_constraints.sdc
<tpw_rules>
correct. because you're going through the logic paths instead of the clock paths so you can pick up jitter and delay and stuff, and quartus isn't analyzing any of it
<mcc111[m]>
you are recommending I try those four lines?
<tpw_rules>
there's also stuff like logic glitching
<tpw_rules>
it's two
<mcc111[m]>
without changing any of the other logic?
<tpw_rules>
that should tell quartus about your clocks and we can see what it says
<tpw_rules>
correct
<galibert[m]>
an enable-based clock is not something you want to go out of the fpga. A logic based clock can be a mess
<tpw_rules>
if it's generated, and then latched on a nice clock, and then nothing else happens, it could be okay. but feeding it to the DDR engines is no bueno
<mcc111[m]>
and if i change resolution.py i will need to change those two lines?
<tpw_rules>
no
<tpw_rules>
well yes if you change the divide factor, sorry
<mcc111[m]>
do you expect this to change the output, or do you expect it to only add wrnings?
<tpw_rules>
it's possible it could change the output. if quartus doesn't know about a clock it won't optimize it. this could tell it to get its butt in gear and clean things up but it's a little unlikely
<mcc111[m]>
Error (11802): Can't fit design in device. Modify your design to reduce resources, or choose a larger device. The Intel FPGA Knowledge Database contains many articles with specific details on how to resolve this error. Visit the Knowledge Database at https://www.altera.com/support/support-resources/knowledge-base/search.html and search for this specific error message number.
<tpw_rules>
does it provide any context?
<galibert[m]>
Error (11801): I don't like you, go away.
<tpw_rules>
sometimes it's not size but now that it's a clock it might be saying "uh dummy you can't hook logic up to a ddr clock"
<tpw_rules>
and the placement fails
<galibert[m]>
(or it feels like that :-) )
<mcc111[m]>
sighs what is the directory i need to delete to simulate a "clean" build
<mcc111[m]>
git clean xffd worked but i also had to reinstall my pdm
<tpw_rules>
that's where you have to fire up the GUI and see what in the fuck quartus decided to call it
<mcc111[m]>
Okay. So we didn't actually change anything by adding the "two lines"?
<tpw_rules>
correct, they're broken
<mcc111[m]>
"call it" you mean the -name must be something different?
<galibert[m]>
Warning (332060): Node: core_top:ic|amaranth_core:ac|amaranth_core.video_clk_div:video_clk_div|clk_reg[0] was determined to be a clock but was found without an associated clock assignment.
<galibert[m]>
wazzat?
<tpw_rules>
that's what we're trying to get rid of
<tpw_rules>
try just -source <name> instead of -source [get_ports <name>]
<mcc111[m]>
you mean, type vid_0 and vid_90?
<mcc111[m]>
and you don't recommend I start poking around in quartus?
<tpw_rules>
the -name is what qartus calls the clock. the -source is what internal whatever the clock signal is
<tpw_rules>
which is only very distantly related to your amaranth variable names (and verilog for that matter, amaranth does not make this process substantially worse)
<mcc111[m]>
i see. but if i were'nt using amaranth i'd be using the megafunction gui, which is nasty but at least doesn't generate bad code?
<tpw_rules>
it does automatically handle this part, yes
<galibert[m]>
If you use an amaranth-generated pll, it will be handled automatically too
<galibert[m]>
derive_pll_clocks in the .sdc does that
<tpw_rules>
so if my last suggestion doesn't work, maybe galibert[m] can hook you up with the PLL code. that should be automatically generatable too
<mcc111[m]>
i'm not attempting to decipher these before i post them, i'm attempting to decipher afterward and you kepe beatin gme lol
<tpw_rules>
The master clock for this clock assignment could not be derived. Clock: vid_0 was not created. oh my fuck
<galibert[m]>
Warning (332087): The master clock for this clock assignment could not be derived. Clock: vid_0 was not created.
<galibert[m]>
Warning (332034): Specified master clock: clk74a not found on or feeding the specified source node: core_top:ic|amaranth_core:ac|amaranth_core.video_clk_div:video_clk_div|clk_reg[0]
<tpw_rules>
oh.
<tpw_rules>
it's clk_74a
<tpw_rules>
sorry
<mcc111[m]>
is that a "this is too logic-y to be a clock"
<tpw_rules>
shot from the hip and missed
<mcc111[m]>
oh.
<mcc111[m]>
yes, it is
<galibert[m]>
heh
<galibert[m]>
you're faster than me at reading quartus logs I see
<galibert[m]>
Warning (332034): Specified master clock: clk_74a not found on or feeding the specified source node: core_top:ic|amaranth_core:ac|amaranth_core.video_clk_div:video_clk_div|clk_reg[0]
<mcc111[m]>
do we need to like specify what file clk_74a lives in
<mcc111[m]>
core_top:clk_74a or something
<mcc111[m]>
i have literally zero idea the format of this file and have not attempted to look it up lol
<tpw_rules>
or just feeding clk_74a directly into amaranth?
<galibert[m]>
direct
<mcc111[m]>
i was interested but not surprised to discover that if, on this machine, a rust build and a quartus build happen at the same time a youtube tab is playing music, the oomkiller kills firefox
<tpw_rules>
ok then last try is [get_ports clk_74a]
<mcc111[m]>
you want me to try [get_ports clk_74a] NOT [get_clocks clk_74a] ? 6 is the former
<tpw_rules>
so then we did already try [get_ports clk_74a]
<mcc111[m]>
i have not configured any PLLs. it is possible the code i inherited contained one.
<galibert[m]>
yes, get_ports is what matches the example
<mcc111[m]>
ie, from the example code.
<tpw_rules>
to be clear, BUILDLOG6.TXT is the result of [get_ports clk_74a] correct?
<mcc111[m]>
no. i typoed. BUILDLOG6.txt is the result of get_clocks star star. this is the result of get_ports clk_74a:
<galibert[m]>
Warning (332049): Ignored create_generated_clock at core_constraints.sdc(17): Argument: -master_clock must contain exactly one valid clock. File: /home/mcc/work/f/analogue-core-template-amaranth/src/fpga/core/core_constraints.sdc Line: 17
<galibert[m]>
a new one
<tpw_rules>
new dumb error. unclear if the clock specified earlier doesn't exist or there's something else
<tpw_rules>
anyway, i gotta go
<mcc111[m]>
there are two master clocks
<tpw_rules>
a PLL is the right way to do this. if you want to use galibert[m]'s code rather than the megawizard that should be a pretty nice experience
<mcc111[m]>
clk_74a and clk_74
<mcc111[m]>
* clk_74a and clk_74b
<mcc111[m]>
the latter is the first but phase shifted by the other amount. it was explained to me the two clocks are available on opposite sides of the fpga's physical die
<mcc111[m]>
okay, thank you for trying.
<mcc111[m]>
i will try the PLL megawizard first, and then gaibert's only once i am confident i have something that works.
<tpw_rules>
ok. glad i could help at least with understanding clocks, if not with fighting quartus
<tpw_rules>
hopefully once the megawizard works you can learn the lesson of why not to synthesize clocks with logic :)
<galibert[m]>
you're making your life more complicated :-)
<mcc111[m]>
well, look at it this way
<mcc111[m]>
if the megawizard doesn't work
<mcc111[m]>
then i can get the fpgaming discord to explain to me wtf is happening without having to explain what i'm doing with the manually-instantiated PLL
<mcc111[m]>
tpw_rules: i do hope i can get some version of this into the documentation.
<tpw_rules>
(i'm not sure the people in that chat know too much about fpgas)
<tpw_rules>
(but they are learning)
<galibert[m]>
(well, I'm in that discord, so... ;-) )
<tpw_rules>
i meant to include active
<galibert[m]>
Well, jotego is rather good
<tpw_rules>
the people big and excited and into making cores i helped a lot when this stuff first came out
<tpw_rules>
it seems the ones who know like kev and the original core authors were lacking some fundamentals
<tpw_rules>
ugh
<tpw_rules>
i mean staying quiet while the talkers were lacking some fundamentals
<galibert[m]>
kevtris was lacking fundamentals? I think I'm not parsing your sentence right
<tpw_rules>
i screwed up
<tpw_rules>
i missed an entire clause in it
<tpw_rules>
kevtris and the original core authors for sure know what they're doing
<tpw_rules>
the new wave when openfpga dropped a) talked a lot in the channel and b) lacked some fundamentals
<galibert[m]>
but they're not talking, I see
<tpw_rules>
yes
<tpw_rules>
same to you. have you ever talked in that channel?
<galibert[m]>
that I'm not surprised about
<galibert[m]>
hmmm, probably not
<tpw_rules>
proof right there :)
<galibert[m]>
Been careful not to fully show my knowledge level either :-)
<tpw_rules>
aaaaaaaaanyway
<tpw_rules>
the amaranth docs definitely need documentation on the inserters and stuff
<tpw_rules>
i really wouuld appreciate if they had a section on The Theory of Clock Domains too
<tpw_rules>
or a link to such
<galibert[m]>
Damn, you made my brain switch into factorio context, and that made everything weird
<tpw_rules>
cause it really is powerful and why i and others like it and a gap between "okay whee we can look at timing diagrams and a D flop" in class and what the chip actually does and how you make a design where you don't cry the entire time (not promised)
<galibert[m]>
with verilog you cry the entire time (promised)
<galibert[m]>
The theory of synchronous circuits
<galibert[m]>
I want to write one at some point, but since I'm spending my work day writing lately, I don't have the energy
<tpw_rules>
anyway, bye. maybe i'll try my hand too now that i've regurgitated some stuff down and had an actual student. keep us updated with your PLL journey
<cr1901>
"Understanding Clock Domain Crossing Issues" on EETimes is the reference I point ppl to. I remember reading once it's the most viewed article on that site by a large margin.
<cr1901>
It basically goes over everything (although it handwaves REQ/ACK handshaking a bit)
<mcc111[m]>
<galibert[m]> "but they're not talking, I see" <- i assume everyone is happy for them to be busy working on the actual product instead lol
<galibert[m]>
Also, enthusiastic but clueless newbies can be... tiring. I dread the "Hi, I'm learning to program and I've decided to do an emulator" people
<galibert[m]>
When understanding what you do when writing an emulator requires low-level knowledge they don't even know exist
<mcc111[m]>
i mean, i consider myself in the enthusiastic but clueless newbies category.
<galibert[m]>
ah no, you're nowhere near the clueless level