Verilog Matlab 联合仿真

一、概述

         在进行仿真时,有时候一部分参考模型(reference model)来自于Matlab,这就需要通过某种方法调用并运行Matlab的参考模型。verilog并不支持直接调用Matlab,但是可以通过DPI接口调用C函数,而Matlab又预留了为C开放的API接口,因此在SV中调用Matlab可以通过如下步骤来实现:

  1. Verilog通过DPI调用C,为C中某些变量赋值
  2. 从verilog中传递来的变量通过适当的类型转换传递到Matlab中
  3.  C通过API启动Matlab并调用Matlab中的函数/模型
  4. Matlab函数运算结果返回C,并通过适当的数据类型转换返回给verilog

二、verilog 与 C 通信

1、数据格式转换  

        C中并没有SV中的一些变量类型,例如bit,reg等,因此SV与C通信首先需要将SV中的数据类型转化为C可以识别的类型,部分典型变量类型的对应关系如下所示(这些类型都定义在svdpi.h头文件中):

SystemVerilogC(input)C(output)
bytecharchar*
intintint*
realdoubledouble*
reg[N:0]/logic[N:0]const svLogicVecVal*svLogicVecVal*
bit[N:0]const svBitVecVal*svBitVecVal*
open array[]svOpenArrayHandlesvOpenArrayHandles

2、C侧代码编写

         C侧除了要包含一些要用到的基础的头文件(例如stdio.h)以外,还需要包含上述提到的svdpi.h头文件:

    #include "svdpi.h"

        该头文件中定义了SV与C通信的类型转换,以及C对这些数据类型的操作方法。

        另外,C侧代码并不一定需要main函数,Verilog仅把C代码当成task或function调用。例如,在C侧编写函数如下:

int factorial(int i)
{if(i <= 1) return 1;else return(i * factorial(i - 1));
}

3、Verilog侧代码编写

        若想在Verilog中使用编写的C函数,则需要在进行导入(注意导入函数的可见范围):

import "DPI-C" function int factorial(input int i);

        之后便可以在可见范围内的module等地方使用该函数了,例如:

module test;
int result;
......
initial begin
result = factorial(5);
......
end
endmodule

 三、C 与 Matlab 通信

1、C侧代码编写

1)启动Matlab引擎

        C可以通过Matlab引擎指针来启动Matlab引擎,该引擎由Matlab软件包含的engine.h提供:

#include "engine.h"

        由于C启动Matlab需要用到Matlab引擎指针,之后便可以使用engOpen函数获取引擎指针,例如:

Engine *ep;
if(!(ep = engOpen("\0")))printf("\nCan't start Matlab engine!\n");

        engOpen函数原型如下: 

#include "engine.h"
Engine *engOpen(const char *startcmd);

        其参数为启动指令字符串,若在Windows环境下,则启动指令必须为空,在Linux环境下,启动指令为空时在当前主机启动,若启动指令为主机名,则在指定主机上启动,若为其它Matlab指令字符串,则Matlab会在启动时执行该指令。该函数返回Engine指针,若启动失败则返回NULL。

2)定义数据类型

        此外,Matlab中数据以矩阵的形式存储,因此还要包含定义矩阵类型以及操作方法的头文件matrix.h:

#include "matrix.h"

        Matlab中以矩阵形式存储数据,将C中的变量传递给Matlab(或反过来)时,需要定义Matlab能够识别的矩阵形式的变量,即mxArray类型,通常定义mxArray类型变量为指针变量,例如:

mxArray *mxarr_ptr = NULL;

        在定义完mxArray类型指针变量之后,可能还需要指定其大小和类型,需要用到mxCreateDoubleMatrix函数,该函数原型如下:

#include "matrix.h"
mxArray *mxCreateDoubleMatrix(mwSize m, mwSize n, mxComplexity ComplexFlag);

        其中,第一个参数和第二个参数代表创建m行n列的矩阵空间,第三个参数指定矩阵为实矩阵(mxREAL)还是复矩阵(mxCOMPLEX)。

3)C向Matlab传输数据

        结合前一节可以知道,若想向Matlab传递数据,首先应将C中普通类型的变量赋值到mxArray类型的变量中,此时需要用到mxSetPr函数,该函数原型如下:

#include "matrix.h"
void mxSetPr(mxArray *pm, double *pr);

        其中,第一个参数为mxArray类型的指针,第二个参数为double类型的指针。(在Matlab2018a版本以后,mxSetPr函数不再被建议使用,而应该使用mxSetDoubles函数)

        此外,当double类型指针未被分配空间时,则首先需要使用mxCalloc函数对其动态分配内存空间(注意不能使用calloc或malloc函数),其原型如下:

