首页 > 其他 > 详细

FPGA学习笔记(六)—— 时序逻辑电路设计

时间:2018-05-23 15:58:18      阅读:557      评论:0      收藏:0      [点我收藏+]
用always@(posedge clk)描述
       时序逻辑电路的基础——计数器在每个时钟的上升沿递增1)
技术分享图片

   例1.四位计数器(同步使能、异步复位)

 

// Module Name: counter_4bit
// Description: 4bit异步复位同步使能二进制计数器

module counter_4bit(
    input    clk,            //系统时钟信号
    input    rst,            //系统复位按键
    input    en,             //计数器使能端
    output   reg [3:0]q      //计数器计数值输出
    );
  //同步使能,异步复位
    always@(posedge clk,posedge rst)
    if(rst)
        q <= 0;
    else if(en)
        q <= q + 1b1;       //计数器加一
endmodule

   testbench测试代码如下:

 

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Module Name: counter_4bit_tb 
// Description: 4bit计数器模块测试文件
//////////////////////////////////////////////////////////////////////////////////
`define clk_period 20   //宏定义时钟周期  
module counter_4bit_tb();
    
    reg     clk;    //用于产生时钟信号
    reg     rst;    //用于产生复位信号
    reg     en;     //用于产生使能信号
    wire    [3:0]q; //计数器计数值输出

    //例化测试模块
  counter_4bit counter_4bit_test(
       .clk(clk),          //系统时钟信号
       .rst(rst),            //系统复位按键
       .en(en),            //计数器使能端
       .q(q)               //计数器计数值输出
        );
     
     //开始测试
     //生成时钟信号
     initial clk = 1;
     always #(`clk_period/2)  clk = ~clk;         //clk每5ns翻转一次,产生100M时钟信号
     
     initial begin
            rst = 1;    en = 0;
        #(`clk_period * 5 + 1 );   
            rst = 0;
        #(`clk_period * 5);
            en = 1;
        #(`clk_period *20);     //因为4bit计数16个clk就清零,所以延时20个时钟周期
            $stop;
      end
endmodule

 

 

 

  测试结果如下:

技术分享图片

   综合的电路图如下:

技术分享图片

  计数器是我们设计的第一个时序逻辑电路,也是最基本、最重要的时序逻辑电路,由图中可以看到一个计数器由加法器和D触发器组成;

  特别要注意的一点,在用verilog描述计数寄存器加一的时候,我们没有先写一个加法器,然后例化调用,而是直接采用 q <= q + 1‘b1这样描述加法器,这点在综合出的电路图也可以看出,加法器不再是门电路的组合,而是用一个圆圈替代,这时,数字逻辑设计的思想就又抽象了一层,不再是门电路的组合,而是这些具有逻辑功能的小方块的组合,所以,抽象的思想在数字逻辑设计中至关重要;

   在编写testbench仿真测试的时候,我们也不再像测试组合逻辑电路那样利用穷举法测试功能,而是利用时钟测试,比如测试4bit的加法器,一要测试它能不能在每个时钟沿加一,而要测试它计满时可不可以自动清零;所以,在测试时序逻辑电路的时候要准确把握clk时钟信号

   注:计数器只是基本电路,比如分频器、定时器、巴克码序列发生器在计数器基本电路上设计即可;
 
例2.基本分频操作——分频器(闪烁灯:LED以1hz的频率闪烁)
    分频器是计数器的一大应用,在FPGA中没有像C语言中delay()这样的延时,那如何延时呢?可以通过分频器,将系统100M的高速时钟信号经过分频器,变为1hz的输出信号,这样,LED就会按1s的周期闪烁;
  1hz的时钟信号是每500ms翻转1次,而在100M的时钟下,1个clk是10ns,所以应该每计数 500_000_000/10 = 50_000_000 次输出信号翻转,就产生了1hz的信号;50_000_000大概估算需要一个26位的寄存器;又因为计数器是从0开始计数的,所以最大计数值应该为49_999_999,设计如下:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Create Date: 2018/05/22 20:32:26
// Module Name: flashled 
// Description: 产生一个时钟信号,让LED灯按1hz的频率闪烁
//////////////////////////////////////////////////////////////////////////////////
 //`define SIMULATION      /*** 仿真时保留,板级验证时注释 ***/
