引言

我们在进行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相关推荐

  1. 深入浅出JS—18 手把手实现一个Promise类

    Promise类的实现是高级面试中常考的题目,由于Promise包含的方法比较多,一般写到Promise1.0或者2.0版本已经能够满足面试要求了,不过全面深入理解Promise对于工作中Promis ...

  2. 深入浅出matplotlib(18):三个Y轴显示

    前面学习了两个Y轴的数据显示,在matplotlib里有直接的函数支持显示,因此显示两个Y轴的数据是很容易实现的,当然两个Y轴的情况也是最常用的情况,在很多数据显示里都会使用到,但是三个Y轴或者更多的 ...

  3. 使用VisualStudio读写NI FPGA板卡实例(基于FPGA Interface C API Generator)

    实验平台说明:安装了NI LabVIEW 2015 32bit版本,安装了NI FPGA Interface C API Generator,安装了硬件PCIe-7842R:安装了Visual Stu ...

  4. 深入浅出FPGA-11-梦回大唐

    引言 大唐,就是咱中国. 2012年伦敦奥运会结束了!刚看到一篇新闻,中国奥运代表团凯旋.从中国人第一次参加奥运会,到成为奥运夺金大国,过去了近30年! 在FPGA行业,中国什么时候才能突破美国的垄断 ...

  5. FPGA入门相关资料

    FPGA入门相关资料 01-语言与基础吗-verilog与数字电路 书籍推荐: 语法基础:Verilog 数字系统设计教程 [第2版] -- Digital System Design Tutoria ...

  6. 中国计算机学会CCF推荐国际学术会议和期刊目录-计算机体系结构/并行与分布计算/存储系统

    计算机体系结构/并行与分布计算/存储系统 中国计算机学会推荐国际学术刊物  (计算机体系结构/并行与分布计算/存储系统) 一.A类 序号 刊物简称 刊物全称 出版社 网址 1 TOCS ACM Tra ...

  7. 探索 Zynq MPSoC:配套 PYNQ 和机器学习应用一起使用 - 序言鸣谢目录20211231

    写在前面的话:看到朋友圈分享的这本书,一时技痒,给自己定个小目标,从今天开始翻译本书,作为小白学习FPGA之路的记录,仅供个人学习之用,并非用于任何商业目的.仅发布于知乎.个人CSDN博客和/或个人微 ...

  8. 视频教程-JavaScript+jQuery+项目实战系列视频教程-JavaScript

    JavaScript+jQuery+项目实战系列视频教程 国内IT培训讲师,国内知名出版社IT作家.经验丰富,草根悍将.待人诚恳,从不摆架子,做事认真负责. 周知胜 ¥117.00 立即订阅 扫码下载 ...

  9. 案例式c语言程序设计彭文艺答案,彭文艺

    <计算机应用基础/高等学校计算机科学与技术应用型教材>内容包括:计算机基础知识.WindowsXP劋作系统.Word2010处理文档.Excel2010表格处理.PowerPoint201 ...

  10. Conference and Journal Level in 2016

    中国计算机学会推荐国际学术会议和期刊目录 (2015 年) 中国计算机学会 中国计算机学会推荐国际学术期刊 (计算机体系结构/并行与分布计算/存储系统) 一.A 类 序号 刊物简称 刊物全称 出版社 ...

最新文章

  1. C语言字符串哪个头文件,如果在程序中要使用C语言的字符串处理函数,应在程序中包含这哪个头文件。...
  2. CentOS 6安装Oracle报错解决方案
  3. java 周易解梦接口_周公解梦
  4. 《微软文档管理解决方案2007》之一:安装部署 - [SharePoint Server]
  5. vue获取元素距离页面顶部的距离_VUE实时监听元素距离顶部高度的操作
  6. 【Redis】redis 持久化 RDB 和 AOF
  7. 路由的跳转 , 动态路由的配置
  8. kettle-多文件合并
  9. IOS开发者证书申请及应用上线发布详解(2014版)
  10. 中仪股份管道机器人_中仪股份 X5-HT 管道CCTV检测机器人
  11. 成长,进一寸有一寸的欢喜
  12. python安装PyQt5_stylesheets
  13. 【附加作业】沈航软件工程期末附加作业
  14. [信息论与编码]离散信道及信道容量(三)
  15. 与或非逻辑运算符用法详解
  16. Linux常用命令(三)
  17. 【经典算法】双指针(尺取法):爱,是双向奔赴,还是你追我赶?
  18. 校园疫情防控系统毕业设计,校园疫情防控管理系统设计与实现,校园疫情防控系统论文毕设作品参考
  19. Java考试案例-列出101至200之间的质数
  20. Intertek绿叶标志认证的标准及流程

热门文章

  1. 实现EasyExcel对Excel读操作(读操作)
  2. 解决telnet无法连接(Connection refused)
  3. ERP财务管理的功能模块及实施步骤
  4. 记录--uni-app实现蓝牙打印小票
  5. Android 状态栏样式设置
  6. 【MySql 数据库综合练习04】
  7. 【混淆工具】保护Net程序代码安全
  8. OpenStack — Nova
  9. 阿里java代码检测工具p3c
  10. python文字冒险游戏_[Python] 猜数大冒险1.0 用控制台玩的简易文字冒险游戏