#include "matrix.h"
#include <stdlib.h>
void *mxCalloc(mwSize n, mwSize size);

        其中,第一个参数为分配内存的单元数量,第二个参数为每个单元的大小(通常搭配sizeof函数使用),如果成功,函数返回动态内存的起始位置,否则返回NULL。

        接下来就需要将mxArray类型的变量传递至Matlab中,此时需要用到engPutVariable函数,该函数原型如下:

#include "engine.h"
int engPutVariable(Engine *ep, const char *name, const mxArray *pm);

        其中,第一个参数为引擎指针,第二个参数为Matlab中变量的名字,第三个参数为mxArray类型变量的指针,当操作成功时返回1,否则返回0

  需要注意的是,如果指定的名字在Matlab中不存在,则会在Matlab中创建该名字的变量并为其赋值,如果该名字已存在,则会将原变量替换为新变量,此外,传递的变量最大为2GB。

4)C调用Matlab程序

        Matlab提供了从C传递指令的engEvalString函数,其原型如下所示:

#include "engine.h"
int engEvalString(Engine *ep, const char *string);

        其中,第一个参数为引擎指针,第二个参数为指令字符串,若引擎关闭或指针为空则返回1,否则返回0,即使Matlab并不能识别该指令。

        通过该函数,我们便可以像在Matlab console中执行指令一样调用Matlab函数(.m文件),但需要注意的是,在调用函数或模型前,首先需要将Matlab的工作路径设置正确,例如:

//--假设在/sv_matlab/demo/目录下存放有func_add.m文件,用于将两个数相加
engEvalString("path('/sv_matlab/demo/',path);");
//--在C中直接调用上述函数将两数相加,前提是Matlab中已经有a,b两个变量
engEvalString("func_add(a,b)");

5)C从Matlab获取数据

        我们需要先从Matlab获取变量至C中的mxArray类型变量中,之后再将mxArray类型变量中的数据提取到C的普通类型变量中。首先,我们需要使用engGetVariable函数获取mxArray变量,该函数原型如下:

#include "engine.h"
mxArray *engGetVariable(Engine *ep, const char *name);

        其中,第一个参数为引擎指针,第二个参数为Matlab中变量名字的字符串,当指定的名称字符串不存在时,函数返回NULL,否则返回指向该变量的mxArray指针。

        之后,我们需要使用mxGetPr函数从mxArray类型变量中获取值,该函数原型如下:

#include "matrix.h"
mxDouble *mxGetPr(const mxArray *pm);

        其参数为mxArray类型变量的指针,如果指定的mxArray类型变量的指针为NULL,则返回函数NULL,否则返回指向mxArray中存储数据的指针。

6)释放内存

        在C和Matlab处理完相应的数据之后,可能需要为一些变量之前分配的空间释放其内存以防止内存泄漏。

        使用mxFree函数释放由mxCalloc分配的内存,其函数原型如下:

#include "matrix.h"
void mxFree(void *ptr);

        使用mxDestroyArray函数释放由mxCreateDoubleMatrix分配的内存,其函数原型如下:

#include "matrix.h"
void mxDestroyArray(mxArray *pm);

7)关闭Matlab引擎

         在处理完所有数据并释放完成内存后,可以使用前面提到的engEvalString函数来关闭Matlab引擎,例如:

engEvalString(ep,"close");

2、Matlab侧代码编写

        对于Verilog调用Simulink Model进行联合仿真的情况,其中一个方法就是,可以将Matlab中所有的变量,无论是输入还是输出,均打包成一个函数包,这样我们就可以通过engEvalString函数来调用整个模型。

四、Verilog & Matlab交互示例

        我们以从verilog中向Matlab中传递两个变量并将两个变量在Matlab中相加后返回给Verilog为例,再梳理一边该流程。首先是Verilog侧代码(这里用的是SV):

