深入浅出FPGA-18-VPI
2014-03-24 21:07
302 查看
引言
我们在进行RTL仿真时,有时候会遇到HDL工程和C语言工程需要进行数据通信时,使用$readmem()等系统任务会方便很多,但是有时候,实现较复杂功能时,$readmem()就会稍显不足。这时,就需要我们编写特殊的系统任务,来实现。HDL语言提供的PLI,VPI正是为了解决这个问题而设计的,本小节,我们就熟悉一下VPI。
1,VPI简介
Verilog过程接口(Verilog Procedural Interface, VPI),最初被称为编程语言接口(Program Language Interface, PLI) 2.0,是一个针对C语言的Verilog过程接口。它可以使数字电路的行为级描述代码直接调用C语言的函数,而用到的C语言函数也可以调用标准的Verilog系统任务。Verilog程序结构是IEEE 1364编程语言接口标准的一部分。它最新的版本是2005年更新的。更多信息请参考: http://en.wikipedia.org/wiki/Verilog_Procedural_Interface
和 http://www.asic-world.com/verilog/pli6.html#Verilog_Procedural_Interface_(VPI)
2,简单示例
在了解了VPI的含义以及工作原理之后,我们通过下面一个简单的例子来说明VPI的具体使用方法。针对不同的仿真工具(VCS,modelsim,NC sim),使用VPI有不同的方式。
本实验以modelsim为例。
a,编写C语言实现
hello.c/* * vpi simple test * rill,2014-03-21 */ #include "vpi_user.h" static PLI_INT32 hello(PLI_BYTE8 * param) { vpi_printf("Hello Rill!\n"); return 0; } // Associate C Function with a New System Task void registerHelloSystfs(void) { s_vpi_systf_data task_data_s; vpiHandle systf_handle; task_data_s.type = vpiSysTask; task_data_s.sysfunctype = vpiSysTask; task_data_s.tfname = "$hello"; task_data_s.calltf = hello; task_data_s.compiletf = 0; task_data_s.sizetf = 0; task_data_s.user_data = 0; systf_handle = vpi_register_systf(&task_data_s); vpi_free_object(systf_handle); } // Register the new system task here void (*vlog_startup_routines[]) () = { registerHelloSystfs, 0 // last entry must be 0 };
b,编写verilog HDL文件
hello.v:module hello; initial $hello; endmodule
c,测试
为了测试方便,我编写了一个简单的shell脚本,如下所示:hello.sh:
#!/bin/bash # Rill creat 140321 gcc -c -I/home/openrisc/modelsim/modeltech/include hello.c ld -G -o hello.sl hello.o vlib work vlog hello.v vsim -c -pli hello.sl hello #run -all #quit
d,测试结果
下面是在linux下的测试结果:3,实际应用实例
通过上面的例子,我们看到了verilog和C语言的交互过程。其实,VPI的本质就是为了方便C语言和verilog之间交换数据。下面是一个实际工程中部分关键代码,请参考:
vpi_demo.c:
// VPI includes #include <vpi_user.h> uint32_t vpi_pipe[2]; // [0] - read, [1] - write void check_for_command(); void get_command_data(); void return_command_data(); //========================================= void init_pipe(void) { if(pipe(vpi_pipe) == -1) { perror("pipe error\n"); exit(1); } } //========================================= void check_for_command(char *userdata){ vpiHandle systfref, args_iter, argh; struct t_vpi_value argval; int value,i; int n; unsigned char data; //if(DBG_JP_VPI) printf("check_for_command\n"); //n = read(rsp_to_vpi_pipe[0], &data, 1); n = read(vpi_pipe[0], &data, 1); if ( ((n < 0) && (errno == EAGAIN)) || (n==0) ) { // Nothing in the fifo this time, let's return return; } else if (n < 0) { // some sort of error perror("check_for_command"); exit(1); } if (DBG_JP_VPI) { printf("jp_vpi: c = %x:",data); print_command_string(data); fflush(stdout); } // Return the command to the sim // Obtain a handle to the argument list systfref = vpi_handle(vpiSysTfCall, NULL); // Now call iterate with the vpiArgument parameter args_iter = vpi_iterate(vpiArgument, systfref); // get a handle on the variable passed to the function argh = vpi_scan(args_iter); // now store the command value back in the sim argval.format = vpiIntVal; // Now set the command value vpi_get_value(argh, &argval); argval.value.integer = (uint32_t) data; // And vpi_put_value() it back into the sim vpi_put_value(argh, &argval, NULL, vpiNoDelay); // Cleanup and return vpi_free_object(args_iter); n = write(vpi_to_rsp_pipe[1],&data,1); if (DBG_JP_VPI) printf("jp_vpi: r"); if (DBG_JP_VPI) printf("\n"); return; } void get_command_data(char *userdata){ vpiHandle systfref, args_iter, argh; struct t_vpi_value argval; int value,i; int n = 0; uint32_t data; char* recv_buf; recv_buf = (char *) &data; // cast data as our receive char buffer read_command_data_again: n = read(vpi_pipe[0],recv_buf,4); if ((n < 4) && errno==EAGAIN) goto read_command_data_again; else if (n < 4) { printf("jp_vpi: get_command_data errno: %d\n",errno); perror("jp_vpi: get_command_data read failed"); } if (DBG_JP_VPI) printf("jp_vpi: get_command_data = 0x%.8x\n",data); // Obtain a handle to the argument list systfref = vpi_handle(vpiSysTfCall, NULL); // Now call iterate with the vpiArgument parameter args_iter = vpi_iterate(vpiArgument, systfref); // get a handle on the variable passed to the function argh = vpi_scan(args_iter); // now store the command value back in the sim argval.format = vpiIntVal; // Now set the data value vpi_get_value(argh, &argval); argval.value.integer = (uint32_t) data; // And vpi_put_value() it back into the sim vpi_put_value(argh, &argval, NULL, vpiNoDelay); // Cleanup and return vpi_free_object(args_iter); return; } void return_command_data(char *userdata){ vpiHandle systfref, args_iter, argh; struct t_vpi_value argval; int value,i; int n, length; uint32_t data; char* send_buf; // Obtain a handle to the argument list systfref = vpi_handle(vpiSysTfCall, NULL); // Now call iterate with the vpiArgument parameter args_iter = vpi_iterate(vpiArgument, systfref); // get a handle on the length variable argh = vpi_scan(args_iter); argval.format = vpiIntVal; // get the value for the length object vpi_get_value(argh, &argval); // now set length length = argval.value.integer; // get a handle on the object passed to the function argh = vpi_scan(args_iter); // now store the command value back in the sim argval.format = vpiIntVal; // Now set the data value vpi_get_value(argh, &argval); data = (uint32_t) argval.value.integer; // Cleanup and return vpi_free_object(args_iter); if (DBG_JP_VPI) printf("jp_vpi: return_command_data %d bytes, 0x%.8x\n",length,data); send_buf = (char *) &data; //cast our long as a char buf // write the data back n = write(vpi_pipe[1],send_buf,length); return; } //========================================= void register_check_for_command() { s_vpi_systf_data data = {vpiSysTask, 0, "$check_for_command", (void *)check_for_command, 0, 0, 0}; vpi_register_systf(&data); return; } void register_get_command_data() { s_vpi_systf_data data = {vpiSysTask, 0, "$get_command_data", (void *)get_command_data, 0, 0, 0}; vpi_register_systf(&data); return; } void register_return_command_data() { s_vpi_systf_data data = {vpiSysTask, 0, "$return_command_data", (void *)return_command_data, 0, 0, 0}; vpi_register_systf(&data); return; } //========================================= void (*vlog_startup_routines[]) () = { register_check_for_command, register_get_command_data, register_return_command_data, 0 // last entry must be 0 };
vpi_demo.v:
integer cmd; reg [31:0] cmd_data; reg [31:0] exec_data; task exec_cmd; input [31:0] cmd_data; begin exec_data <= cmd_data + 1;//verilog process code end task main; begin while (1) begin cmd = -1; while (cmd == -1) begin #1000 $check_for_command(cmd); case (cmd) `TEST_CMD0: begin $get_command_data(cmd_data); exec_cmd(cmd_data); $return_command_data(4,exec_data); end end end end
相关文章推荐
- 深入浅出FPGA-15-xilinx_zynq7000_EPP上一个简单实验(PL)
- 深入浅出FPGA-14-ChipScope软件使用
- 深入浅出FPGA-11-梦回大唐
- 深入浅出FPGA-12-VMM(验证方法学)
- 深入浅出FPGA-16-xilinx_zynq7000_EPP上一个简单实验(PS)
- FPGA基础知识18(在Quartus II下产生无源代码网表设计文件方法 QXP VQM 加密文件)
- 关于《深入浅出教你玩转FPGA…
- 深入浅出FPGA-17-xilinx_zynq7000_EPP上一个简单实验(PS+PL)
- 深入浅出FPGA-14-ChipScope软件使用 (深入浅出FPGA系列)
- 【西西学FPGA】Lesson18 SPI 与 FLASH
- 深入浅出FPGA-14-ChipScope软件使用
- FPGA研发之道(18)-设计不是凑波形(八)总线(上)
- Android开发视频教程-深入浅出系列Lesson18-SPI110723_Mobile.Widget概述
- 深入浅出FPGA-3-verilog HDL
- 深入浅出FPGA-4-数字电路设计基础
- 深入浅出FPGA-2-让source insight 支持verilog HDL
- 深入浅出FPGA-4-数字电路设计基础
- Scala深入浅出实战经典:18,Scala中文件的读取、写入、控制台输入操作代码实战
- 深入浅出FPGA-1-Cyclone芯片内部
- 深入浅出FPGA-3-verilog HDL