非阻塞赋值的例子:新赋值不会影响当前always中执行的语句,因为其综合成寄存器,有效输入是时钟上升沿到达前的数据。
reg c,b;
always@(posedge clk)
begin
b <= a;
c <= b;
end
非阻塞赋值语句简述为:在一个always 块中,语句是并行执行的
module nonblockingassignment (clk ,q1,q2);
input clk;
output [2:0] q1,q2;
reg[2:0] q1,q2;
always @ (posedge clk)
begin
q1<=q1+3'b1;
q2<=q1;
end
endmodule
寄存器是clk边沿触发,在clk边沿时更新寄存器输出,根据其时钟特性,在clk脉冲到来前,输入值就必须提前到达寄存器输入端。所以在新的clk时更新的输入值不可能影响到寄存器输出。这也就是always中的非阻塞赋值不会影响同一clk中其他的非阻塞赋值。
以下是使用阻塞和非阻塞赋值应遵循的一些基本原则,这些原则有利于防止竞态(race condition)的发生。
(1)当用always块来描述组合逻辑(combinational logic)时,即不是由clk触发的应当使用阻塞赋值。
1 always@(sel or a or b) begin
2 case (sel)
3 2'b00 : c = a;
4 2'b01 : c = b;
5 endcase
6 end
(2)对于时序逻辑(sequential logic)的描述和建模,即由clk触发的应当使用非阻塞赋值。
reg c,b;
always@(posedge clk)
begin
b <= a;
c <= b;
end
(3)在同一个always模块中,不要混合使用阻塞赋值和非阻塞赋值,对同一变量既进行阻塞赋值,又进行非阻塞赋值,在综合时会出错。所以在由clk触发的always中全部使用非阻塞赋值,电平触发的always中使用阻塞赋值,把阻塞赋值和非阻塞赋值分在不同的always中书写。
(4)尽量不要再在多个不同的always块中对同一变量赋值。
(5)使用$strobe显示使用非阻塞赋值的变量。
verilog中的for循环和C语言中的for循环不一样,表示的是电路的硬件行为,循环几次,就是将相同的电路复制几次!
integer i; //be careful, i should be integer!
for(i = 0;i <= 7 ;i = i+1)begin
if(data_in[i])
data_out[i] <= 1;
else
data_out[i] <= 1'bz;
end
上面的语句就是相当于8个选择器
assign data_out[0] = data_in[0]?1:1'bz;
``````
assign data_out[7] = data_in[7]?1:1'bz;
因为for loop是复制电路行为,所以互相之间并行,可将其放在always中或者generate模块中。在两种模块中的i类型与赋值方式均不同,示例如下。
Example:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 08/14/2014 11:10:33 AM
// Design Name:
// Module Name: top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module top(
input clk,
input[7:0] data,
output reg[7:0] q //for always,reg q
//output [7:0] q //for generate,net q
);
integer i; //always format
always@(posedge clk) begin
for(i=0;i<8;i=i+1)begin
q[i]<=data[i];
end
end
/* genvar i; //generate format
generate
for(i=0;i<8;i=i+1)begin
assign q[i]=data[i];
end
endgenerate*/
endmodule
由RTL图可知,生成了八个register。
对于loop中的 integer i: integer类型一般只是用于loop,其他时候基本不用此类型,其默认是32bit。