verilog-FIR实现及modelsim-DPI C验证

介绍

本设计为一个FIR滤波器,滤波器系数由round(rcosdesign(0.25,20,4)*2048)生成如下图所示,共计81个系数,最大值为1094,最小值为-203,数据输入为($random%8)*2-7,即为[-7,-5,-3,-1,1,3,5,7]中的随机数,经过matlab测试输出测试后,设定输入数据为有符号4位数,输出为有符号16位数,实验环境为windows10+modelsim-se-64-10.4+mingw64。

RTL编写

       建立fir.sv文件,设计采用了10级流水的并行结构,注意需要在代码中加入import "DPI-C" context function int c_fir (input int data),以便生成相应的h文件。详细代码如下:

module fir(
    clk,
    rst,
    data_in,
    data_out
    );
    input wire clk;//????
    input wire rst;//????
    input wire signed[3:0] data_in;//8PAM??????{-7,-5,-3,-1,1,3,5,7}
    output reg signed[15:0] data_out;//FIR??
    import "DPI-C" context function int c_fir (input int data);
    parameter N=81;//81?????? ????? ????41?
    wire signed[11:0] h[0:(N-1)/2];//??????
    reg signed[15:0] data_reg[0:N-1];//????
    integer k;
    //1????????????
    always @(posedge clk) begin
        if(rst) begin
            for(k=0;k<N;k=k+1)
                data_reg[k]<=0;
        end
        else begin
            for(k=1;k<N;k=k+1)
                data_reg[k]<=data_reg[k-1];
            data_reg[0]<=data_in;
        end
    end
    //2??? 16?????*4?????
    reg signed[19:0] mul[0:N-1];
    always @(posedge clk) begin
        if(rst)begin
            for(k=0;k<N;k=k+1)
                mul[k]<=0;
        end
        else begin
            for(k=0;k<(N+1)/2;k=k+1)
                mul[k]<=data_reg[k]*h[k];
            for(k=(N+1)/2;k<N;k=k+1)
                mul[k]<=data_reg[k]*h[N-1-k];
        end
    end
    //3??? ??????? 81???? 41???
    reg signed[20:0] sum0[0:(N-1)/2];
    always @(posedge clk) begin
        if(rst) begin
            for(k=0;k<=(N-1)/2;k=k+1)
                sum0[k]<=0;
        end
        else begin
            for(k=0;k<(N-1)/2;k=k+1)
                sum0[k]<=mul[2*k]+mul[2*k+1];
            sum0[(N-1)/2]<=mul[N-1];
        end
    end
    //4??? ??sum0?? 41??? 21???
    reg signed[21:0] sum1[0:(N-1)/4];
    always @(posedge clk) begin
        if(rst) begin
            for(k=0;k<=(N-1)/4;k=k+1)
                sum1[k]<=0;
        end
        else begin
            for(k=0;k<(N-1)/4;k=k+1)
                sum1[k]<=sum0[2*k]+sum0[2*k+1];
            sum1[(N-1)/4]<=sum0[(N-1)/2];
        end
     end
    //5??? ??sum1?? 21??? 11???
     reg signed[22:0] sum2[0:(N-1)/8];
    always @(posedge clk) begin
        if(rst) begin
            for(k=0;k<=(N-1)/8;k=k+1)
                sum2[k]<=0;
        end
        else begin
            for(k=0;k<(N-1)/8;k=k+1)
                sum2[k]<=sum1[2*k]+sum1[2*k+1];
            sum2[(N-1)/8]<=sum1[(N-1)/4];
        end
    end
    //6??? ??sum2?? 11??? 6???
    reg signed[23:0] sum3[0:(N-1)/16];
    always @(posedge clk) begin
        if(rst) begin
            for(k=0;k<=(N-1)/16;k=k+1)
                sum3[k]<=0;
        end
        else begin
            for(k=0;k<(N-1)/16;k=k+1)
                sum3[k]<=sum2[2*k]+sum2[2*k+1];
            sum3[(N-1)/16]<=sum2[(N-1)/8];
        end
    end
    //7????6?????? ??3??
     reg signed[24:0] sum4[0:2];
    always @(posedge clk) begin
    if(rst) begin
        for(k=0;k<=2;k=k+1)
        sum4[k]<=0;
    end
    else begin
        for(k=0;k<=2;k=k+1)
            sum4[k]<=sum3[2*k]+sum3[2*k+1];
        end
    end
   //8????3?????? ??2??
    reg signed[25:0] sum5[0:1];
    always @(posedge clk) begin
    if(rst) begin
        for(k=0;k<=1;k=k+1)
        sum5[k]<=0;
    end
    else begin
        sum5[0]<=sum4[0]+sum4[1];
        sum5[1]<=sum4[2];
    end
    end
     //9????????
     reg signed[26:0] sum6;
     always @(posedge clk) begin
     if(rst) begin
         sum6<=0;
     end
     else begin
         sum6<=sum5[0]+sum5[1];
     end
     end
    //10?????
    always @(posedge clk) begin
        if(rst)data_out<=0;
        else begin 
        if(sum6>32767)data_out<=32676;
        else if(sum6<-32768)data_out<=-32768;
        else data_out<=sum6;
        end
    end
    //11?????
    assign h[0]=0;assign h[1]=-3;assign h[2]=-3;assign h[3]=-1;assign h[4]=3;assign h[5]=4;
    assign h[6]=1;assign h[7]=-3;assign h[8]=-5;assign h[9]=-3;assign h[10]=3;assign h[11]=7;
    assign h[12]=5;assign h[13]=-1;assign h[14]=-8;assign h[15]=-8;assign h[16]=-2;assign h[17]=7;
    assign h[18]=10;assign h[19]=3;assign h[20]=-8;assign h[21]=-12;assign h[22]=-3;assign h[23]=13;
    assign h[24]=22;assign h[25]=10;assign h[26]=-19;assign h[27]=-44;assign h[28]=-38;assign h[29]=6;
    assign h[30]=67;assign h[31]=96;assign h[32]=54;assign h[33]=-56;assign h[34]=-174;assign h[35]=-203;
    assign h[36]=-66;assign h[37]=244;assign h[38]=637;assign h[39]=966;assign h[40]=1094;        
