2.4.2 Always语句
行为描述结构主要有初始化的initial结构和常态化的always结构。
一个程序中可以包含任意多个initial或always结构。这些结构都是相互并行执行的,即这些结构的执行顺序与其书写的顺序无关。一个initial结构或always结构的执行,产生一个单独的控制流,所有的initial和always结构都在0时刻开始并行执行。
由于本书基本不涉及initial结构故在此不予介绍,下面重点介绍always结构。
always结构是不断重复执行的过程,结构内部有多个语句的时候,一般是顺序执行的,除非用特殊的表达方式,语句可以并行执行。
1. always基本形式
always 最简单的是由一个赋值语言组成的语句体。例如下面的定义时钟例子。
always Clk = ~Clk; //此语句将无限循环执行。
这里的语句是Clk = ~Clk,always是一个结构的关键字(保留字)。在一行中出现“//”符号,表示后面是注释部分。如果要用多行进行注释,那么注释部分前端要用“ /*”符号,注释的结束处要使用“ */”符号。
此always结构有一个过程性赋值。因为always结构是重复执行的,并且在此例中没有延时控制,所以过程语句将在0时刻无限循环取值0和1。这种always结构体内的语句,在执行时必须带有某种延时控制,不然不会达到所希望的效果。
语句的延时控制描述,规定在语句的前面加“ #”和正整数的形式构成。上面的always结构,如果加上5个单位的延时控制,其表示如下。
always #5 Clk = ~Clk;
这个语句执行时将产生时钟周期为10个单位时间长度的波形,因为每隔5个单位时间,Clk的值就取反。语句前面不加“#”就表示没有延时,这个取反的变化只会在原地进行,就不会出现带延长时间的波形。
单位时间在Verilog HDL中规定用“`timescale 计时单位/计时精度”的宏来定义。规定宏语句结束是空格。例如,
`timescale 10ns/10ns
这个宏表示计时单位与计时精度都一样是10纳秒。定义时间宏使用规定,计时精度不能超过计时单位。如果我们不规定单位时间,Quartus II类的软件会自动设置缺省的时间,我们不必担心出问题。
always结构有事件触发的表达方式,形式是在always的后面添加“@”字符,并用括号指出事件。对于多个操作由事件触发的情况,要用begin ... end的方式将操作作语句包含在其中。例如,
reg Q,Qbar;
always @ (t)
begin
#5 Q = 1’b1;
#1 Qbar = ~Q;
end
第一句指出 Q,Qbar都是寄存器型变量,t是在别处定义的变量,在这里起着驱动结构体内部语句执行的作用,所以又叫敏感变量。这里用“=”连接的语句都是顺序执行的。因而这里描述的过程是:如果事件t发生变化,经过5个单位时间将二进制数1送到Q,之后再经过1个单位时间将Q的反码送给Qbar。
2. always内语句执行顺序
用“ =”连接的赋值方式是要消耗一定时间的,叫阻塞赋值。阻塞赋值的形式一般都用在顺序执行方式上。在顺序结构中,阻塞赋值语句要前一个执行完成,后面的一个语句才能够执行。
always结构的事件驱动还可以更加精确,精确到敏感变量变化的前沿或后沿的时刻驱动。这要使用保留字posedge或negedge修饰敏感变量。例如,
reg Q, Qbar;
always @(posedge t or negedge v)
begin
Q <= 1’b1;
Qbar <= ~Q;
end
这里的敏感变量有t和v,在t变化的前沿或v变化的后沿,begin与end之间的语句会执行,其他时间不执行。
符号“<=”表示的是没有延时的赋值,称为非阻塞赋值。
非阻塞赋值的语句都在事件发生的时刻执行。Verilog HDL规定,多个敏感变量只要有一个发生变化,都会引起always结构begin与end之间的语句执行。多个敏感变量之间用“or”或“,”进行列表。
非阻塞赋值同阻塞赋值的区别很严格,非阻塞赋值不用管其他语句是否执行,它只与敏感变量的变化时刻有关,而阻塞赋值要从前到后顺序执行。上面例子中的2个非阻塞赋值语句,就相当于两个并行执行的语句,所以本次执行完成之后,Qbar的值并不是本次Q值的反码0,而是前面一次t或v变化时Q值的反码。
行为描述结构主要有初始化的initial结构和常态化的always结构。
一个程序中可以包含任意多个initial或always结构。这些结构都是相互并行执行的,即这些结构的执行顺序与其书写的顺序无关。一个initial结构或always结构的执行,产生一个单独的控制流,所有的initial和always结构都在0时刻开始并行执行。
由于本书基本不涉及initial结构故在此不予介绍,下面重点介绍always结构。
always结构是不断重复执行的过程,结构内部有多个语句的时候,一般是顺序执行的,除非用特殊的表达方式,语句可以并行执行。
1. always基本形式
always 最简单的是由一个赋值语言组成的语句体。例如下面的定义时钟例子。
always Clk = ~Clk; //此语句将无限循环执行。
这里的语句是Clk = ~Clk,always是一个结构的关键字(保留字)。在一行中出现“//”符号,表示后面是注释部分。如果要用多行进行注释,那么注释部分前端要用“ /*”符号,注释的结束处要使用“ */”符号。
此always结构有一个过程性赋值。因为always结构是重复执行的,并且在此例中没有延时控制,所以过程语句将在0时刻无限循环取值0和1。这种always结构体内的语句,在执行时必须带有某种延时控制,不然不会达到所希望的效果。
语句的延时控制描述,规定在语句的前面加“ #”和正整数的形式构成。上面的always结构,如果加上5个单位的延时控制,其表示如下。
always #5 Clk = ~Clk;
这个语句执行时将产生时钟周期为10个单位时间长度的波形,因为每隔5个单位时间,Clk的值就取反。语句前面不加“#”就表示没有延时,这个取反的变化只会在原地进行,就不会出现带延长时间的波形。
单位时间在Verilog HDL中规定用“`timescale 计时单位/计时精度”的宏来定义。规定宏语句结束是空格。例如,
`timescale 10ns/10ns
这个宏表示计时单位与计时精度都一样是10纳秒。定义时间宏使用规定,计时精度不能超过计时单位。如果我们不规定单位时间,Quartus II类的软件会自动设置缺省的时间,我们不必担心出问题。
always结构有事件触发的表达方式,形式是在always的后面添加“@”字符,并用括号指出事件。对于多个操作由事件触发的情况,要用begin ... end的方式将操作作语句包含在其中。例如,
reg Q,Qbar;
always @ (t)
begin
#5 Q = 1’b1;
#1 Qbar = ~Q;
end
第一句指出 Q,Qbar都是寄存器型变量,t是在别处定义的变量,在这里起着驱动结构体内部语句执行的作用,所以又叫敏感变量。这里用“=”连接的语句都是顺序执行的。因而这里描述的过程是:如果事件t发生变化,经过5个单位时间将二进制数1送到Q,之后再经过1个单位时间将Q的反码送给Qbar。
2. always内语句执行顺序
用“ =”连接的赋值方式是要消耗一定时间的,叫阻塞赋值。阻塞赋值的形式一般都用在顺序执行方式上。在顺序结构中,阻塞赋值语句要前一个执行完成,后面的一个语句才能够执行。
always结构的事件驱动还可以更加精确,精确到敏感变量变化的前沿或后沿的时刻驱动。这要使用保留字posedge或negedge修饰敏感变量。例如,
reg Q, Qbar;
always @(posedge t or negedge v)
begin
Q <= 1’b1;
Qbar <= ~Q;
end
这里的敏感变量有t和v,在t变化的前沿或v变化的后沿,begin与end之间的语句会执行,其他时间不执行。
符号“<=”表示的是没有延时的赋值,称为非阻塞赋值。
非阻塞赋值的语句都在事件发生的时刻执行。Verilog HDL规定,多个敏感变量只要有一个发生变化,都会引起always结构begin与end之间的语句执行。多个敏感变量之间用“or”或“,”进行列表。
非阻塞赋值同阻塞赋值的区别很严格,非阻塞赋值不用管其他语句是否执行,它只与敏感变量的变化时刻有关,而阻塞赋值要从前到后顺序执行。上面例子中的2个非阻塞赋值语句,就相当于两个并行执行的语句,所以本次执行完成之后,Qbar的值并不是本次Q值的反码0,而是前面一次t或v变化时Q值的反码。