Next: , Previous: VPI with Channels, Up: Co-simulation


6.6 Hierarchical co-simulation

The final example demonstrates how to co-simulate with Verilog placeholder definitions in HAC. This allows one to co-simulate any Verilog definition with circuits anywhere in the instance hierarchy in HAC.

Suppose you have some Verilog library that contains definitions that you wish to connect in HAC but simulate in Verilog.

     // "lib.v"
     module FLIPFLOP(d, q, clk);
       in d, clk;
       out q;
     ...
     end module

In HAC one would define a placeholder definition:

     defproc FLIPFLOP(bool d, q, clk) { }

and you could instantiate FLIPFLOPs anywhere and everywhere in the circuit hierarchy. It would be extremely tedious to connect each HAC instance to a corresponding Verilog instance by hand, using just $to_prsim and $from_prsim calls.

This problem is solved by taking advantage of modularity of Verilog module definitions.

     // "lib.v-wrap"
     module HAC_FLIPFLOP;
       wire d, q, clk;
       parameter prsim_name="";
       reg [64*8:1] verilog_name;
       FLIPFLOP dummy(d, q, clk);
       initial begin
       #0
       if (prsim_name != "") begin
         $sformat(verilog_name, "%m");
         $from_prsim({prsim_name, ".d"}, {verilog_name, ".d"});
         $from_prsim({prsim_name, ".clk"}, {verilog_name, ".clk"});
         $to_prsim({verilog_name, ".q"}, {prsim_name, ".q"});
       end
       end
     endmodule

Every Verilog instance of HAC_FLIPFLOP instantiates a local FLIPFLOP and automatically connect its ports to hacprsim, provided you set the prsim_name parameter using defparam. The explicit #0 timestamp guarantees that the functions are not called until after initial statements, when the HAC object file is supposed to be loaded. For every instance of FLIPFLOP in the HAC hierarchy:

     module TOP;
     ...
     HAC_FLIPFLOP __0();
     defparam __0.prsim_name="x.y[0]";
     HAC_FLIPFLOP __1();
     defparam __1.prsim_name="x.y[1]";
     HAC_FLIPFLOP __2();
     defparam __2.prsim_name="x.q.w";
     ...
     endmodule

How do you find every instance of FLIPFLOP in the HAC hierarchy? The current method is to query the allocate-compiled object file:

     $ hacobjdump inst_foo.haco-a > inst_foo.objdump 2>&1
     $ sed -n  '/Globally allocated state/,$p' inst_foo.objdump | \
         sed -n '/\[global process entries\]/,/\[global.*entries\]/p' | \
         grep "^[0-9]" | cut -f5-6 > inst_foo.processes

The resulting inst_foo.proceses lists every unique process with its type1. The user can construct a database of known Verilog types to extract the canonical prsim names of all Verilog wrapper processes in the HAC namespace. From there, it is trivial to generate top-level Verilog instantiations of all wrappers.

What if there are a hundred definitions across Verilog libraries? Fortunately, we have already written such script to convert entire libraries into wrapper definitions.

     $ bindir/wrap_verilog_modules_to_hacprsim.awk lib.v > lib.v-wrap

Limitations: arrays and buses (in progress), template parameters (not yet).

To use the output file lib.v-wrap in your top-level Verilog file:

     `include "lib.b"
     `include "lib.v-wrap"
     
     module TOP;
     // instantiate Verilog wrappers, set their prsim_names
     ...
     endmodule

If you've copied the example directory already, the target that demonstrates this process is and_tree.vx-log. The Verilog library is standard.v which begets standard.v-wrap. and_tree.hac instantiates and connects a tree of AND gates which are defined in the Verilog library. and_tree.v includes the library and its wrapper, and instantiates top-level instances to connect to hacprsim. The simulation stimulus just toggles some of the input signals to the AND-tree.


Footnotes

[1] This would much more elegant using the Scheme interface of hacguile.