0. Introduction
The Verilog PLI (programming Language Interface) is a mechanism for Verilog code to call C + + functions. It allows Verilog to invoke the user-written C + + function like a system call (such as $display/$stop/$random). PLI can perform the following functions:
- Power analysis
- Code Coverage tools
- Modify the Verilog simulation data structure (e.g., modify to a more precise delay, i.e. SDF reverse)
- Custom Output Display
- Joint simulation
- debugging features of the design
- Simulation analysis
- C-Model interface for accelerated simulation
- Testbench Modeling
To accomplish this, C code needs to be able to access Verilog's internal data structures, so Verilog PLI needs to provide some access to the Assembly (ACC routines), in addition to Verilog PLI provides another set of assemblies: Task function assembly (TF Routines). There are currently two versions of PLI: PLI1.0 and Pli2.0,pli 2.0, also known as VPI, are released with Verilog 20,011.
1. Working principle
1) Writing function
2) Compile and generate the shared library (. DLL in Windows. So in UNIX). Some emulators such as VCs allow static linking.
3) The Veriog code is passed to the compiler (referred to as link linking) in the compile/C + + function details
4) Once the link is complete, it can be like running other verilog simulations.
When the Verilog emulator encounters a user-defined system function, the control is handed over to the PLI program (c + + function)
2. Example-hello World
Here is a simple example where the example does not involve any PLI standard functions (ACC,TF, etc.), so you can simply connect the C + + function with the corresponding emulator.
HELLO.C:
#include <stdio.h> void Hello () { printf ("\nhello world!\n" );}
Hello_pli.v
Module hello_pli (); Initial begin $hello; #ten $finish; End Endmodule
Compile and run using the following VCS command:
Vcs-r-P Hello.tab hello_pli.v hello.c
The contents of the Hello.tab file are as follows:
$hello Call=hello
3. Sample-pli Application
The following example will simply invoke the PLI system function to implement C + + code access to the Verilog code's data structure and apply it to the testbench for monitoring the DUT.
The DUT is designed as a simple 16-binary counter with the COUNTER.V code as follows:
' Timescale 1ns/10psModuleCounter (inputCLK,inputReset,inputEnable,Output Reg[3:0] count); always@(PosedgeClassor Posedgereset)begin if(reset)beginCount<=4'B0; End Else if(enable)beginCount<= count+1'B1; End EndEndmodule
Write the Testbench code PLI_COUNTER_TB.V as follows:
1' Timescale 1ns/10ps2 ModuleCOUNTER_TB ();3 Regenable;4 RegReset;5 RegClk_reg;6 WireCLK;7 Wire[3:0] Dut_count;8 9 Initial beginTenEnable =0; OneClk_reg =0; Areset =0; -$display ("%g, asserting reset", $ Time); -#Tenreset =1; the#Tenreset =0; -$display ("%g, asserting Enable", $ Time); -#TenEnable =1; -# -Enable =0; +$display ("%g, deasserting Enable", $ Time); -#1$display ("%g, terminating Simulator", $ Time); +#1$finish; A End at - always begin -#5Clk_reg =!Clk_reg; - End - - AssignCLK =Clk_reg; in Initial - begin to$dumpfile ("WAVE.VCD"); + $dumpvars; - End the * Initial begin $ $counter _monitor (COUNTER_TB.CLK, Counter_tb.reset, counter_tb.enable, counter_tb.dut_count);Panax Notoginseng End - the Counter U ( + . CLK (CLK), A . Reset (reset), the . Enable (enable), + . Count (Dut_count) - ); $ $ Endmodule
In the code above, line 35-37 calls the user-defined system function $counter_monitor, monitors the signal and prints the value, and this system function is written in C code and invoked through PLI.
C code pli_full_example.c as follows:
#include "Acc_user.h"typedefChar*string; handle CLK; handle reset; handle enable; handle dut_count;intcount;intSim_time;stringHigh ="1"; void counter ();intPli_conv (stringIn_string,intno_bits); void Counter_monitor () {acc_initialize (); CLK= Acc_handle_tfarg (1); Reset= Acc_handle_tfarg (2); Enable= Acc_handle_tfarg (3); Dut_count= Acc_handle_tfarg (4); Acc_vcl_add (Clk,counter,NULL, vcl_verilog_logic); Acc_close ();} void counter () {P_acc_value value; Sim_time=Tf_gettime (); stringI_reset = Acc_fetch_value (Reset,"%b", value); stringI_enable = Acc_fetch_value (Enable,"%b", value); stringI_count = Acc_fetch_value (Dut_count,"%b", value); stringI_CLK = Acc_fetch_value (CLK,"%b", value); intsize_in_bits=acc_fetch_size (Dut_count); intTb_count =0; //Counter function goes here if(*i_reset = = *High ) {Count=0; io_printf ("%d, Dut_info:counter is reset\n", Sim_time); } Else if(*i_enable = = *high) && (*I_CLK = = *High )) { if(Count = = the) {Count=0; } Else{Count= Count +1; } } //Counter Checker function goes Checker logic goes here if((*I_CLK! = *high) && (*i_reset! = *High )) {Tb_count=Pli_conv (i_count,size_in_bits); if(Tb_count! =count) {io_printf ("%d, Dut_error:expect value%d, Got value%d\n", Sim_time, Count, Tb_count); Tf_dofinish (); } Else{io_printf ("%d, Dut_info:expect value%d, Got value%d\n", Sim_time, Count, Tb_count); } }}//multi-bit vector to integer conversion.intPli_conv (stringIn_string,intno_bits) { intCONV =0; inti =0; intj =0; intBin =0; for(i = no_bits-1; I >=0; i = i-1) { if(* (in_string + i) = = the) {bin=1; } Else if(* (in_string + i) = = -) {io_printf ("%d, warning:x detected\n", Sim_time); Bin=0; } Else if(* (in_string + i) = =122) {io_printf ("%d, warning:z detected\n", Sim_time); Bin=0; } Else{bin=0; } CONV= Conv + (1<< J) *bin; J++; } return conv;}
View Code
Because C code calls the PLI system function, it needs to include the header file "Acc_user.h", Acc_user.h can be found in the VCS installation directory, you need to use the VCS command parameters to specify the header file path,
The VCS command is as follows:
" -g-l$vcs_home/linux/lib " +acc+3
The-cflag command parameter is used to pass C compilation parameters to the C compiler because C code uses the Access assembly ACC routines, and +ACC+3;+V2K is added because the code uses the VERILOG2001 syntax.
The-p parameter, like the above example, specifies the tab file, but the difference is that the Access property needs to be added at this time acc,r to read, W to write, Pli_counter.tab as follows:
$counter _monitor Call=counter_monitor acc=rw:*
The results of the operation are as follows:
About Verilog PLI