endmodule

C编写

       使用C语言实现FIR滤波器,注意头文件使用,#include "svdpi.h"  #include <stdlib.h>  #include "fir.h",详细代码如下:

#include "svdpi.h"
#include <stdlib.h>
#include "fir.h"
int c_fir(int data) {
	int k;
	int h[81] = { 0,-3,-3,-1,3,4,1,-3,-5,-3,
		    3,7,5,-1,-8,-8,-2,7,10,3,-8,
		   -12,-3,13,22,10,-19,-44,-38,
		   6,67,96,54,-56,-174,-203,-66,	
		   244,637,966,1094	,966,637,
		244,-66,-203,-174,-56,54,96,67,	
		6,-38,-44,-19,10,22,13,-3,-12,-8,3,10,7,-2,-8,-8,-1,	
		5,7,3,-3,-5,-3,1,4,3,-1,-3 ,-3,0};
	static int reg[81];
	int tmp;
	for (k = 80; k >= 1; k--) {
		reg[k] = reg[k - 1];
	}
	reg[0] = data;
	for (k = 0; k < 81; k++) {
		tmp += reg[k] * h[k];
	}
	if (tmp > 32767)
		tmp = 32767;
	else if (tmp < -32768)
		tmp = -32768;
	return tmp;
}

int main()
{
	int source[4 * 100], shape[4 * 100];
	int i;
	for (i = 0; i < 4 * 100; i++) {
		source[i] = (i % 4 == 0) ? (rand() % 8 * 2 - 7) : 0;
		shape[i] = c_fir(source[i]);
	}
	return 0;
}

Testbench编写

       利用计数器方式实现4倍下采样的功能,同时对RTL模块和C函数进行测试,进行结构对比,代码如下:

module fir_test;
	reg clk;
	reg rst;
	import "DPI-C" function int c_fir(input int data);
	initial begin
	clk <= 0;
	rst <= 1;
	#20 rst<=0;
	end
	always #5 clk <= ~clk;
	reg[1:0] cnt;
	reg signed[3:0] src;
	always @(posedge clk) begin
        	if(rst) begin src<=0;cnt<=0;end
        	else begin
            		cnt<=cnt+1;
            		if(cnt==0)src<=($random%8)*2-7;
            		else src<= 0;
        	end
        end;
	wire signed[15:0] shape0;
	reg signed[15:0] shape1;
	fir fir0(clk,rst,src,shape0);
	always @(posedge clk) begin
		if(rst)shape1<=0;
		else shape1<=c_fir(src); 	end
endmodule

运行流程

  1. vlog -sv -dpiheader fir.h fir.sv,由fir.sv生成供c程序使用的.h头文件。
  2. gcc -c -I D:\modeltech64\include fir.c,对fir.c文件进行编译,生成.o对象文件。
  3. gcc -shared -Bsymbolic -o fir.dll fir.o,对fir.o文件编译,生成动态链库文件.dll。
  4. 通过GUI界面启动仿真,添加信号到wave窗口,开始运行仿真,设立输入输出为10进制,并以模拟波形显示,得到结果如下:

 从波形可以看出,RTL输出与C函数输出在幅值上一致,但是时间滞后了10个时钟,这是由于rtl流水线为10级流水,在开始阶段,需要10个时钟周期来使得流水线完全跑起来。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值