-
Notifications
You must be signed in to change notification settings - Fork 585
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
using --public
in verilator
#2071
Comments
Actually - I found that verilator will sometime generate a VL_SIG for internal module signals and other time not. What determines this behavior? This could be useful... |
Similar work was recently done for cocotb (https://github.com/cocotb/cocotb). It uses VPI and currently the preferred way is to use |
And you should not mess with anything not explicitly exposed as public. The preferred way is to use DPI, but VPI is probably what you are looking at. |
See #2072 |
@wallento actually - I just took a look at cocotb. It seems like there is a branch of cocotb that supports VPI? |
In my Vtop.h I see: VL_MODULE(Vtop) {
public:
// PORTS
// The application code writes and reads these signals to
// propagate new values into/out from the Verilated model.
// Begin mtask footprint all:
VL_IN8(op,0,0);
VL_IN16(a,15,0);
VL_IN16(b,15,0);
VL_OUT16(o,15,0);
// LOCAL SIGNALS
// Internals; generally not touched by application code
// Begin mtask footprint all:
VL_SIG8(top__DOT__op,0,0);
VL_SIG16(top__DOT__a,15,0);
VL_SIG16(top__DOT__add_a,15,0);
VL_SIG16(top__DOT__add_b,15,0);
VL_SIG16(top__DOT__add_o,15,0); I assume its ok to access the local VL_SIGs? |
cocotb is based on VPI, it is the mainline. You can find the recent PR where I added support for Verilator here: cocotb/cocotb#943 It is safe to read them, but I propose to use |
I'm adding a verilator backend to nMigen(then new and improved Migen). |
Although I said I would only be reading internals - it turns out there is a useful cases for writing internals too. But even though the |
Most likely you write a value then the next eval overwrites it, it is not a force. Make sure you are e.g. writing a flop's storage that is not getting loaded (or not clocked). |
I had a doing |
Like this?
Build:
Run:
Can you elaborate a bit more if you want to do random accesses? Can you synthesize DPI into the design? Inserting DPI into your modules is the most portable and fast way. |
Huh. That's strange^^.. Lemme see what I was missing. |
Ah, its from yosys, than DPI may probably only be an option if you put a wrapper around your design:
Updated
Build and run:
Generating accessors in the modules by yosys is both a rabbit hole and probably out of scope for yosys. |
DPI is definitely the way to go then! |
Also, do you know how I can guarantee DPI is thread safe?
On designs of notable size, it should make sense to enable |
Well, the trade-off between VPI and DPI is that VPI can access arbitrary signals (hence --public-flat-rw) and DPI is limited to compile time accesses (dynamicity is only the scope). For that you get a speed of DPI comparable to directly accessing the signals. The latter is the fastest, but limited to Verilator. I would say the speed difference between DPI and Verilator native is negligible.. |
About threads @wsnyder can probably comment better |
Thanks again. Lastly, I've gotten reads and writes to work for signals less than 32 bits long with DPI. But how can I return a 75 bit signal for example? I imagine verilator should see this as some sort of array of chars or perhaps uints... |
I would suggest not using --threads-dpi, which will use the default pure option. If you benchmark and find DPI uses most of the time, possibly the all option could be used but the app's DPI C code likely needs fixing to support that. |
OK - I figured out how to get DPI accesses of arbitrary width. |
I've pasted example getter and setter DPI methods for working with widths greater than 64 should any one else find these useful. rm -rf obj_dir/
verilator --cc --exe test_wrap.v test.v test.cpp
make -C obj_dir/ -f Vtest_wrap.mk
./obj_dir/Vtest_wrap test.vmodule t (input [71:0] a, output [71:0] o);
adder add (.a(a), .b(), .o(o));
endmodule
module adder (input [71:0] a, input [71:0] b, output [71:0] o);
assign o = a + b;
endmodule
test_wrap.vmodule t_wrap (input [71:0] a, output [71:0] o);
t dut (.a(a), .o(o));
export "DPI-C" function read_a;
function void read_a(output bit [71:0] result);
result = dut.add.a;
endfunction
export "DPI-C" function write_a;
function void write_a(input bit [71:0] in);
dut.add.a = in;
endfunction
endmodule test.cpp#include "Vtest_wrap.h"
#include <cstdio>
extern void write_b(char);
void print_by_int(uint32_t* val){
printf("print_by_int\n");
for(int i = 0; i < 3; i++)
{
printf("%d: ",i);
printf("%2x\n",val[i]);
}
}
int main(int argc, char** argv) {
Vtest_wrap top;
svSetScope(svGetScopeFromName("TOP.t_wrap"));
//set and read top.a using verilator public method
top.a[0] = 1;
top.a[1] = 2;
top.a[2] = 3;
top.eval();
printf("from verilator ");
print_by_int(top.a);
//set top.a using DPI and read with DPI
uint32_t ret[] = {0,0,128};
top.write_a((svBitVecVal *)&ret);
printf("from DPI ");
print_by_int(ret);
//read top.a with verilator public method - should
//match output of DPI
printf("from verilator ");
print_by_int(top.a);
top.final();
return 0;
} output
|
So DPI exporting worked with smaller designs. But now I am trying to simulate a RISCV CPU and verilator is changing the names of the DPI functions I defined in its header file. For example, I originally had The header file also has this new section called
I should note that I wrote DPI access methods for all the port signals in my verilog generated from nMigen. So this is about a few hundred... Could this simply be too many DPI methods for verilator to handle? I'm also quite certain that the names have no special symbols. |
Turns out I did have some illegal characters. All good now. |
Great! |
I and currently trying to use verilator as the backend simulator for the Python Migen HDL. I know this was done with Scala Chisel. In order to be useful, I need to peek at hierarchical signals. Unit tests often do look and inputs and output in submodules. I read that
--public
might result in mis-simulations for clocks. What exactly does this mean? How do you suggest I go about exposing sub netlist signals?I should add that I don't plan to modify sub signals - only read them.
The text was updated successfully, but these errors were encountered: