分享

Verilog中阻塞和非阻塞赋值原则

 丁毛毛qxevv5ba 2017-12-24


阻塞赋值操作符 =

阻塞赋值是指当前的赋值语句阻断了其后的语句,也就是说后面的语句必须等到当前的赋值语句执行完毕才能执行。阻塞赋值可以看成是一步完成的,即计算等号右边的值并同时赋给左边变量。


例如:采用阻塞赋值实现四选一多路选择器。

module mux4_to_1 (out, i0, i1, i2, i3, s0, s1);

    output out;

    input i0,i1,i2,i3,s0,s1;

    reg out;


    always @(s1 or s0 or i0 or i1 or i2 or i3)

    begin

        case ( {s1, s0} )

            2'b00: out = i0;

            2'b01: out = i1;

            2'b10: out = i2;

            2'b11: out = i3;

            default: out = 1'bx;

        endcase    

    end

endmodule


非阻塞赋值



非阻塞赋值操作符 <=

非阻塞赋值是指在过程块中,当前的赋值语句不会阻断其后的语句。非阻塞赋值操作只能用于对寄存器型变量进行赋值,因此只能用在'initial'块和'always'块等过程块中。非阻塞赋值不允许用于连续赋值。


例如:采用非阻塞赋值实现移位寄存器。

module mux4_to_1 (q3, d, clk);

    output [7:0] q3;

    input [7:0] d;

    input clk;

    reg [7:0] q3, q2, q1;


    always @(posedge or clk)

    begin

        q1 <= d;

        q2 <= q1;

        q3 <= q2;

    end

endmodule


简单理解就是,阻塞赋值是按需执行,非阻塞赋值是并行执行。


在编写Verilog代码时,要牢记:


  • 时序电路建模时,用非阻塞赋值。

  • 锁存器电路建模时,用非阻塞赋值。

  • 用always块建立组合逻辑模型时,用阻塞赋值。

  • 在同一个always块中建立时序和组合逻辑电路时,用非阻塞赋值。

  • 在同一个always块中不要既用阻塞又用非阻塞赋值。

  • 不要在一个以上的always块中为同一个变量赋值。

  • 用$strobe系统任务来显示用非阻塞赋值的变量值。

  • 在赋值时,不要使用#0延迟。



应用举例



用always块描述组合逻辑时,应采用阻塞赋值语句例如,用阻塞赋值实现四输入与或非门。

module ex4_to_1 (y, a, b, c, d);

    output y;

    input a, b, c, d;

    reg y, tmp1, tmp2;


    always @(a or b or c or d)

    begin

        tmp1 = a & b;

        tmp2 = c & d;

        y = tmp1 | tmp2

    end

endmodule




当把组合逻辑和时序逻辑写入到同一个always块中时,应遵从时序逻辑建模原则,使用非阻塞赋值例如,实现一个具有异步复位功能的触发器,该触发器利用时钟上升沿触发,输出q等于输入a、b的异或。

module nbex2 (q, a, b, clk, rst_n);

    output q;

    input a, b, clk, rst_n;

    reg q;


    always @(posedge clk  or  negedge rst_n)

        if ( !rst_n ) q <= 1'b0;    //时序逻辑

        else           q <= a^b;     //异或,组合逻辑

endmodule


也可以将组合和时序逻辑分写在两个always块中,不要在同一个always块中同时使用阻塞和非阻塞赋值。

module nbex2 (q, a, b, clk, rst_n);

    output q;

    input a, b, clk, rst_n;

    reg q, y;


    always @(a  or  b)

        y = a^b;

    always @(posedge clk  or  negedge rst_n)

        if ( !rst_n ) q <= 1'b0; 

        else           q <= y; 

endmodule


在一个以上的always块中对同一个变量进行多次赋值可能会导致竞争冒险,即使采用非阻塞赋值也可能会产生竞争冒险。




用Verilog HDL描述加法器电路很简单,综合器可以根据用户的配置自动综合成相应的加法器,比如配置成超前进位的并行加法器。四位加法器的行为描述方式如下:

module add_4 (cout, sum, a, b, cin);

    output cout;

    output [3:0]  sum;

    input [3:0]  a,b;

    input cin;


    assign {cout, sum} = a b cin;

endmodule




用Verilog HDL描述八位乘法器

module mult_8 (X, Y, Product);

    input [7:0]  X, Y;

    output [15:0]  Product;


    assign Product = X * Y;

