Iteration which stops at address map boundaries
krcb197 opened this issue · 2 comments
This may be a question or a feature request. I want to upgrade peakrdl-python so that address maps are split into separate Python files, both the register model and the testbench. This is because the generated Python files can get very big for real-world designs.
My plan is to split into separate files at the address map boundaries, as this is in the spirit of the systemRDL specification. The problem is that registers can be within a dependent register file and should be included.
In order to do this it would be useful to have a python generator implemented on an address map node which iterates through descendent register files but does not iterate inside a child address map.
I don't believe any of the generators currently provided quite do what I am looking for, if I am wrong please let me know where to look and go no further.
Assuming this feature is not in the compiler today, I could implement it within peakrdl-python but I feel other people may need a similar feature so that it belongs in the systemrdl-compiler. I would be happy to attempt to implement it, I think I can see how to add it to node.py
, there are two approaches:
- add a mode (controlled by a new parameter) to the existing
descendants
generator to no iterate within an address map - add a new generator to the
AddrmapNode
class for example calledowned_descendants
which would iterate through all the descendants stopping but not going within an child address map. This could be extended to have some additional generatorsowned_registers
andowned_fields
which provided all the registers / fields that were owned by an address map including those inside descendent register files.
All feedback is gratefully received.
There are several different ways to perform design traversal using the Node API methods. Although Node.descendants()
is the most straightforward, it is pretty brute-force and not particularly flexible as you have discovered.
One option is to perform manual traversal using the Node.children()
method, and then use recursive function calls. This gives you the most control over traversal, but also requires you to handle a lot of it manually.
The JSON exporter example I have in the docs has a good walk through of this method: https://systemrdl-compiler.readthedocs.io/en/stable/examples/json_exporter.html#a-note-on-register-model-traversal
In your case, you would simply skip recursion if you encounter another addrmap node.
I find this method is usually most useful if you are transforming the existing hierarchical RDL register structure into a similar hierarchical data structure in a different format (IP-XACT, JSON, etc) - it lends itself nicely to this since you can use function calls and return values to recursively rebuild your transformation.
Another method is to use the walker/listener protocol described here: https://systemrdl-compiler.readthedocs.io/en/stable/model_traversal.html#using-the-walker-listener
This is on the complete opposite end of the spectrum. This uses a listener class that has numerous callbacks that are called during model traversal. By default, the walker/listener method does not give you any control over how the model is traversed - your callback listener class just relaxes and enjoys the ride as the walker iterates through every element in the design.
In some cases you may want to have some control of the walker's traversal, so I have added a mechanism to the walker/listener protocol to "cancel" traversal at various points. This is done from within the listener callback functions by returning the desired WalkerAction object (Returning None
is equivalent as the Continue
action).
For your case, you could return the SkipDescendants
action from within the enter_Addrmap()
callback. Of course you would need to ensure this is not immediately triggered from the top-level's addrmap callback by either checking if it the same addrmap as the top, or to use the walker's skip_top=True mechanism
I have found the walker/listener mechanism to be quite convenient in the PeakRDL-regblock generator when I generate structs, since it lets me build some pretty nifty and extensible mechanisms. See: https://github.com/SystemRDL/PeakRDL-regblock/blob/main/src/peakrdl_regblock/struct_generator.py#L118