verilog调用其他module_调用DPI联动Systemverilog与C

距离上次更新专栏都两个月过去了,知乎的推荐算法还是比较良心,我这样断更法,每天被阅读数都还蛮不错的,提出表扬233

断更倒不是因为我懒,而是因为被老师召唤回了学校,还被多塞进了一个组。这段时间,投简历,期末考试,两个组的活,机考复习等等事务全扑上来,酸爽~~(我还作死报了个班学唱歌233) 不过也好,忙着总比闲着好,学习速度比在家快多了。

嘛,在总结今天的内容之前,先挖几个坑,等我定下工作,有下面这么些东西可以慢慢更:

1.紫光、Xilinx、Altera跑同样代码的效果比较 。

(这三家板子我现在是已经跑成了一些工程的。另外我甚至还想挤点时间,把DC的综合效果也一并加入比较,反正学校服务器不用白不用)

2.跨时钟域专题。

3.时序约束专题。

4.IEEE浮点规则、浮点定点转换verilog代码。

5.一些数电面试常考内容。比如异步FIFO、格雷码、三种RAM与不同读写模式的写法、三种复位方式、消抖、序列发生、序列检测这些。

都是蛮简单的东西,到时候在github仓库上整理好后,简单点一下,然后分享链接出来就好了。

6.CUDA编程,这是目前为另一个组的项目刚开始学的东西,坑先挖着,一口也吃不成胖子,慢慢学慢慢输出呗。

话说了解了CUDA之后我开始为FPGA的未来担心起来233 CUDA感觉上也太强大了。


终于到今天的内容了,DPI (Direct Programming Interface),systemverilog用于与C沟通的桥梁,久闻大名了,一直没有操弄过。今天看到”数字芯片实验室“的公众号更新了这个内容,虽然面试题还有一大堆都没看完,还是决定来把玩一番。很有意思!公众号的文章链接我放这了。基于QuestaSIM的SystemVerilog DPI使用流程(step by step)

我这个文章重点要讲的是玩完他的代码后,根据《systemverilog测试平台指南》这本书的讲解改了两段代码来跑的效果。

第一个是一段特简单的乘方代码,重点只是测一下sv能不能通过加automatic关键字的方法,自动给吃进去的c代码做迭代。

第二个是试了一下如果c代码里有指针和动态分配的内容,sv该如何处理。


乘方代码

(1)c代码

#include "stdio.h"
#include "dpi_types.h"

int factorial(int i)
{
    printf("factorial n");
    if (i == 1) 
        return 1;
    else
       return i*factorial(i - 1);
}

这里要注意我们添加的dpi_types.h,光在c里面这么写还是不够的,还需要在questasim的vlog指令里让questasim去读入这个dpi_types.h。

(2)bat中的questasim指令

vlib work
vlog test.sv -dpiheader dpi_types.h dpi_test.c
vopt +acc test -o opt_test
vsim -i opt_test -do " view source

(3)乘方的sv代码

module test ();

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


 test1 t1();
 

 endmodule

 program automatic test1();
    initial begin
        for(int i =1;i <=10;i=i+1)
            $display("%0d! = %0d",i ,factorial(i));
    end
endprogram
 

跑的效果:

87d3859f72acd34675680c4e93c87cbb.png

计数器代码

具体做的事情是:在C代码里动态分配一块内存,做个计数器。

(1)c代码:

#include "stdio.h"
#include "veriuser.h"
#include "svdpi.h"
#include "malloc.h"

typedef struct{
unsigned char cnt;
}cnt_mem;

void* counter8_allocate_mem(){
cnt_mem* c = (cnt_mem*) malloc(sizeof(cnt_mem));
c->cnt = 0;
printf("malloc a %d byte memory to instn",sizeof(cnt_mem));
return c;
}

void counter8(
        cnt_mem* inst_c,
        svBitVecVal* dout_c,
        svBitVecVal* din_c,
        svBit reset_c,
        svBit load_c
        )
{
    if(reset_c) 
        inst_c->cnt = 0;
    else if (load_c)
        inst_c->cnt = *din_c;
    else 
        inst_c->cnt++;

    *dout_c = inst_c->cnt;
    printf("count = %d, i = %d, reset  = %d, load = %dn",*dout_c,*din_c,reset_c,load_c);

}

这里注意:svBit、svBitVecVal* 这些类型,第一次用的人肯定是陌生的,不过这其实就是几个在c中的bit,指针概念在sv中的等效表达而已。网上一搜那种DPI变量类型的对照表格就明白了。

(2)bat文件,跟上一个工程完全一样。

(3)sv代码:

具体做的事情是:

1.通过import"DPI-C"这句话把c代码里的两个函数(一个用于分内存、一个用于做计数)吃进来。这里要注意,我刻意让第二句“DPI-C”的参数名后缀写成跟所有地方都不一样的_a,用来表示这个地方的命名不重要。

2.然后把第一个函数动态分配的内存,通过chandle传进第二个计数器函数进行计数。计数器函数的调用,其实就相当于我们正常情况下在testbench里面例化module,这里就要注意连线了。这里连出去到testbench层的线是可以在questasim里面画时序图的。

3.写好testbench连上计数器函数(或者叫她module)的连线的初始化,时钟,控制信号变化。跑起来后,testbench在每个时钟上升沿调用计数器的c代码,就相当于调用一个必然在一个周期内可以跑完的组合逻辑。

计数器函数每次被调用后,将结果通过连线返回给testbench。

module test ();

import "DPI-C" function chandle counter8_allocate_mem();
import "DPI-C" function void counter8(
    input chandle inst_a,
    output bit[7:0] dout_a,
    input bit[7:0] din_a,
    input bit reset_a,load_a
);

bit[7:0] dout_w,din_w;
    bit reset_w,load_w;
    chandle inst1;
    bit clk;

initial begin
    
    inst1 = counter8_allocate_mem();//动态分配内存

    reset_w = 0;
    load_w = 0;
    din_w = 8'd233;


    fork
        forever  #10 clk = ~clk;    
        forever @(posedge clk) begin
            counter8(inst1,dout_w,din_w,reset_w,load_w);//把内存传进计数器函数
        end
    join_none


    #10  
    load_w =1;
    #20
    load_w =0;
    #1000
    $finish;
end


endmodule

跑的效果:(我这里是给的初值就是233)

5d60cc8fc65e5eb89835aa4874a9a009.png

e5f25958fb633408df37d15dfcd4918e.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值