C/C++教程

数字asic流程实验(三) Verilog编写&前仿真

本文主要是介绍数字asic流程实验(三) Verilog编写&前仿真,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

数字asic流程实验(三) Verilog编写&前仿真

1.Verilog编写

本次实验要实现的是一个三级抽取CIC滤波器,抽取系数为64。回顾上一章节中的CIC滤波器结构,可以发现其硬件实现是非常简单的,积分器的部分通过加法器与D触发器即可实现,降采样通过分频器实现,梳状器的部分则通过减法器和触发器实现。

img

编写分频器的verilog实现,其输入信号为时钟信号clk与复位信号rst_n,输出信号为64倍分频后的时钟信号clk_div。

分频器使用计数器实现。当复位信号为低时,计数器值复位为0,clk_div输出为0;当复位信号为高时,计数器在时钟clk的每个上升沿计数,当第32个上升时钟沿到来时clk_div进行翻转,由于计数器位数为5位,第32个上升时钟沿到来的同时计数器也清零了,直到下一次的第32个上升时钟沿再重复上述过程,故clk_div两次翻转的时间(一个周期)为64个clk周期,从而实现了64倍分频。

分频器的verilog代码实现如下:

module divider(
    input clk,
    input rst_n,
    output reg clk_div
);

reg [4:0]count;

always @(posedge clk or negedge rst_n) begin
    if (rst_n == 0) begin
        count <= 5'd0;
        clk_div <= 1'b0;
    end
    else if (count < 31) begin
        count <= count + 1;
        clk_div <= clk_div;
    end
    else begin
        count <= count + 1;
        clk_div <= ~clk_div;
    end
end

endmodule

编写CIC滤波器的verilog实现,其输入信号为时钟clk,复位信号rst_n以及调制器输入信号in,输出信号为量化值out。

由于积分运算会导致数据位宽变宽,需要通过公式计算

\[B_{out}=B_{in}+Nlog_2(RM) \]

公式中,\(B_{out}\)为输出数据的位数,\(B_{in}\)为输入数据的位数,\(N\)为滤波器级数,\(R\)为滤波器阶数,\(M\)​​为降采样系数。代入数据后可以计算得到所需要的位数为19位,因此设计寄存器位宽为19。

需要注意的是梳状器作为降采样部分的后级,所有的时钟信号都需要使用分频器64倍分频后的时钟clk_div。

CIC滤波器的verilog实现代码如下:

module cic_filter(
    input clk,
    input rst_n,
    input in,
    output [18:0] out
);
    reg [18:0]out_reg;
    wire clk_div;
    reg [18:0]sum1,sum2,sum3;
    wire [18:0]sum1_nxt,sum2_nxt,sum3_nxt;

    // 积分器加法器部分
    assign sum1_nxt = sum1 + in;
    assign sum2_nxt = sum2 + sum1;
    assign sum3_nxt = sum3 + sum2;

    // 积分器D触发器部分
    always @(posedge clk or negedge rst_n) begin
        if (rst_n == 0) begin
            sum1 <= 19'b0;
            sum2 <= 19'b0;
            sum3 <= 19'b0;
        end
        else begin
            sum1 <= sum1_nxt;
            sum2 <= sum2_nxt;
            sum3 <= sum3_nxt;
        end
    end

    // 调用分频器
    divider div(
        .clk(clk),
        .rst_n(rst_n),
        .clk_div(clk_div)
    );

    reg [18:0]sub1,sub2,sub3;
    wire [18:0]sub1_nxt,sub2_nxt,sub3_nxt;

    // 梳状器减法器部分
    assign sub1_nxt = sum3_nxt - sub1;
    assign sub2_nxt = sub1_nxt - sub2;
    assign sub3_nxt = sub2_nxt - sub3;

    // 梳状器D触发器部分
    always @(posedge clk_div or negedge rst_n) begin
        if (rst_n == 0) begin
            sub1 <= 19'b0;
            sub2 <= 19'b0;
            sub3 <= 19'b0;
        end
        else begin
            sub1 <= sum3_nxt;
            sub2 <= sub1_nxt;
            sub3 <= sub2_nxt;
        end
    end

    // 输出
    always @(posedge clk_div or negedge rst_n) begin
        if (rst_n == 0) begin
            out_reg <= 0;
        end
        else begin
            out_reg <= sub3_nxt;
        end
    end

    assign out = out_reg;

