Keyboard Shortcuts
ctrl + shift + ? :
Show all keyboard shortcuts
ctrl + g :
Navigate to a group
ctrl + shift + f :
Find
ctrl + / :
Quick actions
esc to dismiss
Likes
Search
Coding style: Get/Put vs. Client/Server for pipelines?
(I appreciate that this is a subjective question and the general answer is "it depends", but gut wisdom and opinions from experienced Bluespec programmers would be very welcome!) I'm writing a modest graphics core in BSV, with a various moving parts: tile renderers, a sprite engine, a compositor, pixel drivers for various output protocols, and so on. I have a bunch of components that take some data in and produce data out: obvious ones like memory ports, and some domain-specific things like a palette engine (takes in a stream of palette indices, does lookups in palette RAM, outputs R/G/B color signals). Most of these components have both Get and Put interfaces. Some are obviously server-shaped (e.g. memory ports), whereas others represent part of a pipeline in which an upstream module connects to Put, and a downstream module connects to Get. How would you structure the APIs for modules that are expected to be pipelined in a chain? So far in my code, I've hesitated between two approaches:
I believe both of these approaches can be made to work, and can produce equivalent RTL when synthesized. Should I prefer one approach over the other? Or is there another better structure that I'm missing? I'm still relatively inexperienced in Bluespec, so I'm particularly interested in hard lessons learned, where it turns out a particular structure leads to headaches later, or conversely a particular structure results in more readable and maintainable code down the road. Thanks, - Dave |
You may want to look at the Fife 5-stage RISC-V pipeline in:
? ? https://github.com/rsnikhil/Learn_Bluespec_and_RISCV_Design
?
In 'Code/src_Fife/' you will find the 5 CPU pipeline stages
S1_Fetch.bsv through S5_Retire.bsv, each with its own stage interface,
and a top-level CPU.bsv that instantiates the stages and connects
them.
?
* In a linear pipeline I prefer to keep separate 'Get' and 'Put'
? ? sub-interfaces instead of combining them into a Client/Server
? ? because I don't think Client/Server terminology is appropriate
? ? here. ?I think of
? ? ? ? Client ? ?as sending requests and receiving responses
? ? ? ? Server ? as receiving requests and sending responses
? ? neither of which is the case in a linear pipeline where one is
? ? receiving something (not a 'request') from upstream and sending
? ? something (not a 'response') to downstream.
?
? ? Further, we never 'mkConnection' a Get/Put of one module with a
? ? Put/Get of another, in the usual Client/Server connection: we
? ? connect a Put of the module with an upstream Get and a Get of the
? ? module with a downstream Put.
?
* Instead of 'Get' and 'Put' I use 'Semi_FIFOF_O' and 'Semi_FIFOF_I',
? ? respectively, which are essentially the 'first/deq/notEmpty' and
? ? 'enq/notFull' sides of a FIFOF interface. ?I prefer these over
? ? 'Get/Put' because (a) I can test for notEmpty/notFull and (b) I
? ? can non-destructively examine 'first' in a rule condition.
?
? ? These interfaces, and their 'mkConnection' can be found in:
?
? ? ? https://github.com/B-Lang-org/bsc-contrib
?
? ? at 'Libraries/Misc/Semi_FIFOF.bsv'
?
* Each stage interface is more than just one Semi_FIFO_I and one Semi_FIFOF_O:
? ? * Each stage interface may also have an 'init' method (invoked from the top-level CPU.bsv)
? ? * Some stages have more than one-in and/or more than one-out. ?Eg.,?
?
? ? ? ?* S1_Fetch has one-in in the reverse direction from S5_Retire
? ? ? ? ?for redirections (traps and correcting branch mispredictions),
? ? ? ? ?and two-outs, one to S2_Decode and one to the ICache.
?
? ? ? ?* S2_Decode has one-in from S1_Fetch, and one-in from the
? ? ? ? ?ICache and only one-out to S3_Decode
?
? ? ? ?* S3_RR_RW has one-in from S2_Decode, many outs to
? ? ? ? ?different execution pipelines, and one-in in the reverse
? ? ? ? ?direction from S5_Retire to update the register file.
?
? ? ? ?* S5_Retire has many ins from the different execution pipes,
? ? ? ? ? one out in the reverse direction to S1_Fetch (traps and redirections),
? ? ? ? ? and one out in the reverse direction to S3 (update register file).
?
? ? Thus, the overall pipeline is a more complex graph than a single
? ? straight-line one-in, one-out pipe.
? ? The 'mkConnections' in CPU.bsv establish this graph.
|
Thank you for the comprehensive reply! And for the pointer to the RISC-V design course, I'd been meaning to read it in more detail but forgot about it. Your reasoning makes a lot of sense to me. In particular, at the current stage of design the pipeline is still linear, but further down the road it's going to at least have splits and joins, and maybe also some backwards flow. I did not consider that with just the code in front of me right now, but that would be very awkward to materialize as clients and servers. Taking the Fife pipeline as a guide, I can actually already see how this structure is going to improve the readability of my tiling engine. Its current Server-based architecture is forcing me to mix the equivalent of the fetch and decode stages together, which creates quite a tangle and effectively forces the module to have a little state machine to keep track of things. This code should really be broken into 2 or 3 smaller pipeline stages, but I couldn't see that when trying to shoehorn everything into a Server interface. Thank you! - David On Sun, Apr 6, 2025, at 13:51, Rishiyur Nikhil via groups.io wrote:
|
to navigate to use esc to dismiss