Custom types for annotating a flow object space

I'm looking at using PyPy's flow object space for an experimental converter for MyHDL (http://www.myhdl.org/), a Python library for representing HDL (i.e. hardware) models. By conversion, I mean converting the MyHDL model that represents the hardware into either Verilog or VHDL that downstream tools will support. Currently, there is a converter that works very well in many situations, but there are substantial limitations on the code that can be converted (much greater restrictions than RPython imposes), as well as somewhat frustrating corner cases. It strikes me that much of the heavy lifting of the conversion problem can be handled by the PyPy stack. My question then regards the following. MyHDL represents certain low level structures as python objects. For example, there is a notion of a signal, represented by a Signal object, that has a one to one mapping to the target HDL language. All the attributes of the Signal object describe how it should be converted. So, during annotation, the Signal object should be maintained as a base type, rather than burying deeper into the object to try and infer more about its type (which invariably breaks things due to RPython non-conformity). There are probably a few other types (though not many) that should be handled similarly. How does one instruct the translator to do this? Is it a case of writing a custom TranslationDriver to handle the custom types? Thanks for any help, Henry

Le 22/03/15 20:02, Henry Gomersall a écrit :
No, you simply need to register your Python types with the translator and describe their properties by subclassing some internal classes. The interface is a bit complicated and requires some understanding of RPython's inner workings, but it works. rply has a good example of that: https://github.com/alex/rply/blob/master/rply/lexergenerator.py (specifically, the part that is guarded by 'if rpython:') Here's how it works: The ExtRegistryEntry tells the annotator to special-case Rule objects by annotating them as SomeRule(). SomeRule describes the annotator-level properties of Rule objects while RuleRepr tells the rtyper how to translate them to low-level (C-like) objects. In your case, you definitely need an ExtRegistryEntry and a SomeSignal, but what to put in SignalRepr and whether you even need it depends on how you intend the Verilog/VHDL backend to work.

On 22/03/15 21:45, Ronan Lamy wrote:
Ah, that's fantastic :) So as I understand it, ExtRegistryEntry provides some metaclass magic that auto registers the relevant type as a special case, with the decision made by the object returned from compute_annotation() ? Is there some documentation on this aspect of the internals from RPython? There are obviously lots of questions that would be much easier to get with some docs (ordering? default actions? what the default methods are doing?). Thanks! Henry

Hi Henry. I must say we had quite a bit of a discussion and it seems we did not understand what are you trying to achieve. What is the goal of what you're doing? Translating MyHDL (or verilog) to rpython and compiling it? Something else? Writing the converter itself in RPython? Please explain. Cheers, fijal On Sun, Mar 22, 2015 at 10:02 PM, Henry Gomersall <heng@cantab.net> wrote:

On 23/03/15 08:33, Maciej Fijalkowski wrote:
Essentially, the valid _convertible_ MyHDL would have the constraint of being restricted to RPython. This is essentially a mix of hardware specific types, some simple types and control flow (it's inside a simple generator, and the function is wrapped in a decorator to provide some hardware specific semantics, but I suspect this is not helpful detail). So, we have a series of generators in which the generator code, and all types referenced inside the generator are either written in RPython, or are conceptually a base type (that is, a type that should not be burrowed into and is a direct representation of a hardware feature), that describes the activity of hardware. The intention would be to use PyPy to translate these RPython blocks into VHDL or Verilog. There is support code that is normal python that surrounds these generators which is normal Python, but that is just essentially to set up the name space and attributes of the generator, which is then returned as the active object. Does that all make more sense? Cheers, Henry

On 23/03/15 09:37, Maciej Fijalkowski wrote:
No it doesn't. The VHDL/Verilog parts need to be written. There is a task of inferring flow from a restricted subset of Python, from which V* can be generated. Any solution to the problem looks remarkably like what I understand is being done by RPython. Would you suggest a better strategy? The current solution is built on traversing the AST and special casing certain inferred structures. The IR is never explicit and so it's hard to do much with the flow graph. The concept is that by building on the RPython flow object space as an intermediate representation, much more flexibility can be added to the convertible code (e.g. inferring translated structures from the IR, rather than from the code). Cheers, Henry

As it happens this is of interest to be, because I may have a use for MyHDL or something similar in a year or so. However, from this thread I'm a little confused about where the RPython toolchain would fit in. Sorry if I'm completely off-base here... Presumably you want to keep your Python (2?) front end -- you wouldn't want application programmers using RPython directly, it is really tricky to write in as it's designed for a very specific use case which is very different from generic Python programming. I would guess that the reason for porting MyHDL to an RPython toolchain is that you don't just produce a flat Verilog file, but you also have a runtime system which simulates the Verilog (or the higher level Python description)? This sounds very interesting, I'm not sure how helpful the RPython GCs and JIT would be in your case, but it would be interesting to hear where you think a performance improvement can be made. You might have seen this paper on the PyPy status blog, on instruction set simulators: http://csl.cornell.edu/~cbatten/pdfs/lockhart-pydgin-ispass2015.pdf I don't think it is quite the same as your use case, but there are some interesting ideas in there. Cheers, Sarah On Mon, Mar 23, 2015 at 10:38 AM, Henry Gomersall <heng@cantab.net> wrote:
-- Dr. Sarah Mount, Senior Lecturer, University of Wolverhampton website: http://www.snim2.org/ twitter: @snim2

On 23/03/15 12:10, Sarah Mount wrote:
Well, users currently _are_ restricted to a small subset of "convertible" python. I would suggest this is actually more restrictive than RPython. I suppose the question I have is what happens at the boundary with RPython - can one construct an object that is crosses the boundary, with some RPython only methods and some general Python methods? It might be that code that is RPython compliant cannot also use necessary MyHDL constructs, though there may well be workarounds (it would almost certainly not be the case that the code is too flexible). It's worth noting the MyHDL is several overlapping things. It's first and foremost a library for representing hardware concurrency. If a developer is restricted to only a small subset of valid Python and types, the blocks that are described using MyHDL constructs can be converted into VHDL or Verilog. It allows very neat workflow - one has the full power of Python for defining behaviour, and then one writes the convertible code (which is verified against the behavioural model), and then one cosimulates the converted code, verifying that is doing the write thing (using a Verilog/VHDL simulator).
Well, potentially, but the big win is in being allowed a broader range of convertible constructs. For example, there is currently no way to handle general iterables (only loops of the form `for i in range(N):` are allowed). Clearly, this is very restrictive for writing nice, expressive code. Stepping back a minute. The ultimate goal IMO would be a tool that takes a MyHDL instance block (that is, that represents the function of a hardware block), along with the associated static namespace, and converts into something that downstream tools can understand (VHDL or Verilog), with as much expressive power in the code as makes sense given the target restrictions. All these things are possible in the current approach, but I've been wondering if the similar functionality of similar tools can be used to do some of the heavy lifting. The current approach is essentially trying to implement a "MyHDL restricted" python to VHDL/Verilog translator.
That's interesting. I had seen it but not really noticed it's relevance. Cheers, Henry

Hi, On Mon, Mar 23, 2015 at 12:41 PM, Henry Gomersall <heng@cantab.net> wrote:
On 23/03/15 12:10, Sarah Mount wrote:
<snip>
Ah, my mistake.
Thanks, that has certainly clarified things for me.
Hmm. So, what I understand from this is that your current front-end implements a very small subset of Python, you have noticed that RPython implements a slightly larger subset of Python, so you want to replace your front-end and maybe some internals with the RPython equivalents? I'm not sure how well this will work. For one thing, RPython is intended to be translated to a native format (i.e. you take a description of an interpreter or VM in RPython and after a very long compile you get a native executable that is your interpreter, with any RPython internals, such as JITs and GCs, included). I'm not sure if this is a win for you or not, because I'm not sure if an RPython front-end can really be made to fit a MyHDL back-end, without just re-writing the whole thing as an interpreter. Cheers, Sarah -- Dr. Sarah Mount, Senior Lecturer, University of Wolverhampton website: http://www.snim2.org/ twitter: @snim2

On 23/03/15 12:50, Sarah Mount wrote: <snip>
So, the thinking initially, which I still think might be the route to go, is to tap in to the flow object space. Having a really good representation of the flow graph would be hugely useful in generating the relevant HDL code. If it's possible to also tap into some of the annotation code, this might be useful, but then again it might not :) Cheers, Henry

Hi, On Mon, Mar 23, 2015 at 1:00 PM, Henry Gomersall <heng@cantab.net> wrote:
I don't know enough about the internals of RPython etc. to speak to this. It sounds like it would be more useful to you to try and extract the modules and packages you need and move them over to MyHDL (if your licenses match suitably) rather than using the full toolchain. Perhaps I have the wrong end of the stick though. Sarah -- Dr. Sarah Mount, Senior Lecturer, University of Wolverhampton website: http://www.snim2.org/ twitter: @snim2

Hi all, Thought I would chime in since this is also of interest to me. I have two distinct projects related to hardware simulation, one of which is very well suited towards the RPython toolchain (Pydgin), and another which is much more closely related to MyHDL (PyMTL). Sarah kindly pointed out that Pydgin is relevant here (thanks Sarah!), but I thought it might be useful to briefly summarize both Pydgin and PyMTL to explain why one uses RPython and the other does not. [[ This turned out to be really long, so feel free to check out the TL;DR at the end. ]] == PyMTL== PyMTL (https://github.com/cornell-brg/pymtl) is a framework for hardware design. If you just use PyMTL for RTL-modeling it could very much be considered an alternative to MyHDL: special Python types are provided to model fixed-bitwidth logic that can be simulated directly in Python. Once this behavioral logic is verified in Python simulation, and provided the logic is described in a sufficiently restricted subset of Python, we can then translate it into Verilog. We do not have a VHDL backend. More generally, PyMTL supports multi-level simulation, so that functional-level, cycle-level, and register-transfer level logic can be described, composed, and simulated together. This, along with the way we construct our models (we use Python classes like Verilog modules), makes us a bit different than MyHDL. However, I think the mechanism we use to translate RTL logic into Verilog is quite similar: we have our own "translator" to manually walk the AST of behavioral logic, infer types, and generate Verilog source. [[ Aside: for a clarification of the distinctions between functional-level, cycle-level, and RTL modeling you can see a brief summary here: http://morepypy.blogspot.com/2015/03/pydgin-using-rpython-to-generate-fast.h... ]] == Pydgin == Pydgin (https://github.com/cornell-brg/pydgin) is a framework for constructing fast **functional-level** simulators for processors, also known as Instruction-Set Simulators (ISSs). Pydgin uses the RPython translation toolchain to take simple Python descriptions of a processor's state and instructions and generate a JIT-enabled ISS. This simulator is capable of executing compiled ELF binaries (however, your compiler and your Pydgin ISS must agree on what the target architecture is!). Pydgin is a great match for RPython because writing a simple processor simulator is very similar to writing a bytecode interpreter. Instructions are fetched, decoded, and then executed; the primary difference being that instead of bytecodes we are executing binary instructions extracted from a compiled executable. However, this does not necessarily work for arbitrary hardware. Processors specifically just happen to behave a lot like a language VM. I'm not sure this approach could be used to create say, a fast functional-level model of a router; or a specialized vision-processing accelerator. It certainly wouldn't make sense for something simple like a ripple-carry adder (bad example, but I think you catch what I mean). == Using the RPython for HDL Generation == PyMTL certainly shares the same challenge Henry mentioned in terms of translator/converter/compiler robustness: we only support a subset of Python which is is many ways more restrictive than RPython. I've thought a little bit about using the RPython translation toolchain to make Verilog generation easier; its type analysis is certainly more sophisticated than my simple translator. To make this possible, support for fixed-bitwidth types would be needed for the type annotator, and in our case we would really need support for Python properties because we use these quite a bit. However, I think the RPython translation toolchain wouldn't really address the biggest challenge here, which is lowering the behavioral logic into a representation translatable into synthesizable Verilog. I've actually found the the type annotation to be manageable (although my type inference for local temporaries really could/should be improved), the hard part for me has been transforming the AST into a representation that maps to valid Verilog. This often involves unrolling lists of ports into individual ports, expanding attribute accesses into temporary wires and assignments, determining which signals should be marked as type wire or reg, creating wire lists so that indexed accesses map to the correct input/output ports. More importantly, it would be really nice to know when it simply **is not possible** to convert a Python construct into valid Verilog. My analysis is currently not great at this. I'm not sure the intermediate representation used by the RPython toolchain would be a very good mapping for Verilog, so I'm not entirely sure there is much else than the annotator we could really leverage. That combined with the relative complexity of the RPython toolchain makes it seem like it might not be the right way to go. It will likely need to support much more complex Python code than we could ever hope to convert into Verilog, which results in both slower translation times and potentially complicates maintainability. However, I'm not a compiler expert so I could be (and hopefully I am!) wrong here. == How Can RPython Help RTL Designers? == That being said, I think there are some neat opportunities for using RPython to speed up hardware simulation. Pydgin was certainly one approach, but like I mentioned earlier it only works well for models that behave like an interpreter. However, both MyHDL and PyMTL use Python for hardware simulation, and both have shown rather good speedups when using PyPy. I think the addition of a few features could potentially improve our simulation performance on PyPy even more: === Backend support for fixed bit-width datatypes === RPython already has this for 32-bit integers, but in RTL we are dealing with arbitrary bitwidths. I currently model these in Python using a special Bits class which handles all shifting, slicing, bitmasking, and conversions when interacting with Python ints. I suspect these operations are pretty expensive. Maybe PyPy already does a good job of optimizing these, but it seems like there might be an opportunity here. === Support for tracing loop-less logic === RTL models have very data dependent control flow, however, this control flow very rarely uses loops and instead consists of large if/else trees. If/else trees model muxes which are common in hardware, whereas loops are only sometimes synthesizable into real hardware and are therefore used less frequently (loops in HDL descriptions are generally only synthesizable if they represent logic that will ultimately be unrolled in a hardware implementation). In addition, PyMTL models combinational logic with many small functions and an event queue: the order and frequency in which these small functions are placed on the queue to execute is extremely data-dependent. I suspect the PyPy tracer has a very hard time optimizing this logic. However, we know ahead of time these small functions will be executed very frequently and should be JIT'd, we just don't know the order in which they will execute since this will likely change each iteration through the simulator. For these reasons, we think RTL models are very challenging for PyPy to optimize; and we have data that supports this. If you look at Figure 14 of our PyMTL paper ( http://csl.cornell.edu/~cbatten/pdfs/lockhart-pymtl-micro2014.pdf), you'll see that PyPy is able to give us 25x speedup on a functional-level model of a simple mesh network (~1 primary logic function), a 12x speedup on a cycle-level model (~3*64 primary logic functions), and only a 6x improvement on an RTL model (~14*64 logic functions). A 6x performance improvement is nothing to sneeze at, but it seems like a more detailed model should have an opportunity to get **higher** speedups than less-detailed models because there are more operations to optimize. === Hooks for guaranteeing JITing of specific functions === To address the problems mentioned above, it would be really helpful to be able to mark specific functions as being JIT'able to PyPy. We know these will be executed very frequently, so we don't even need/want a visit counter, just JIT it as soon as you see it. Or maybe set the trace boundries to be the entry and exit of the decorated function. Unfortunately, this is more of a method-based approach and I don't think it's easy to implement in RPython/PyPy. = TL;DR = RPython is great for creating fast simulators for hardware models that act like an interpreter (e.g. processors). I have doubts about how useful it can be for generating Verilog for a Python HDL; although I hope I'm wrong here and someone smarter than me can figure it out. However, I think both MyHDL and PyMTL simulations could greatly benefit from certain PyPy optimizations. Derek On Mon, Mar 23, 2015 at 9:02 AM, Sarah Mount <mount.sarah@gmail.com> wrote:

On 23/03/15 15:26, Derek Lockhart wrote:
PyMTL looks interesting, though I don't quite understand what you mean by multi-level simulation. On the topic at hand, I wonder if there is scope for defining a common intermediate representation (I mean, that both PyMTL and MyHDL can target). Certainly, that would allow substantially more capability for novel schemes for writing to V*, as well as sharing improvements in target generation. If so, perhaps this discussion should be taken off list. My question in the context of PyPy is then, is building on the flow object space sensible here? This is quite a natural fit for MyHDL, as the logic is fully described (including all the signals) inside a single function. Cheers, Henry

On Tue, Mar 24, 2015 at 8:46 PM, Henry Gomersall <heng@cantab.net> wrote:
I'm skeptical. Maybe you can abuse parts of it, but you'll soon realize that some things are not fitting in your model. Additionally, you would need to write verilog/vhdl backend which is a non-trivial amount of work

Le 22/03/15 20:02, Henry Gomersall a écrit :
No, you simply need to register your Python types with the translator and describe their properties by subclassing some internal classes. The interface is a bit complicated and requires some understanding of RPython's inner workings, but it works. rply has a good example of that: https://github.com/alex/rply/blob/master/rply/lexergenerator.py (specifically, the part that is guarded by 'if rpython:') Here's how it works: The ExtRegistryEntry tells the annotator to special-case Rule objects by annotating them as SomeRule(). SomeRule describes the annotator-level properties of Rule objects while RuleRepr tells the rtyper how to translate them to low-level (C-like) objects. In your case, you definitely need an ExtRegistryEntry and a SomeSignal, but what to put in SignalRepr and whether you even need it depends on how you intend the Verilog/VHDL backend to work.

On 22/03/15 21:45, Ronan Lamy wrote:
Ah, that's fantastic :) So as I understand it, ExtRegistryEntry provides some metaclass magic that auto registers the relevant type as a special case, with the decision made by the object returned from compute_annotation() ? Is there some documentation on this aspect of the internals from RPython? There are obviously lots of questions that would be much easier to get with some docs (ordering? default actions? what the default methods are doing?). Thanks! Henry

Hi Henry. I must say we had quite a bit of a discussion and it seems we did not understand what are you trying to achieve. What is the goal of what you're doing? Translating MyHDL (or verilog) to rpython and compiling it? Something else? Writing the converter itself in RPython? Please explain. Cheers, fijal On Sun, Mar 22, 2015 at 10:02 PM, Henry Gomersall <heng@cantab.net> wrote:

On 23/03/15 08:33, Maciej Fijalkowski wrote:
Essentially, the valid _convertible_ MyHDL would have the constraint of being restricted to RPython. This is essentially a mix of hardware specific types, some simple types and control flow (it's inside a simple generator, and the function is wrapped in a decorator to provide some hardware specific semantics, but I suspect this is not helpful detail). So, we have a series of generators in which the generator code, and all types referenced inside the generator are either written in RPython, or are conceptually a base type (that is, a type that should not be burrowed into and is a direct representation of a hardware feature), that describes the activity of hardware. The intention would be to use PyPy to translate these RPython blocks into VHDL or Verilog. There is support code that is normal python that surrounds these generators which is normal Python, but that is just essentially to set up the name space and attributes of the generator, which is then returned as the active object. Does that all make more sense? Cheers, Henry

On 23/03/15 09:37, Maciej Fijalkowski wrote:
No it doesn't. The VHDL/Verilog parts need to be written. There is a task of inferring flow from a restricted subset of Python, from which V* can be generated. Any solution to the problem looks remarkably like what I understand is being done by RPython. Would you suggest a better strategy? The current solution is built on traversing the AST and special casing certain inferred structures. The IR is never explicit and so it's hard to do much with the flow graph. The concept is that by building on the RPython flow object space as an intermediate representation, much more flexibility can be added to the convertible code (e.g. inferring translated structures from the IR, rather than from the code). Cheers, Henry

As it happens this is of interest to be, because I may have a use for MyHDL or something similar in a year or so. However, from this thread I'm a little confused about where the RPython toolchain would fit in. Sorry if I'm completely off-base here... Presumably you want to keep your Python (2?) front end -- you wouldn't want application programmers using RPython directly, it is really tricky to write in as it's designed for a very specific use case which is very different from generic Python programming. I would guess that the reason for porting MyHDL to an RPython toolchain is that you don't just produce a flat Verilog file, but you also have a runtime system which simulates the Verilog (or the higher level Python description)? This sounds very interesting, I'm not sure how helpful the RPython GCs and JIT would be in your case, but it would be interesting to hear where you think a performance improvement can be made. You might have seen this paper on the PyPy status blog, on instruction set simulators: http://csl.cornell.edu/~cbatten/pdfs/lockhart-pydgin-ispass2015.pdf I don't think it is quite the same as your use case, but there are some interesting ideas in there. Cheers, Sarah On Mon, Mar 23, 2015 at 10:38 AM, Henry Gomersall <heng@cantab.net> wrote:
-- Dr. Sarah Mount, Senior Lecturer, University of Wolverhampton website: http://www.snim2.org/ twitter: @snim2

On 23/03/15 12:10, Sarah Mount wrote:
Well, users currently _are_ restricted to a small subset of "convertible" python. I would suggest this is actually more restrictive than RPython. I suppose the question I have is what happens at the boundary with RPython - can one construct an object that is crosses the boundary, with some RPython only methods and some general Python methods? It might be that code that is RPython compliant cannot also use necessary MyHDL constructs, though there may well be workarounds (it would almost certainly not be the case that the code is too flexible). It's worth noting the MyHDL is several overlapping things. It's first and foremost a library for representing hardware concurrency. If a developer is restricted to only a small subset of valid Python and types, the blocks that are described using MyHDL constructs can be converted into VHDL or Verilog. It allows very neat workflow - one has the full power of Python for defining behaviour, and then one writes the convertible code (which is verified against the behavioural model), and then one cosimulates the converted code, verifying that is doing the write thing (using a Verilog/VHDL simulator).
Well, potentially, but the big win is in being allowed a broader range of convertible constructs. For example, there is currently no way to handle general iterables (only loops of the form `for i in range(N):` are allowed). Clearly, this is very restrictive for writing nice, expressive code. Stepping back a minute. The ultimate goal IMO would be a tool that takes a MyHDL instance block (that is, that represents the function of a hardware block), along with the associated static namespace, and converts into something that downstream tools can understand (VHDL or Verilog), with as much expressive power in the code as makes sense given the target restrictions. All these things are possible in the current approach, but I've been wondering if the similar functionality of similar tools can be used to do some of the heavy lifting. The current approach is essentially trying to implement a "MyHDL restricted" python to VHDL/Verilog translator.
That's interesting. I had seen it but not really noticed it's relevance. Cheers, Henry

Hi, On Mon, Mar 23, 2015 at 12:41 PM, Henry Gomersall <heng@cantab.net> wrote:
On 23/03/15 12:10, Sarah Mount wrote:
<snip>
Ah, my mistake.
Thanks, that has certainly clarified things for me.
Hmm. So, what I understand from this is that your current front-end implements a very small subset of Python, you have noticed that RPython implements a slightly larger subset of Python, so you want to replace your front-end and maybe some internals with the RPython equivalents? I'm not sure how well this will work. For one thing, RPython is intended to be translated to a native format (i.e. you take a description of an interpreter or VM in RPython and after a very long compile you get a native executable that is your interpreter, with any RPython internals, such as JITs and GCs, included). I'm not sure if this is a win for you or not, because I'm not sure if an RPython front-end can really be made to fit a MyHDL back-end, without just re-writing the whole thing as an interpreter. Cheers, Sarah -- Dr. Sarah Mount, Senior Lecturer, University of Wolverhampton website: http://www.snim2.org/ twitter: @snim2

On 23/03/15 12:50, Sarah Mount wrote: <snip>
So, the thinking initially, which I still think might be the route to go, is to tap in to the flow object space. Having a really good representation of the flow graph would be hugely useful in generating the relevant HDL code. If it's possible to also tap into some of the annotation code, this might be useful, but then again it might not :) Cheers, Henry

Hi, On Mon, Mar 23, 2015 at 1:00 PM, Henry Gomersall <heng@cantab.net> wrote:
I don't know enough about the internals of RPython etc. to speak to this. It sounds like it would be more useful to you to try and extract the modules and packages you need and move them over to MyHDL (if your licenses match suitably) rather than using the full toolchain. Perhaps I have the wrong end of the stick though. Sarah -- Dr. Sarah Mount, Senior Lecturer, University of Wolverhampton website: http://www.snim2.org/ twitter: @snim2

Hi all, Thought I would chime in since this is also of interest to me. I have two distinct projects related to hardware simulation, one of which is very well suited towards the RPython toolchain (Pydgin), and another which is much more closely related to MyHDL (PyMTL). Sarah kindly pointed out that Pydgin is relevant here (thanks Sarah!), but I thought it might be useful to briefly summarize both Pydgin and PyMTL to explain why one uses RPython and the other does not. [[ This turned out to be really long, so feel free to check out the TL;DR at the end. ]] == PyMTL== PyMTL (https://github.com/cornell-brg/pymtl) is a framework for hardware design. If you just use PyMTL for RTL-modeling it could very much be considered an alternative to MyHDL: special Python types are provided to model fixed-bitwidth logic that can be simulated directly in Python. Once this behavioral logic is verified in Python simulation, and provided the logic is described in a sufficiently restricted subset of Python, we can then translate it into Verilog. We do not have a VHDL backend. More generally, PyMTL supports multi-level simulation, so that functional-level, cycle-level, and register-transfer level logic can be described, composed, and simulated together. This, along with the way we construct our models (we use Python classes like Verilog modules), makes us a bit different than MyHDL. However, I think the mechanism we use to translate RTL logic into Verilog is quite similar: we have our own "translator" to manually walk the AST of behavioral logic, infer types, and generate Verilog source. [[ Aside: for a clarification of the distinctions between functional-level, cycle-level, and RTL modeling you can see a brief summary here: http://morepypy.blogspot.com/2015/03/pydgin-using-rpython-to-generate-fast.h... ]] == Pydgin == Pydgin (https://github.com/cornell-brg/pydgin) is a framework for constructing fast **functional-level** simulators for processors, also known as Instruction-Set Simulators (ISSs). Pydgin uses the RPython translation toolchain to take simple Python descriptions of a processor's state and instructions and generate a JIT-enabled ISS. This simulator is capable of executing compiled ELF binaries (however, your compiler and your Pydgin ISS must agree on what the target architecture is!). Pydgin is a great match for RPython because writing a simple processor simulator is very similar to writing a bytecode interpreter. Instructions are fetched, decoded, and then executed; the primary difference being that instead of bytecodes we are executing binary instructions extracted from a compiled executable. However, this does not necessarily work for arbitrary hardware. Processors specifically just happen to behave a lot like a language VM. I'm not sure this approach could be used to create say, a fast functional-level model of a router; or a specialized vision-processing accelerator. It certainly wouldn't make sense for something simple like a ripple-carry adder (bad example, but I think you catch what I mean). == Using the RPython for HDL Generation == PyMTL certainly shares the same challenge Henry mentioned in terms of translator/converter/compiler robustness: we only support a subset of Python which is is many ways more restrictive than RPython. I've thought a little bit about using the RPython translation toolchain to make Verilog generation easier; its type analysis is certainly more sophisticated than my simple translator. To make this possible, support for fixed-bitwidth types would be needed for the type annotator, and in our case we would really need support for Python properties because we use these quite a bit. However, I think the RPython translation toolchain wouldn't really address the biggest challenge here, which is lowering the behavioral logic into a representation translatable into synthesizable Verilog. I've actually found the the type annotation to be manageable (although my type inference for local temporaries really could/should be improved), the hard part for me has been transforming the AST into a representation that maps to valid Verilog. This often involves unrolling lists of ports into individual ports, expanding attribute accesses into temporary wires and assignments, determining which signals should be marked as type wire or reg, creating wire lists so that indexed accesses map to the correct input/output ports. More importantly, it would be really nice to know when it simply **is not possible** to convert a Python construct into valid Verilog. My analysis is currently not great at this. I'm not sure the intermediate representation used by the RPython toolchain would be a very good mapping for Verilog, so I'm not entirely sure there is much else than the annotator we could really leverage. That combined with the relative complexity of the RPython toolchain makes it seem like it might not be the right way to go. It will likely need to support much more complex Python code than we could ever hope to convert into Verilog, which results in both slower translation times and potentially complicates maintainability. However, I'm not a compiler expert so I could be (and hopefully I am!) wrong here. == How Can RPython Help RTL Designers? == That being said, I think there are some neat opportunities for using RPython to speed up hardware simulation. Pydgin was certainly one approach, but like I mentioned earlier it only works well for models that behave like an interpreter. However, both MyHDL and PyMTL use Python for hardware simulation, and both have shown rather good speedups when using PyPy. I think the addition of a few features could potentially improve our simulation performance on PyPy even more: === Backend support for fixed bit-width datatypes === RPython already has this for 32-bit integers, but in RTL we are dealing with arbitrary bitwidths. I currently model these in Python using a special Bits class which handles all shifting, slicing, bitmasking, and conversions when interacting with Python ints. I suspect these operations are pretty expensive. Maybe PyPy already does a good job of optimizing these, but it seems like there might be an opportunity here. === Support for tracing loop-less logic === RTL models have very data dependent control flow, however, this control flow very rarely uses loops and instead consists of large if/else trees. If/else trees model muxes which are common in hardware, whereas loops are only sometimes synthesizable into real hardware and are therefore used less frequently (loops in HDL descriptions are generally only synthesizable if they represent logic that will ultimately be unrolled in a hardware implementation). In addition, PyMTL models combinational logic with many small functions and an event queue: the order and frequency in which these small functions are placed on the queue to execute is extremely data-dependent. I suspect the PyPy tracer has a very hard time optimizing this logic. However, we know ahead of time these small functions will be executed very frequently and should be JIT'd, we just don't know the order in which they will execute since this will likely change each iteration through the simulator. For these reasons, we think RTL models are very challenging for PyPy to optimize; and we have data that supports this. If you look at Figure 14 of our PyMTL paper ( http://csl.cornell.edu/~cbatten/pdfs/lockhart-pymtl-micro2014.pdf), you'll see that PyPy is able to give us 25x speedup on a functional-level model of a simple mesh network (~1 primary logic function), a 12x speedup on a cycle-level model (~3*64 primary logic functions), and only a 6x improvement on an RTL model (~14*64 logic functions). A 6x performance improvement is nothing to sneeze at, but it seems like a more detailed model should have an opportunity to get **higher** speedups than less-detailed models because there are more operations to optimize. === Hooks for guaranteeing JITing of specific functions === To address the problems mentioned above, it would be really helpful to be able to mark specific functions as being JIT'able to PyPy. We know these will be executed very frequently, so we don't even need/want a visit counter, just JIT it as soon as you see it. Or maybe set the trace boundries to be the entry and exit of the decorated function. Unfortunately, this is more of a method-based approach and I don't think it's easy to implement in RPython/PyPy. = TL;DR = RPython is great for creating fast simulators for hardware models that act like an interpreter (e.g. processors). I have doubts about how useful it can be for generating Verilog for a Python HDL; although I hope I'm wrong here and someone smarter than me can figure it out. However, I think both MyHDL and PyMTL simulations could greatly benefit from certain PyPy optimizations. Derek On Mon, Mar 23, 2015 at 9:02 AM, Sarah Mount <mount.sarah@gmail.com> wrote:

On 23/03/15 15:26, Derek Lockhart wrote:
PyMTL looks interesting, though I don't quite understand what you mean by multi-level simulation. On the topic at hand, I wonder if there is scope for defining a common intermediate representation (I mean, that both PyMTL and MyHDL can target). Certainly, that would allow substantially more capability for novel schemes for writing to V*, as well as sharing improvements in target generation. If so, perhaps this discussion should be taken off list. My question in the context of PyPy is then, is building on the flow object space sensible here? This is quite a natural fit for MyHDL, as the logic is fully described (including all the signals) inside a single function. Cheers, Henry

On Tue, Mar 24, 2015 at 8:46 PM, Henry Gomersall <heng@cantab.net> wrote:
I'm skeptical. Maybe you can abuse parts of it, but you'll soon realize that some things are not fitting in your model. Additionally, you would need to write verilog/vhdl backend which is a non-trivial amount of work
participants (5)
-
Derek Lockhart
-
Henry Gomersall
-
Maciej Fijalkowski
-
Ronan Lamy
-
Sarah Mount