endmodule

编写testbench用于仿真,文件1k1000mv.txt中存储了一段∑-Δ调制器对一个周期的正弦波采样后输出的码流,通过系统任务$readmemb将其读入声明好的存储器mem中,并将数据按次序以1位码流的形式进行输出到CIC滤波器的输入端口in,此外在testbench中设置时钟信号clk周期为156.25ns,复位信号rst_n在仿真开始500ns后由低电平变为高电平。

testbench的verilog实现代码如下:

`timescale 1ns/1ns
`define period 78.125

module testbench;
    // input
    reg clk,rst_n,in;
    // output
    wire [18:0]out;

    // 设置时钟周期为156.25ns
    always #`period clk <= ~clk;

    // 初始化
    initial begin
        rst_n <= 1'b0;
        clk <= 1'b0;
        #500;
        rst_n <= 1'b1;
    end

    integer i;
    
    // 定义存储器mem
    reg mem[0:3000000];
    
    // 将1k1000mv.txt文件读入mem
    initial $readmemb("1k1000mv.txt",mem);

    // 将mem中数据次序输出到in
    always @(posedge clk or negedge rst_n) begin
        if(rst_n == 0) begin
            i = 0;
            in <= 0;
        end
        else begin
            in <= mem[i];
            i = i + 1;
        end
    end

    // 调用cic滤波器
    cic_filter cic(
        .clk(clk),
        .rst_n(rst_n),
        .in(in),
        .out(out)
    );

endmodule

2.使用Modelsim进行前仿真

1.打开Modelsim,File---->New---->Project.. 建立新工程,命名为CICFilter,并设置工程路径

image-20210725233419104

image-20210725233501108

2.将编写好的verilog文件、1k1000mv.txt全部放到工程路径下

image-20210725233920361

3.在Modelsim的Project标签页中右键,点击Add to Project ---> Existing File... 选择工程路径下的verilog文件,Add file as type选为Verilog。将三个verilog文件全部添加进工程。

image-20210725234008270

image-20210725234106291

4.在Modelsim的Project标签页中右键,点击Compile ---> Compile All,编译全部verilog文件

image-20210725234402384

5.若编译成功,下方Transcript窗口会输出编译成功的信息。若提示失败则根据报错信息修改verilog并再次编译。

image-20210725234430925

6.点击Simulate--->Start Simulation... 在弹出的窗口中,点击work左侧的小加号展开,在展开的栏目中点击选中testbench,进入仿真环境。

image-20210725235317595

image-20210725235658477

image-20210725235807772

7.在仿真环境中①为Instance窗口,所有例化的模块都会显示在其中;②为Objects窗口,选中①中的模块后,该窗口会对应显示模块中的信号,寄存器,存储器等;③为Wave窗口,用于显示仿真波形。在Instance窗口中点击testbench,在Objects窗口中选中out并右键,Add to ---> Wave ---> Selected Signals,将out信号加入Wave窗口

image-20210726001011513

image-20210726001311351

image-20210726001515795

8.以同样的方式将in信号也添加进Wave窗口

image-20210726001613423

9.修改右上角仿真时间,设置为1ms,再点击其右侧的run图标

image-20210726001704257

10.此时Wave窗口应出现绿色波形,点击左侧小放大镜自动缩放波形时间轴

image-20210726001842261

11.在Wave窗口中右键out信号,Format ---> Analog(automatic)

image-20210726001951100

12.可以看到一个周期正弦波信号

image-20210726002135940

13.多次点击run图标运行仿真,可以看到多个周期的正弦波

image-20210726002235341

14.使用左侧放大镜功能调整波形横轴分度,可以看到在out值大的部分(波峰),in信号是以1为主的码流,在out值小的部分(波谷),in信号是以0为主的码流,和上一章节的调制器输出与CIC滤波器输出的关系是一致的。

image-20210726002725726

image-20210726002648841

至此完成了CIC滤波器的Verilog编写及前仿真的实验流程。

3.参考资料

https://blog.csdn.net/FPGADesigner/article/details/80885415

《数字集成电路设计入门--从HDL到版图》 于敦山 北大微电子学系

这篇关于数字asic流程实验(三) Verilog编写&前仿真的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!