endmodule


您也可以自己具体描述乘法器的实现方式:

    parameter size = 8, longsize = 16;

    reg [size:1]  opa, opb;

    reg [longsize:1]  result;


    begin: mult

         integer bindex;

         result = 0;

         for (bindex=1; bindex<=size; bindex=bindex 1)

             if (opb[bindex])

                 result = result (opa<<(bindex-1));

    end




3-8译码器设计实例(无使能控制端)

module decoder (out, in);

    output [7:0]  out;

    input [2:0]  in;


    assign out = 1'b1<<in;

endmodule




简单的比较器设计实例

module compare (equal, a, b);

    parameter size = 1;

    output  equal;

    input [size-1:0]  a, b;


    assign equal = (a==b)? 1 : 0;

endmodule




多路选择器设计实例

module mux2 (out, a, b, sel);

    output  out;

    input  a, b,sel;

    reg out;


    always @( a or b or sel )

     begin

         case (sel)

             1'b0: out = a;

             1'b1: out = b;

             default: out = 'bx;

          endcase

      end    

endmodule




奇偶校验位生成器设计实例

module parity (even_bit, odd_bit, input_bus);

    output  even_bit, odd_bit;

    input [7:0]  input_bus;


    assign odd_bit = ^input_bus;

    assign even_bit = ~odd_bit;

endmodule




三态输出驱动器设计实例

module trist1 (out, in, enable);

    output  out;

    input in, enable;


    assign out = enable? in : 'bz;

endmodule


三态双向驱动器设计实例

module bidir (tri_inout, out, in, enable, b);

    inout  tri_inout;

    output  out;

    input in, enable, b;


    assign tri_inout = enable? in : 'bz;

    assign out = tri_inout ^ b;

endmodule




触发器设计实例

module dff (q, data, clk);

    output  q;

    input  data, clk;

    reg q;


    always @( posedge clk )

         begin

             q <= data;

          end    

endmodule


电平敏感型锁存器设计实例

module latch1 (q, data, clk);

    output  q;

    input  data, clk;

    assign q = clk ? data : q;

endmodule


带置位和复位端的电平敏感型锁存器设计实例

module latch2 (q, data, clk, set, reset);

    output  q;

    input  data, clk, set, reset;

    assign q = reset? 0 : (set? 1 : (clk ? data : q ));

endmodule




移位寄存器设计实例

module shifter ( din, clk, clr, dout );

    input  din, clk, clr;

    output [7:0] dout;

    reg [7:0] dout;


    always @( posedge clk )

         begin

             if (clr) dout <= 8'b0;

             else

                 begin

                     dout <= dout << 1;

                     dout[0] <= din;

                 end

          end    

endmodule




8位计数器设计实例

module counter1 ( out, cout, data, load, cin, clk );

    output [7:0] out;

    output cout;

    input [7:0] data;

    input load, cin, clk;

              reg [7:0] out;


    always @( posedge clk )

         begin

             if (load) 

                 out <= data;

             else

                  out <= out cin;

          end

    assign cout = (&out) & cin;

endmodule




Verilog HDL 三段式状态机模版


在用Verilog编写状态机时,建议分为三个alwaysk块完成。

三段式描述风格虽然代码结构复杂了一些,但这样做容易发现问题和改正模块编写中出现的问题。

 

//第一个always块,描述在时钟驱动下次态迁移到现态。

always @ (posedge clk or negedge rst_n)  //异步复位

if (!rst_n)

current_state<= IDLE;

else

current_state<= next_state; //注意,使用非阻塞赋值

 

//第二个always块,描述状态的转移关系

always @ (current_state)   //电平触发,将现态作为敏感信号

begin

    case (current_state)

S1: next_state = S2;  //阻塞赋值

       S2: next_state = S3;  //阻塞赋值

       ……

       default: next_state = ‘bx; //对多余状态的处理

    endcase

end

 

//第三个always块,描述每个状态对应的输出

always @ (current_state)

begin

     ...

    case (current_state)

 S1: out1 = 1'b1; //对输出进行赋值

 S2: out2 = 1'b1;

        ……

 default: ...       // 避免综合出锁存器。

    endcase

end


这种风格的描述比较适合大型的状态机,查错和修改也比较容易,很多公司的综合器都建议使用这种风格来描述状态机,俗话说,学好数电,风光无限。



    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多