Major Tools
Other Tools
General Info

verilating/compiling modules into separate object files

Added by Alex Solomatnikov almost 10 years ago

Is it possible to verilate/compile several modules into separate object files and then link them together to create simulator executable?

The problem is that it is difficult to get Verilog source code for some IP blocks because they belong to 3rd party providers which are only willing to provide encrypted RTL. Unfortunately, the option of "just say no" is not available here since this involves some unique IP without any alternatives and there is no way to negotiate directly with the provider.

Since as far as I understand verilator does not handle encrypted Verilog, another idea came to mind: to verilate/compile IP RTL into an object file and use it as a form of encryption. Not sure if everybody would agree with this approach but at least I think it would be much easier.

Replies (7)

RE: verilating/compiling modules into separate object files - Added by Wilson Snyder almost 10 years ago

The approach has merit; some IP vendors already provide Verilated models of whole chips.

Unfortunately though there's no way to include such a model underneath another Verilated model. The only option currently open is to put it to the "side" and create your own C++/SC wrapper.

Sorry, it's not a easy thing to add support for, but if you or someone has a lot of time to do it let me know.

RE: verilating/compiling modules into separate object files - Added by Jim Kulp over 9 years ago

I just starting using verilator, and I ran into this issue in the first hour. We do modular builds bottom up and I was hoping to use verilator without requiring a global processing of all the verilog in one monolithic step. So I'm just checking whether modular builds are a future roadmap item or are likely to be available "soon". It was very easy to build/compile a ".a" library of low level modules, each "verilated", but no way to use such a library. I noticed the "system perl wrapper script" in another forum issue, but I'm not sure if this is the same thing.

RE: verilating/compiling modules into separate object files - Added by Wilson Snyder over 9 years ago

I'm not sure of the world "build" in your context. The feature to run verilator on different modules, is unlikely to come soon, as it requires some complex gymnastics including resolving dotted references, tracing, and such. However you are free to take the files Verilator makes and compile them into .a files in hierarchies or however you wish, you'll just need to write your own makefile. Also, if your project is large, use ccache and distcc, or equivalent - see the docs.

RE: verilating/compiling modules into separate object files - Added by Jim Kulp over 9 years ago

Thanks for the quick response. I'll try to be clearer. By "build" I mean a generic workflow that we use for lots of different technologies and tools, including Xilinx and Altera synthesis tools and simulators. Some synthesis tools are happy seeing a reference to a "black box" module, and then later incorporating a precompiled/presynthesized core in its place (at "link" time). I was hoping to copy that pattern with verilator. One experiment I was going to try was a block box/empty declaration that was forced to be not-inlined, and then throw away the generated file for that empty module, and link against a library that included the real module. Does that make sense to try? (Assuming I guarantee that the empty module is identical including parameters to the real one).

RE: verilating/compiling modules into separate object files - Added by Wilson Snyder over 9 years ago

I understand. Unfortunately that's exactly what's not supported. (Nor BTW is it supported by most of the simulator vendors; again those nasty dotted references and elaboration difficulties.)

It's not worth trying it, Verilator flattens the design and it won't work to substitute a model under the covers.

RE: verilating/compiling modules into separate object files - Added by Wilson Snyder over 9 years ago

Here's some notes on getting modular compiles in Verilator. I know it would be much appreciated by many users, as it's valuable not only for embedding IP, but also because it would reduce compile time and icache footprints for highly replicated designs like multicore chips.

First it's worth noting that a Verilated module has always been allowed to be instantiated multiple times at a level "above" either in C or SystemC, what's new is the Verilated-under-Verilated (or more generally C-or-something-else-under-Verilated). Also I'd note DPI callbacks, tracing and coverage already mostly support hierarchical calls (due to how they work inside SystemC), and if they don't "just work" should require only minor changes.

As far as limitations, SystemVerilog elaboration will cause a mess. To get started, we probably simply require that the instantiated module not have any parameter overrides, nor can it have any dotted variable or function references that cross the "boundary". Later we could make a two-pass approach where pass one finds all dotted references in every level, and then the second pass can read all of the dotted requirements and do the "real" object generation.


First, thoughts on the "child" Verilator run.

Obviously we'll need a flag for this mode. That can be your first edit! (V3Options.* is what you want, and document in bin/verilator.)

Take a look at the eval() routine after an existing Verilator run. Fundamentally what we are trying to do is split that eval() routine into calls that can poke inside child runs (that likewise were made by Verilator).

The first thing that flag will do is turn off (maybe modify) generation of the eval() routine in V3EmitC.

The flag will also generate a data file which can be fed to upper level Verilator runs. To match what some other tools do, this data file would look just like a Verilog "module" file, with input and output statements as usual, but also special /*verilator*/ comments attached. The closer it looks to "normal" verilog the less work it will be; it also makes it easier to debug. As a rough idea...

// This module automatically generated by verilator --gen-child
// etc, etc, etc.
module child (
           input clk,
           input rst,
           input d,
           output q
   // verilator foreign_module
   initial begin
        // verilator foreign_eval _EVAL1
        // verilator foreign_write q
   always @ (negedge rst) begin
        // verilator foreign_eval _EVAL2
        // verilator foreign_write q
   always @ (posedge clk) begin
        // verilator foreign_eval _EVAL2
        // verilator foreign_read rst
        // verilator foreign_read d
        // verilator foreign_write q
   final begin
        // verilator foreign_eval _EVAL3
   // Below indicates that _change_detect() needs to be called, it doesn't just return "1".
   // verilator foreign_change_detect _change_detect

Note this indicates:

  • For every input, the clock domain (in terms of what function to call) for that input. If it goes directly to a flop it's just the clock domain of that flop (in terms of other inputs), otherwise it's sensitive to the other combo logic signals that feed in.
  • For every output, the eval function generating it.
  • The routine names to call to do the "real" internal work.

Verilator already has clock domain information, processed in V3Order, needed to produce the above, so it's mostly a plumbing job to pass the info down to a new stage, say V3EmitChild.cpp. This can borrow much of the guts of V3EmitV (most of V3EmitV would be moved to a header file to avoid duplicate code).

We also need to prevent clock races involving combo logic (imagine a chain of combo logic that crosses between parent and child several times before hitting a flop) and generated clocks. I think that means that a single _EVAL call isn't always enough, we really need the lower level _eval routines to be known to the parent. That will mean a few more pragmas than just foreign_eval; we can deal with that later.


The parent run will resolve the child's module using the module generated above by the child verilator run. Thus I don't think it needs any runtime switch to know it's including a child. (But of course if this parent is going to be a child to a higher level, it would need the same --gen-child flag as we made above.)

verilog.l and verilog.y need to parse the new verilator pragmas, and make new Ast node types for each pragma (see V3AstNodes.h).

Now it's a matter of plumbing those new Ast types everywhere they are needed. Fortunately I don't think it's too bad, since we've made it look like "normal" Verilog. V3Gate needs to know not to optimize these routines, and in V3Order, the eval-child calls get translated to AstCCalls. (Which will in V3Emit become calls to the child's eval routines.)

V3Emit will need some minor changes to call the submodule's constructor.

Getting started

Hopefully this isn't too much to scare you off. I'd suggest ignoring the child problem at the beginning, and focus on the parent by creating a sample proposed "verilator foreign_module" by hand based on something simple (like the flop above), we'll review it, then get it to parse in the parent, and call a hand generated "C" module, and finally work on generating it as the child. But you're of course welcome to do it in the other order (child first) if it sounds more interesting to you.

Feel free to ask questions and feed me changes for thoughts.