Support behavioral PLLs/Events
For fpga simulations, most RTL designs have primitives instantiated, like DDIO, PLL and so on. I would like to try and implement this.
From what I understand, these primitives are handled directly by the FPGA synthesis tools and that the verilog/vhdl code for what it actually implements is not available to the designer. FPGA vendors have simulation libraries for these primitives, but they are non-synthesizable.
Option 1: Write a synthesizable verilog code for the functionality taking into account information in the simulation model and the user guide. This could then be added to the file list during a verilator compilation. All these files would move into the verilator source tree to be included in the compilation when such a primitive instantiation is encountered. Pros: No impact on verilator code. Just one more file for it. Cons: Functional equivalency of the synthesizable verilog code needs to be validated thoroughly. Also not all primitives can be written this way (for eg. PLL, DLL. How do we handle it?)
Option 2: Describe these primitives directly in a C model so that they can directly be compiled and linked with the verilated code. Pros: All primitives/cell libraries can be modelled in C/SystemC as synthesizability is not a constraint for C models. Cons: Since these models are essentially part of the DUT, connecting these models to other parts of the DUT would have to be done internally through code. In other words, the DUT top level class has to instantiate our custom model as well and connect it properly.
I personally favour Option 2. There are two major steps to supporting this feature.
1. Writing the C models for all primitives to be supported 2. Framework to connect these models within the DUT.
Any other options of dealing with this, please do let me know.
Let me know your thoughts.
#1 Updated by Wilson Snyder over 3 years ago
- Category set to Unsupported
- Status changed from New to Feature
Of course option 0 is to avoid simulating the pad ring or PLLs at all. Put all such things "outside" the core of the chip and don't worry about them. That's the common approach for ASICs. But I presume that doesn't work for your case.
I've assisted people doing option 1, synthesized macros, in a few cases. As you noted the hardest case is probably PLLs and clock recovery (which uses PLLs internally). I've dealt with those by adding a fake clock input that runs at the needed synchronization frequency, say 1GHz, and the PLL always locks to one of the 1GHz edges instead of really making it's own frequency. If you don't have many models this isn't too bad, maybe a week per model, and each model can be written in parallel among multiple people.
Option two I've debated but have never done - allow SystemC/C++ models to be instantiated under Verilog code. Several of the commercial simulators support something similar. To support this Verilator would need to recognize the "imported" module (easy), mark its pins as public (easy), but then propagate signal changes from that module to the rest of the design (hard). Another mess is handling logic in the imported module that never hits a flop - the imported module may need multiple evaluations to settle out. Unfortunately that means it won't perform very well (or, it will perform like the commercial simulators that do this - which isn't very well ;) For example you should be able to put a separately Verilated module underneath a separately Verilated module. For really large designs this would be nice to support, but is probably a month of work.
The third choice is to expand Verilator to understand the needed behavioral constructs. This perhaps is the best long term option. Having looked only briefly at this, you'd need real numbers (a few weeks work), but the biggest issue there is likely to be the need for delayed statements, so PLLs work, which requires large internal and simulation loop changes so is probably over a month of work. This has the best performance and long term support. I've mentally already filed delayed statements to be part of Verilator 4, so it's gotten a little thought, but no code as yet.
To summarize then, I think it comes down to how much time you're willing to put into model re-writing vs. Verilator improvements.
#3 Updated by Shankar Giri over 3 years ago
Option 3 makes sense. If I understand the requirements correctly, real numbers and delayed statements handling requires implementation first. Since you mention that you've already given these some thought, I'd be very interested to know them. I'll put in a proposal after I go through your suggestions. I'll also be looking into the code to see how the current implementation holds up with regard to supporting these.
#4 Updated by Wilson Snyder over 3 years ago
Real numbers are probably a week's work, they aren't too bad, it's mostly lots of boilerplate to add the various operators and optimizations, and testing. I haven't needed it at my employer (yet), so haven't gotten to it.
Another sub-requirement I forgot to mention is supporting real "time"s and `timescale. That's probably another week or so. It's also not really that complicated, just a mess of places to edit and it needs hooks into in C standalone, SystemC and tracing.
Yet another may be fork-joins and time delays, maybe another week; they can be fairly simply made into state machines, which are very fast. They need first though:
The biggie is a real event loop. It's probably a few month effort, the big challenge is defining the application's calling interface to support it, while still being able to optimize within the simulation loop without loosing much performance.
If you have time to look at implementing any of these, file separate bugs and I'll post more details.