module flashled(
    input clk,          //时钟信号输入
    input rst,          //复位信号输入
    input en,           //使能信号输入
    output [15:0]led    //led信号输出
    );
    
     
     `ifdef SIMULATION      //仿真情况下
        parameter   CNT_MAX = 26d49;
     `else                  //板级验证情况下
        parameter   CNT_MAX = 26d49_999_999;
     `endif   
       
    reg [25:0]cnt;      //最大计数值49_999_999
    reg [15:0]led_clk;  //输出驱动led的1hz信号
   
    //计数器功能描述
    always@(posedge clk,posedge rst)
        if(rst)
            cnt <= 0;
        else if(en)begin
            if(cnt == CNT_MAX)
                cnt <= 0;
            else
                cnt <= cnt + 1b1;
        end
    
    //产生1hz信号
    always@(posedge clk,posedge rst)
        if(rst)
            led_clk <= 0;
        else if(cnt == CNT_MAX)
            led_clk <= ~led_clk;    //每计满50_000_000个时钟周期(500ms),输出信号翻转一下
        else
            led_clk <=  led_clk;
    
    //经1hz信号输出到led
    assign led = led_clk;
 
endmodule 
  testbench测试文件如下:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Module Name: flashled_tb
// Description: flashled模块测试文件
//////////////////////////////////////////////////////////////////////////////////
`define clk_period 10   //100M时钟信号
module flashled_tb();
    reg clk;          //用于产生时钟信号
    reg rst;          //用于产生复位信号
    reg en;           //用于产生使能信号
    wire [15:0]led;   //观察led输出
    
    //例化测试模块
    flashled flashled_test(
        .clk(clk),          //时钟信号输入
        .rst(rst),          //复位信号输入
        .en(en),           //使能信号输入
        .led(led)           //led信号输出
        );
    
    //产生时钟信号
    initial clk = 1;
    always #(`clk_period/2) clk = ~clk;
    
    //开始测试
    initial begin
        rst = 1;                 //复位;
        en  = 0;
    #(`clk_period * 5);
         rst = 0;
    #(`clk_period * 5);   
          en = 1;                //使能
    #(`clk_period * 50 * 5 );   //仿真情况下计数器每计50次翻转,所以应该延时50 * 5个时钟周次观察翻转情况
          $stop;      
   end
     
endmodule

 

  测试结果如下:
技术分享图片

  综合电路图如下:

技术分享图片

  在编写testbench测试分频器模块时,由于计数器计数值为49_999_999 ,所以花费长时间,因为只需要测试功能,看模块计到设定值后会不会翻转信号,所以这样就是在浪费时间;

  为了加快仿真速度,可以在仿真时将最大值改为49,这样就非常快,为了方便,可以在verilog中使用条件编译:

  `ifdef SIMULATION        //仿真情况下
        parameter   CNT_MAX = 26d49;
     `else                  //板级验证情况下
        parameter   CNT_MAX = 26d49_999_999;
     `endif 

 

例3.基本移位操作——verilog位操作(流水灯:16个LED循环左移)
      //1.取某一位直接操作
      wire [2:0]m;
      assign m = out[5:3];

        //2.循环移位(移位寄存器)
        reg [7:0] shift_a;
        always@(posedge clk)
            shift_a <= {shifta[0],shift[7:1]};
        
        reg [7:0] shift_a;
        wire data;
        always@(posedge clk)
          shift_a <= {data,shift[7:1]};

        reg [7:0] shift_a;
        wire data;
        always@(posedge clk)
          shift_a <= {shift[7:1],data};

       //3、拼接
        wire [3:0]x;
        wire [3:0]y;
        wire [7:0]z;
        wire [31:0]n;

        assign z = {x,y};
        assign n = {x,7{x}};

 

   verilog设计代码如下(计数器部分和分频器相同):

    //移位寄存器功能描述
    always@(posedge clk,posedge rst)
        if(rst)
            led_temp <= 26h0001;
        else if(cnt == CNT_MAX)
              led_temp <= {led_temp[14:0],led_temp[15]};      //循环左移
        else
              led_temp <= led_temp;
     //输出到led
     assign led = led_temp; 

   testbench仿真测试文件和分频器相同;

   测试结果如下:

技术分享图片

技术分享图片

  综合出的电路图如下:

技术分享图片

 

FPGA学习笔记(六)—— 时序逻辑电路设计

原文:https://www.cnblogs.com/Mculover666/p/9077228.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!