深入浅出FPGA-18-VPI
引言
我们在进行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 140321gcc -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] - writevoid 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 returnreturn;}else if (n < 0){// some sort of errorperror("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 listsystfref = vpi_handle(vpiSysTfCall, NULL);// Now call iterate with the vpiArgument parameterargs_iter = vpi_iterate(vpiArgument, systfref); // get a handle on the variable passed to the functionargh = vpi_scan(args_iter);// now store the command value back in the simargval.format = vpiIntVal;// Now set the command valuevpi_get_value(argh, &argval);argval.value.integer = (uint32_t) data;// And vpi_put_value() it back into the simvpi_put_value(argh, &argval, NULL, vpiNoDelay);// Cleanup and returnvpi_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 bufferread_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 listsystfref = vpi_handle(vpiSysTfCall, NULL);// Now call iterate with the vpiArgument parameterargs_iter = vpi_iterate(vpiArgument, systfref); // get a handle on the variable passed to the functionargh = vpi_scan(args_iter);// now store the command value back in the simargval.format = vpiIntVal;// Now set the data valuevpi_get_value(argh, &argval);argval.value.integer = (uint32_t) data;// And vpi_put_value() it back into the simvpi_put_value(argh, &argval, NULL, vpiNoDelay);// Cleanup and returnvpi_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 listsystfref = vpi_handle(vpiSysTfCall, NULL);// Now call iterate with the vpiArgument parameterargs_iter = vpi_iterate(vpiArgument, systfref); // get a handle on the length variableargh = vpi_scan(args_iter);argval.format = vpiIntVal;// get the value for the length objectvpi_get_value(argh, &argval);// now set lengthlength = argval.value.integer;// get a handle on the object passed to the functionargh = vpi_scan(args_iter);// now store the command value back in the simargval.format = vpiIntVal;// Now set the data valuevpi_get_value(argh, &argval);data = (uint32_t) argval.value.integer;// Cleanup and returnvpi_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 backn = 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;
beginexec_data <= cmd_data + 1;//verilog process code
endtask main;beginwhile (1)begincmd = -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);endendendend
深入浅出FPGA-18-VPI相关推荐
- 深入浅出JS—18 手把手实现一个Promise类
Promise类的实现是高级面试中常考的题目,由于Promise包含的方法比较多,一般写到Promise1.0或者2.0版本已经能够满足面试要求了,不过全面深入理解Promise对于工作中Promis ...
- 深入浅出matplotlib(18):三个Y轴显示
前面学习了两个Y轴的数据显示,在matplotlib里有直接的函数支持显示,因此显示两个Y轴的数据是很容易实现的,当然两个Y轴的情况也是最常用的情况,在很多数据显示里都会使用到,但是三个Y轴或者更多的 ...
- 使用VisualStudio读写NI FPGA板卡实例(基于FPGA Interface C API Generator)
实验平台说明:安装了NI LabVIEW 2015 32bit版本,安装了NI FPGA Interface C API Generator,安装了硬件PCIe-7842R:安装了Visual Stu ...
- 深入浅出FPGA-11-梦回大唐
引言 大唐,就是咱中国. 2012年伦敦奥运会结束了!刚看到一篇新闻,中国奥运代表团凯旋.从中国人第一次参加奥运会,到成为奥运夺金大国,过去了近30年! 在FPGA行业,中国什么时候才能突破美国的垄断 ...
- FPGA入门相关资料
FPGA入门相关资料 01-语言与基础吗-verilog与数字电路 书籍推荐: 语法基础:Verilog 数字系统设计教程 [第2版] -- Digital System Design Tutoria ...
- 中国计算机学会CCF推荐国际学术会议和期刊目录-计算机体系结构/并行与分布计算/存储系统
计算机体系结构/并行与分布计算/存储系统 中国计算机学会推荐国际学术刊物 (计算机体系结构/并行与分布计算/存储系统) 一.A类 序号 刊物简称 刊物全称 出版社 网址 1 TOCS ACM Tra ...
- 探索 Zynq MPSoC:配套 PYNQ 和机器学习应用一起使用 - 序言鸣谢目录20211231
写在前面的话:看到朋友圈分享的这本书,一时技痒,给自己定个小目标,从今天开始翻译本书,作为小白学习FPGA之路的记录,仅供个人学习之用,并非用于任何商业目的.仅发布于知乎.个人CSDN博客和/或个人微 ...
- 视频教程-JavaScript+jQuery+项目实战系列视频教程-JavaScript
JavaScript+jQuery+项目实战系列视频教程 国内IT培训讲师,国内知名出版社IT作家.经验丰富,草根悍将.待人诚恳,从不摆架子,做事认真负责. 周知胜 ¥117.00 立即订阅 扫码下载 ...
- 案例式c语言程序设计彭文艺答案,彭文艺
<计算机应用基础/高等学校计算机科学与技术应用型教材>内容包括:计算机基础知识.WindowsXP劋作系统.Word2010处理文档.Excel2010表格处理.PowerPoint201 ...
- Conference and Journal Level in 2016
中国计算机学会推荐国际学术会议和期刊目录 (2015 年) 中国计算机学会 中国计算机学会推荐国际学术期刊 (计算机体系结构/并行与分布计算/存储系统) 一.A 类 序号 刊物简称 刊物全称 出版社 ...
最新文章
- C语言字符串哪个头文件,如果在程序中要使用C语言的字符串处理函数,应在程序中包含这哪个头文件。...
- CentOS 6安装Oracle报错解决方案
- java 周易解梦接口_周公解梦
- 《微软文档管理解决方案2007》之一:安装部署 - [SharePoint Server]
- vue获取元素距离页面顶部的距离_VUE实时监听元素距离顶部高度的操作
- 【Redis】redis 持久化 RDB 和 AOF
- 路由的跳转 , 动态路由的配置
- kettle-多文件合并
- IOS开发者证书申请及应用上线发布详解(2014版)
- 中仪股份管道机器人_中仪股份 X5-HT 管道CCTV检测机器人
- 成长,进一寸有一寸的欢喜
- python安装PyQt5_stylesheets
- 【附加作业】沈航软件工程期末附加作业
- [信息论与编码]离散信道及信道容量(三)
- 与或非逻辑运算符用法详解
- Linux常用命令(三)
- 【经典算法】双指针(尺取法):爱,是双向奔赴,还是你追我赶?
- 校园疫情防控系统毕业设计,校园疫情防控管理系统设计与实现,校园疫情防控系统论文毕设作品参考
- Java考试案例-列出101至200之间的质数
- Intertek绿叶标志认证的标准及流程