zoukankan      html  css  js  c++  java
  • 数字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到版图》 于敦山 北大微电子学系

  • 相关阅读:
    activiti并行和串行区别
    SpringMVC 封装返回结果对象
    maven基础
    activiti表
    SpringBoot进阶
    SpringBoot基础
    javascript ES6模块化
    Vuejs搜索下拉框
    Vuejs2.0 + bootstrap demo
    maven settings.xml
  • 原文地址:https://www.cnblogs.com/sasasatori/p/15059581.html
Copyright © 2011-2022 走看看