• Verilog实现FPGA常用的电路


    一、异步信号同步器设计

    1、复位的设计:采用异步复位,同步释放电路

    http://www.cnblogs.com/qiweiwang/archive/2010/11/25/1887888.html

    2、异步信号同步器:

    http://www.srvee.com/analog/apply/ybxhtbqsj_60096_2.html

      ①电平同步器

    level
     1 module synzer_ls(
     2                  data_out,
     3                  clk1,
     4                  clk2,
     5                  data_in
     6                  ); //level signal synchronizer
     7 
     8   output     data_out;  // signal that after synchronized
     9   input      clk1;      // old clk signal
    10   input      clk2;      // new clk signal
    11   input      data_in;   // signal that before synchronized
    12 
    13   reg        a;         // DFF in the old clk domain
    14   reg        b;         // the first DFF in the new clk domain
    15   reg        c;         // the second DFF in the new clk domain
    16 
    17   always @(posedge clk1) //a
    18     a<=data_in; 
    19   
    20   always @(posedge clk2) //b
    21     b<=a;
    22 
    23   always @(posedge clk2) //c
    24     c<=b;
    25  
    26   assign data_out=c;
    27 
    28 endmodule

      ②边沿检测同步器

      

    edge
     1 module synzer_ed(
     2                  data_out,
     3                  clk1,
     4                  clk2,
     5                  data_in
     6                  ); // edge detecting synchronizer
     7 
     8   output     data_out;  // signal that after synchronized
     9   input      clk1;      // old clk signal
    10   input      clk2;      // new clk signal
    11   input      data_in;   // signal that before synchronized
    12 
    13   reg        a;         // DFF in the old clk domain
    14   reg        b;         // the first DFF in the new clk domain
    15   reg        c;         // the second DFF in the new clk domain
    16   reg        d;         // the third DFF in the new clk domain
    17 
    18   always @(posedge clk1) //a
    19     a<=data_in; 
    20   
    21   always @(posedge clk2) //b
    22     b<=a;
    23 
    24   always @(posedge clk2) //c
    25     c<=b;
    26   
    27   always @(posedge clk2) //d
    28     d<=c;
    29 
    30   assign data_out=c&&(~d);
    31 
    32 endmodule

      ③脉冲检测同步器

    pluse
     1 module synzer_pl(
     2                  data_out,
     3                  clk1,
     4                  clk2,
     5                  data_in,
     6                  rst_n
     7                 );  // pulse synchronizer
     8              
     9  output     data_out; // signal that after synchronized
    10  input      clk1;     // old clk signal
    11  input      clk2;     // new clk signal
    12  input      data_in;  // signal that before synchronized
    13  input      rst_n;    // signal indicating reset 
    14  
    15  reg        a;        // DFF in the old clk domain
    16  reg        b;        // the first DFF in the new clk domain
    17  reg        c;        // the second DFF in the new clk domain
    18  reg        d;        // the third DFF in the new clk domain
    19  
    20  wire       q;
    21  wire       q1;
    22  wire       di;
    23  
    24  assign di=data_in?q1:q;
    25  assign q=a;
    26  assign q1=~a;
    27  assign data_out=(c==d)?0:1;
    28  
    29  always @(posedge clk1) //a
    30  begin
    31    if(!rst_n)
    32      a<=1'b0;
    33    else
    34      a<=di;
    35  end
    36  
    37  always @(posedge clk2) //b
    38     b<=a;
    39 
    40   always @(posedge clk2) //c
    41     c<=b;
    42   
    43   always @(posedge clk2) //d
    44     d<=c;
    45     
    46 endmodule

     二、常用触发器实现

    http://www.eefocus.com/article/08-03/37231s.html

    2.6.1 Verilog基本模块

    1.触发器的Verilog实现

    时序电路是高速电路的主要应用类型,其特点是任意时刻电路产生的稳定输出不仅与当前的输入有关,而且还与电路过去时刻的输入有关。时序电路的基本单元就是触发器。下面介绍几种常见同步触发器的Verilog实现。

    • 同步RS触发器

    RS触发器分为同步触发器和异步触发器,二者的区别在于同步触发器有一个时钟端clk,只有在时钟端的信号上升(正触发)或下降(负触发)时,触发器的输出才会发生变化。下面以正触发为例,给出其Verilog代码实现。

    例2-15 正触发型同步RS触发器的Verilog实现。

    module sy_rs_ff (clk, r, s, q, qb);
            input clk, r, s;
            output q, qb;
            reg q;

            assign qb = ~ q;
            always @(posedge clk) begin
                   case({r, s})
                              2'b00: q <= 0;
                              2'b01: q <= 1; 
                              2'b10: q <= 0;
                              2'b11: q <= 1'bx;
                   endcase
             end
    endmodule

    上述程序经过综合Synplify Pro后,其RTL级结构如图2-2所示。



    图2-2 同步RS触发器的RTL结构图


    在ModelSim 6.2b中完成仿真,其结果如图2-3所示



    图2-3 同步RS触发器的仿真结果示意图

    • 同步T触发器

    T触发器也分为同步触发器和异步触发器,二者的区别在于同步T触发器多了一个时钟端。同步T触发器的逻辑功能为:当时钟clk沿到来时,如果T=0,则触发器状态保持不变;否则,触发器输出端反转。R为复位端,当其为高电平时,输出Q与时钟无关,Q=0。

    例2-16 同步T触发器的Verilog实现。

    module sy_t_ff(clk, r, t, q, qb);
            input clk, r, t;
            output q, qb;
            reg q;

            assign qb = ~q;
            always @(posedge clk) begin
                   if(r)
                       q <= 0; 
                   else
                        q <= ~q;
            end
    endmodule

            上述程序经过综合Synplify Pro后,其RTL级结构如图2-4所示。



    图2-4 同步T触发器电路的RTL结构图


    在ModelSim 6.2b中完成仿真,其结果如图2-5所示



    图2-5 同步T触发器的仿真结果示意图

    •  同步D触发器

    同步D触发器的功能为: D输入只能在时序信号clk的沿变化时才能被写入到存储器中,替换以前的值,常用于数据延迟以及数据存储模块中。

    例2-17 同步D触发器的Verilog实现。

    module sy_d_ff(clk, d, q, qb);
            input clk, d;
            output q, qb;
            reg q;

            assign qb = ~q;
            always @(posedge clk) begin
                   q <= d;
            end
    endmodule

    上述程序经过综合Synplify Pro后,其RTL级结构如图2-6所示。



    图2-6 同步D触发器的RTL结构图


    在ModelSim 6.2b中完成仿真,其结果如图2-7所示



    图2-7 同步D触发器的仿真结果示意图

    • 同步JK触发器

    JK触发器是在RS触发器的基础上发展而来的,常用于实现计数器。当clk=0时,触发器不工作,处于保持状态。当时钟clk=1时,触发器的功能如下:当JK为00、01以及10时实现RS触发器的功能;当JK为11时实现T触发器的功能。

    例2-18 同步JK触发器的Verilog实现。

    module sy_jk_ff(clk, j, k, q, qb);
            input clk, i, k;
            output q, qb;
            reg q;

            assign qb = ~q;
            always @(posedge clk) begin
                    case({j, k})
                               2'b00: q <= q;
                               2'b01: q <= 0; 
                               2'b10: q <= 1;
                               2'b11: q <= ~q; 
                     endcase 
            end
    endmodule

    上述程序经过综合Synplify Pro后,其RTL级结构如图2-8所示。



    图2-8 同步JK触发器的RTL结构图 


    在ModelSim 6.2b中完成仿真,其结果如图2-9所示



    图2-9 同步JK触发器的仿真结果示意图



    2.三态缓冲器的Verilog实现

    三态缓冲器也称三态门,其典型应用是双向端口,常用于双向数据总线的构建。在数字电路中,逻辑输出有两个正常态:低电平状态(对应逻辑0)和高电平状态(对应逻辑1);此外,电路还有不属于0和1状态的高组态(对应于逻辑Z)。所谓高阻,即输出端属于浮空状态,只有很小的漏电流流动,其电平随外部电平高低而定,门电平放弃对输出电路的控制。或者可以理解为输出与电路是断开的。最基本的三态缓冲器的逻辑符号如图2-10所示。

     

    图2-10 三态缓冲器的逻辑符号图


    当OE为高电平时,Dataout与Datain相连;而OE为低时,Dataout为高阻态,相当于和Datain之间的连线断开。

    例2-19 使用Verilog实现三态缓冲器

    inout a;
    wire z, b;
    //当控制信号z为1时,开通三态门,b为输入端口;当z为0时,三态门为高阻,
    //a为输出端口
    assign a = (z) ? b : 8'bz;

    3.38译码器的Verilog实现

    38译码器是通过3条线来达到控制8条线的状态,就是通过3条控制线不同的高低电平组合, 一共可以组合出23=8种状态。在电路中主要起到扩展IO资源的作用。当然,可根据实际需求将38译码器扩展到更高级数上。

    例2-20 使用Verilog实现38译码器

    module decoder3to8(din, reset, dout);
        input [2:0] din;
        input reset;
        output [7:0] dout;

        reg [7:0] dout;
        always @(din or reset) begin
               if(!reset)
               dout = 8'b0000_0000;
        else
               case(din)
                          3'b000: dout = 8'b0000_0001;
                          3'b001: dout = 8'b0000_0010; 
                          3'b010: dout = 8'b0000_0100;
                          3'b011: dout = 8'b0000_1000; 
                          3'b100: dout = 8'b0001_0000; 
                          3'b101: dout = 8'b0010_0000; 
                          3'b110: dout = 8'b0100_0000; 
                          3'b111: dout = 8'b1000_0000; 
               endcase
        end

    endmodule

    上述程序经过综合Synplify Pro后,其RTL级结构如图2-11所示。




    图2-11 38译码器的RTL结构图 


    在ModelSim 6.2b中完成仿真,其结果如图2-12所示



    图2-12 38译码器的仿真结果示意图


    2.6.2 基本时序处理模块

    1.奇、偶数分频电路

    在数字逻辑电路设计中,分频器是一种基本电路。通常用来对某个给定频率进行分频,以得到所需的频率。

    • 偶数分频电路

    偶数倍分频是最简单的一种分频模式,完全可通过计数器计数实现。如要进行N倍偶数分频,那么可由待分频的时钟触发计数器计数,当计数器从0计数到N/2-1时,输出时钟进行翻转,并给计数器一个复位信号,使得下一个时钟从零开始计数,以此循环下去。这种方法可以实现任意的偶数分频。例2-21给出的是一个16分频电路,其它倍数的分频电路可通过修改计数器的上限值得到。

    例2-21 用Verilog实现一个16分频电路。

    module clk_div16(clk_in, reset, clk_out);
            input clk_in; 
            input reset;
            output clk_out; 

            reg clk_out; 
            reg [2:0] cnt; 
            always @(posedge clk_in) begin
                     if(!reset) begin
                     cnt <= 0;
                     clk_out <= 0; 
             end
             else
                 if(cnt == 7) begin 
                       cnt <= 0;
                       clk_out <= !clk_out;
                 end
                 else begin
                         cnt <= cnt + 1;
                               clk_out <= clk_out;
                  end
              end

    endmodule

    上述程序经过综合Synplify Pro后,其RTL级结构如图2-13所示。




    图2-13 16分频电路的RTL结构图


    在ModelSim 6.2b中完成仿真,其结果如图2-14所示,从中可以看出例2-21成功实现了输入时钟的16分频。


    图2-14 16分频电路的仿真结果示意图

    • 奇数分频电路

    奇数倍分频有多种实现方法,下面介绍常用的错位“异或”法的原理。如进行三分频,通过待分频时钟上升沿触发计数器进行模三计数,当计数器计数到邻近值进行两次翻转。比如在计数器计数到1时,输出时钟进行翻转,计数到2时再次进行翻转,即在邻近的1和2时刻进行两次翻转。这样实现的三分频占空比为1/3或者2/3。如果要实现占空比为50%的三分频时钟,可以通过待分频时钟下降沿触发计数,和上升沿同样的方法计数进行三分频,然后将下降沿产生的三分频时钟和上升沿产生的时钟进行相或运算,即可得到占空比为50%的三分频时钟。
           
    这种错位“异或”法可以推广实现任意的奇数分频:对于实现占空比为50%的N倍奇数分频,首先进行上升沿触发的模N计数,计数到某一选定值时进行输出时钟翻转,然后经过(N-1)/2再次进行翻转得到一个占空比非50%奇数N分频时钟。再者同时进行下降沿触发的模N计数,到和上升沿触发输出时钟翻转选定值相同值时,进行输出时钟时钟翻转,同样经过(N-1)/2时,输出时钟再次翻转生成占空比非50%的奇数N分频时钟。两个占空比非50%的N分频时钟相或运算,得到占空比为50%的奇数N分频时钟。

    例2-22 使用Verilog实现3分频电路。

    module clk_div3(clk_in, reset, clk_out);
         input clk_in;
         input reset;
         output clk_out;

         reg [1:0] cnt, cnt1;
         reg clk_1to3p, clk_1to3n;
         always @(posedge clk_in) begin
                if(!reset) begin
                       cnt <= 0;
                       clk_1to3p <= 0;
                end
                else begin
                       if(cnt == 2'b10) begin
                            cnt <= 0;
                                  clk_1to3p <= clk_1to3p; 
                end
                else begin
                      cnt <= cnt + 1;
                            clk_1to3p <= !clk_1to3p;
                      end 
                end       
         end

         always @(negedge clk_in) begin
              if(!reset) begin
                     cnt1 <= 0;
                          clk_1to3n <= 0;
               end
               else begin
                         if(cnt1 == 2'b10) begin
                              cnt1 <= 0;
                                      clk_1to3n <= clk_1to3n; 
                          end
                          else begin
                                cnt1 <= cnt1 + 1; 
                              clk_1to3n <= !clk_1to3n; 
                          end
                end 
            end

            assign clk_out = clk_1to3p | clk_1to3n;

    endmodule

    上述程序经过综合Synplify Pro后,其RTL级结构如图2-15所示。

     


    图2-15 3分频电路的RTL结构图


    在ModelSim 6.2b中完成仿真,其结果如图2-16所示,可以看到输出时钟为占空比为50%的3分频时钟。




    图2-16 3分频电路的仿真结果


    2.同步采样模块

    在实际应用中,外部输入的异步信号需要经过系统时钟的同步化,且将输入的异步信号整形成一个时钟长的脉冲信号,如图2-17所示。这里以例2-23来说明实现的方法。




    图2-17 异步信号的同步采样示意图


    例2-23 使用Verilog将外部异步信号进行同步整形。

    module clk_syn(clk, reset, s_in, s_out);
          input clk;
          input reset;
          input s_in; 
          output s_out;

          reg s_t1, s_t2;
          always @(posedge clk) begin
                 if(!reset) begin 
                        s_t1 <= 0;
                        s_t2 <= 0;
                 end 
                 else begin
                       s_t1 <= s_in; 
                       s_t2 <= s_t1; 
                 end 
           end 

           assign s_out = s_t1 & (!s_t2);

    endmodule

    上述程序经过综合Synplify Pro后,其RTL级结构如图2-18所示。从结果上看,该电路非常简单,但需要一定的时序逻辑能力才能真正理解该段程序。




    图2-18 同步电路的RTL结构示意图


    在ModelSim 6.2b中完成仿真,其结果如图2-19所示,将不等长的高电平信号整形成宽度为一个时钟周期的脉冲信号。




    图2-19 同步电路的仿真结果示意图


    其中,如果在时钟的上升沿din="1",则x=1,y=0,dout=x and (not y)=1;如果din="1"超过一个时钟宽度,则x=1,y=1,dout=x and (not y)=0。即使din在时钟周期内出现抖动,也不会影响输出结果,还是被整形成一个时钟宽度。所以不管是长周期信号还是短周期信号,经过同步采样后,有效高电平宽度都等于时钟周期。

    3.同步状态机的Verilog实现

    状态机一般包括组合逻辑和寄存器逻辑两部分。组合电路用于状态译码和产生输出信号,寄存器用于存储状态。状态机的下一个状态及输出不仅与输入信号有关,还与寄存器当前状态有关。根据输出信号产生方法的不同,状态机可分为米里(Mealy)型和摩尔(Moore)型。前者的输出是当前状态和输入信号的函数,后者的输出仅是当前状态的函数。在硬件设计时,根据需要决定采用哪种状态机。

    • 状态编码 

    状态编码又称状态分配。通常有多种编码方法,编码方案选择得当,设计的电路可以简单;反之,电路会占用过多的逻辑或速度降低。设计时,须综合考虑电路复杂度和电路性能这两个因素。下面主要介绍二进制编码、格雷编码和独热码。

    二进制编码和格雷码都是压缩状态编码。二进制编码的优点是使用的状态向量最少,但从一个状态转换到相邻状态时,可能有多个比特位发生变化,瞬变次数多,易产生毛刺。格雷编码在相邻状态的转换中,每次只有1个比特位发生变化,虽减少了产生毛刺和一些暂态的可能,但不适用于有很多状态跳转的情况。

    独热码是指对任意给定的状态,状态向量中只有1位为1,其余位都为0。n状态的状态机需要n个触发器。这种状态机的速度与状态的数量无关,仅取决于到某特定状态的转移数量,速度很快。当状态机的状态增加时,如果使用二进制编码,那么状态机速度会明显下降。而采用独热码,虽然多用了触发器,但由于状态译码简单,节省和简化了组合逻辑电路。独热编码还具有设计简单、修改灵活、易于综合和调试等优点。对于寄存器数量多、而门逻辑相对缺乏的FPGA器件,采用独热编码可以有效提高电路的速度和可靠性,也有利于提高器件资源的利用率。独热编码有很多无效状态,应该确保状态机一旦进入无效状态时,可以立即跳转到确定的已知状态。

    • 有限状态机的Verilog实现

    用Verilog 语言描述有限状态机可使用多种风格,不同的风格会极大地影响电路性能。通常有3种描述方式:单always块、双always块和三always块。

    单always块把组合逻辑和时序逻辑用同一个时序always块描述,其输出是寄存器输出,无毛刺。但是这种方式会产生多余的触发器,代码难于修改和调试,应该尽量避免使用。
           
    双always块大多用于描述Mealy状态机和组合输出的Moore状态机,时序always块描述当前状态逻辑,组合逻辑always块描述次态逻辑并给输出赋值。这种方式结构清晰,综合后的面积和时间性能好。但组合逻辑输出往往会有毛刺,当输出向量作为时钟信号时,这些毛刺会对电路产生致命的影响。
           
    三always块大多用于同步Mealy状态机,两个时序always块分别用来描述现态逻辑和对输出赋值,组合always块用于产生下一状态。这种方式的状态机也是寄存器输出,输出无毛刺,并且代码比单always块清晰易读,但是面积大于双always块。随着芯片资源和速度的提高,目前这种方式得到了广泛应用。
           
    下面以三always块模块给出状态机的Verilog模板。

    // 构成状态跳转环
    always @(posedge clk or negedge rst_n)
             current_state <= next_state;

    // 完成状态机的内部逻辑
    always @ (current_state or ) begin
              case(current_state)
                      S1: next_state = S2;
                      S2: next_state = S1;
              default: next_state = S2;
              endcase 
    end

    // 完成状态机的外部逻辑
    always @(current_state or ) begin
           case(current_state) 
           S1: 
           S2:
           default: 
           endcase
    end 

    •  综合状态机的一般原则

    在硬件描述语言中,许多基于仿真的语句虽然符合语法规则,但是不能映射到硬件逻辑电路单元,如果要最终实现硬件设计,必须写出可以综合的程序。通常,综合的原则为:

      1. 综合之前一定要进行仿真,仿真会暴露逻辑错误。如果不做仿真,没有发现的逻辑错误会进入综合器,使综合的结果产生同样的逻辑错误。 
      2.  每一次布线之后都要进行仿真,在器件编程或流片之前一定要进行最后的仿真。 
      3.  用Verilog HDL描述的异步状态机是不能综合的,应该避免用综合器来设计。在必须设计异步状态机时,建议用电路图输入的方法
      4. 状态机应该有一个异步或同步复位端,以便在通电时将硬件电路复位到有效状态。建议使用异步复位以简化硬件开销。
      5. 时序逻辑电路建模时,用非阻塞赋值。用always块写组合逻辑时,采用阻塞赋值。不要在多个always块中为同一个变量赋值。
      6.  always块中应该避免组合反馈回路。在赋值表达式右端参与赋值的信号都必须出现在敏感信号列表中,否则在综合时,会为没有列出的信号隐含地产生一个透明锁存器。 

    三、其他

    鉴相:

      

    滤波:

  • 相关阅读:
    首评 | 阿里云顺利完成国内首个云原生安全成熟度评估
    基于任务调度的企业级分布式批处理方案
    阿里云发布性能测试 PTS 2.0:低成本、高效率、多场景压测,业务稳定性保障利器
    OpenKruise v1.2:新增 PersistentPodState 实现有状态 Pod 拓扑固定与 IP 复用
    ZooKeeper 在阿里巴巴的服务形态演进
    阿里云微服务引擎 MSE 5 月产品动态
    应用实时监控服务ARMS 5 月功能快报&优惠汇总
    618 大促来袭,浅谈如何做好大促备战
    「技术人生」第8篇:如何画业务大图
    Serverless Job——传统任务新变革
  • 原文地址:https://www.cnblogs.com/lanlingshan/p/2625364.html
Copyright © 2020-2023  润新知