`timescale 1ns/1ps
import "DPI-C" function real func_add(const real a, const real b);
module test;real val1;real val2;real result;initial beginval1 = 0.3;val2 = 1.1;result = func_add(val1, val2);  //调用C函数$display("SV got result = %0f", result);#10;$finish();end
endmodule

        然后是C侧代码:

#include <stdlib.h>
#include <stdio.h>
#include "svdpi.h"
#include "engine.h"
#include "matrix.h"
double func_add(double a, double b)
{double *val1;double *val2;double *result;val1 = (double *)mxCalloc(1, sizeof(double));val2 = (double *)mxCalloc(1, sizeof(double));*val1 = a;*val2 = b;mxArray = *mxarr_val1 = mxCreateDoubleMatrix(1, 1, mxREAL);mxArray = *mxarr_val2 = mxCreateDoubleMatrix(1, 1, mxREAL);mxArray = *mxarr_result = NULL;Engine *ep;if(!(ep = engOpen("\0")))printf("\nCan't start Matlab engine!\n");else{engEvalString("path('/sv_matlab/demo/',path);");mxSetPr(mxarr_val1, val1);mxSetPr(mxarr_val2, val2);engPutVariable(ep, "a", mxarr_val1);engPutVariable(ep, "b", mxarr_val2);engEvalString(ep, "result = func_demo(a,b)");mxarr_result = engGetVariable(ep, "result");result = mxGetPr(mxarr_result);return *result;}
}

        最后是Matlab侧代码:

function result = func_demo(a, b)result = a + b;
return

因为涉及到调用C函数,因此在跑仿真之前需要先对C文件进行编译,例在/sv_matlab/demo/c目录下有自己编写的C函数,则需要按如下方式对其编译:

gcc demo/c/func_add.c -o demo/c/libdpi.so \-I /appl/tools/cadence/XCELIUM2009/tools.lnx86/inca/include/ \-std=c99 -fPIC -shared -leng -lmx -lmex

其中参数:

-o 指定生成的结果文件,结果文件名为libdpi.so,SV将默认查找这个库内的C函数

-I 指定编译包含的头文件库(这里要用到包含svdpi.h的路径),由仿真工具提供,这里以XCELIUM为例

-fPIC 告诉编译器产生与位置无关代码

-shared 表示生成库能被别的程序链接

-leng -lmx 和 -lmex 编译matlab库所需的参数,主要用于编译和链接

在编译完成之后,便可以启动SV的仿真了,如果C函数没有发生变化,则重复SV侧仿真无需再次编译C函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/253393.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

转 alsa录音放音执行流程详解

前言&#xff1a; linux中&#xff0c;无论是oss还是alsa体系&#xff0c;录音和放音的数据流必须分析清楚。先分析alsa驱动层&#xff0c;然后关联到alsa库层和应用层。 链接分析&#xff1a; core/pcm_native.c文件中.mmap snd_pcm_mmap调用snd_pcm_mmap_data(substream, fi…

jenkins之qq企业邮箱配置

一、配置qq企业邮箱 1、登录jenkins后台管理&#xff0c;选择 系统管理 ☞ 系统设置 2、SMTP server配置 3、邮件通知配置 配置ssl等参数 点击 高级 4、发送邮件测试 总结&#xff1a;邮箱配置不成程分析 1、管理员账号和默认发送账号不一致。2、smtp服务器设置不正确;qq企业…

关于iOS里的做动画方法的差别与注意事项

CoreAnimation与UIView.animation... 这两个方式的主要差别在于&#xff0c;前者如果不主动设置&#xff0c;那么在动画做完以后&#xff0c;会恢复原状。后者则不会&#xff0c;动画做完后是什么样&#xff0c;控件就是什么样。 UIView.animation...是什么 首先我们来做一个动…

mysql-5.7 持久化统计信息详解

一、持久化统计信息的意义&#xff1a; 统计信息用于指导mysql生成执行计划&#xff0c;执行计划的准确与否直接影响到SQL的执行效率&#xff1b;如果mysql一重启 之前的统计信息就没有了&#xff0c;那么当SQL语句来临时&#xff0c;那么mysql就要收集统计信息然后再生成SQL语…

关于传感器”英寸“计量

传感器上的n是指对角线长度为16mm或18mm的n倍 以英寸代指的传感器大小称为靶面尺寸。 在CCD/CMOS出现之前&#xff0c;摄像机是利用一种叫作“光导摄像管&#xff08;Vidicon Tube&#xff09;”的成像器件感光成像的&#xff0c;这是一种特殊设计的电子管&#xff0c;其直径的…

关于USB-AUDIO使用ALSA编程的一点问题

转载自&#xff1a;http://blog.chinaunix.net/uid-25272011-id-3153434.html 最近在调试一款原相PAP7501摄像头中的USB的麦克风&#xff0c;USB层走的应该是标准的UAC协议&#xff0c;具体可以见USB的官网&#xff1a;http://www.usb.org/developers/devclass_docs#approved&a…

让input变成不可编辑状态的方法

有时候&#xff0c;我们希望表单中的文本框是只读的&#xff0c;让用户不能修改其中的信息&#xff0c;如使<input type"text" name"input1" value"中国"> 的内容&#xff0c;"中国"两个字不可以修改。实现的方式归纳一下&#…

npm run dev 在本地调试出现跨域问题解决方法

npm run dev 在本地调试出现跨域问题 在localhost:8080调试时会出现跨域问题&#xff0c;如图&#xff1a; 我的项目是用webpack作为前端自动化构建工具&#xff0c;可以在webpack-dev-server中配置跨域。webpack-dev-server是一个小型的nodejs服务器&#xff0c;是基于express…

alsa声音编程介绍

http://blog.csdn.net/q553716434/article/details/7881552 period(周期):硬件中中断间的间隔时间。它表示输入延时。 声卡接口中有一个指针来指示声卡硬件缓存区中当前的读写位置。只要接口在运行&#xff0c;这个指针将循环地指向缓存区中的某个位置。 frame size sizeof(o…

五、python模块以及包

模块&#xff1a;编写的别的程序中重用一些代码。 1 模块的写法&#xff1a; 创建一个.py文件&#xff0c;该文件中包含函数与变量。使用撰写python解释器本身的本地语言来编写模块。比如使用C代码编写python模块&#xff0c;并且在编译后&#xff0c;可以通过标准的python解释…

jeecg选择按钮带入其他单据值

前端的标签 <input class"inputxt" id"fshimian" name"fshimian" ignore"ignore" datatype"*" value"${shizhePage.fshimian}" /> <t:choose hiddenName"fshimian" hiddenid"fname"…

alsa编程

alsa 编程 分类&#xff1a; linux 2012-08-18 20:13 124人阅读 评论(0) 收藏 举报 编程parametersbufferloopsaccessplayback转载自&#xff1a;http://blog.csdn.net/spygg/article/details/7824750 ALSA(Advanced Linux Sound Architecture)是由内核驱动,标准的API库和一系…

Fiddler4入门——手机抓包

一、下载工具包 百度搜索”fiddler 下载“ &#xff0c;安装最新版本 下载的软件安装包为“fiddler_4.6.20171.26113_setup.exe”格式&#xff0c;双击安装。安装成功&#xff0c;在“开始”-“所有程序”&#xff0c;就会看见这样的图标&#xff0c;若是常用的话&#xff0c;也…

Node.js Performance

https://blog.risingstack.com/node-js-performance-monitoring-with-prometheus/转载于:https://www.cnblogs.com/skating/p/7544838.html

(五)DOM4j进行XML文件的解析及生成

DOM4j本身还是需要使用SAX建立解析器&#xff0c;然后通过文档依次找到根节点&#xff0c;再通过根节点查找每一个节点的内容. 1.写操作 import java.io.File;import java.io.FileOutputStream;import java.util.Iterator; import org.dom4j.Document;import org.dom4j.Documen…

Linux系统基础.作业

要求以root用户登录系统&#xff0c;右击桌面打开终端&#xff0c;查看当前登陆Linux系统所使用的用户名 查看哪些用户在系统上工作 修改当前时间为2018年8月26号11:28 查看2015年10月份日历 使用两种方法查看ls命令的使用说明 清除屏幕 ctrlL使用“useradd tom”命令新建tom用…

Alsa中PCM参数设置

分类&#xff1a; LINUX 1) PCM设备的句柄.2) 指定同时可供回放或截获的PCM流的方向3) 提供一些关于我们想要使用的设置选项的信息,比如缓冲区大小,采样率,PCM数据格式等4) 检查硬件是否支持设置选项.4.1) 初始化PCM变量4.2) 分配hwparams结构4.3) 打开PCM设备4.4) 以声卡的全部…

java5

java基础&#xff08;五&#xff09;命名规则&#xff1a; 名字中只能包含->字母、_、数字、$&#xff0c;且开头不能为数字包名必须都小写文件名首字母和后面英文文件单词首字母都要大写变量和方法名 首字母小写&#xff0c;后面英文单词首字母大写java中的方法&#xff1a…

最新历史版本 :H.265

原来对264有深入的研究&#xff0c;现在想详细了解下265啦&#xff0c;愿265尽快广泛的使用起来&#xff0c;人们可以享受无处不在的视觉盛宴。 H.265是ITU-T VCEG 继H.264之后所制定的新的视频编码标准。H.265标准围绕着现有的视频编码标准H.264&#xff0c;保留原来的某些技术…

凯撒密码、GDP格式化输出、99乘法表

1.恺撒密码的编码 sinput(请输入明文:) print(密文为:) for i in s:print(chr(ord(i)3),end)运行结果为&#xff1a; 2.国家名称 GDP总量&#xff08;人民币亿元&#xff09; 中国 &#xffe5;765873.4375 澳大利亚 &#xffe5; 78312.4375 &#xff08;国家名称左对齐&am…