The recommended way to access signals is via a Verilog task or function. These are converted by Verilator into C++ class functions. Inputs to tasks and functions become arguments passed by value to the C++ function, while outputs become arguments passed by reference (and so can be used for results).
Verilog tasks become C++ void functions, while Verilog functions become C++ functions with a return type of a size appropriate to the result of the Verilog function (uint8_t, uint16_t, uint32_t or uint64_t).
Caution | |
---|---|
One limitation of Verilator is that it cannot handle functions which return values of more than 64 bits. If this is required, an output argument of either a task or function should be used. |
For an example consider the 32-bit wb_insn
register in the ORPSoC control unit. It's full hierarchical
reference is:
orpsoc_fpga_top.or1200_top.or1200_cpu.or1200_ctrl.wb_insn
It is declared as:
reg [31:0] wb_insn;
A Verilog function is declared to give access to this register:
`ifdef verilator function [31:0] get_wb_insn; // verilator public get_wb_insn = wb_insn; endfunction // get_wb_insn `endif
There are two items of note. First the function must include a
verilog public
comment immediately after its
declaration. Secondly functions without inputs are not permitted in
IEEE 1364-2001, so this code must only be exposed to Verilator
processing.
Verilator defines verilator
, so this can be
achieved by surrounding the code with
`ifdef verilator
and
endif
.
The signal can then be accessed from C++, having included the headers for all the intermediate classes:
#include "Vorpsoc_fpga_top_orpsoc_fpga_top.h" #include "Vorpsoc_fpga_top_or1200_top.h" #include "Vorpsoc_fpga_top_or1200_cpu.h" #include "Vorpsoc_fpga_top_or1200_ctrl.h" ... Vorpsoc_fpga_top *orpsoc = new Vorpsoc_fpga_top ("orpsoc"); ... uint32_t wb_insn = orpsoc->v->or1200_top->or1200_cpu->or1200_ctrl->get_wb_insn ();
Accessor functions typically require no inputs. This is acceptable
to Verilator, but is not valid Verilog according to IEEE
1364-2001. Thus (as in the example above), these functions must be
surrounded by `ifdef verilator
and
endif
so they are only seen by Verilator
Verilator cannot make public functions with return values of
greater than 64-bits. Such results should be returned via an
output
argument, where they will be an array of
uint32_t.