目录
对行为级建模的认识
与上一节学到的数据流建模,使用连续赋值语句进行建模的方式不同的是,行为级建模是采用过程化的结构进行建模,与数据流相比,效率大大提高。
过程语句
initial过程语句
inital过程语句是用于初始化的语句,主要用于仿真和测试,在可综合语句中,可做复位信号。initial语句的每个执行过程都是从仿真0时刻开始,整个仿真过程中只执行一次。如果一个模块中有多个initial块,则这些块从仿真0时刻开始
并发执行
,如果在某一个initial块中存在延迟,那么这个块就会停下来,等待延迟时间结束再继续进行。如一个initial块中有多条语句,一般用begin-end将他们组合再一起。
initial过程语句语法格式:
inital
begin
语句1;
语句2;
……
end
always过程语句
相对于initial语句整个过程只执行一次的触发状态,always语句的触发状态是一直存在的,
只要满足always后面的敏感事件列表,就会执行过程块。
always语句块的语法格式:
always@(敏感事件表)
语句块;
例子:
always@(a);//当a的状态改变时
always@(posedge clk or negedge ret);//当clk上升沿或ret下降沿到达时
例1.用always语句描述4选1数据选择器(经典的
组合逻辑电路
)
module mux4_1(out,in0,in1,in2,in3,sel) output out; input in0,in1in2,in3; input[1:0] sel; reg out; //被赋值信号必须定义为reg类型 always@(in0 or in1 or in2 or in3 or sel) case(sel) 2'b00: out=in0; 2'b01: out=in1; 2'b10: out=in2; 2'b11: out=in3; default: out=2'bx; endcase endmodule
例2.用always语句描述同步置数、同步清零计数器(经典的
时序逻辑电路
)
module counter(out,data,load,reset,clk); output[7:0] out; input[7:0] data; input load,clk,reset; reg[7:0] out; always@(posedge clk) //上升沿触发 begin if(!reset) out=8'b00;//同步清0 低电平有效 else if(load) out=data;//同步置数 else out=out+1; end endmodule
//同步清零,同步置数计数器原理
注意事项:
1)inital和always过程语句的
被赋值信号必须定义为reg类型
2)如何选取敏感事件表作为语句块的触发条件
a.采用过程对
组合电路
进行描述时,作为
全部的输入信号
需要列入敏感信号表;
b.采用过程对
时序电路
进行描述时,需要把
时间信号和部分输入信号
列入敏感信号列表,不同的敏感事件表会产生不同的电路形式。
语句块
串行语句块
串行语句块采用关键字begin-end,其中的语句按串行的方式顺序执行,它描述的是电路中数据在时钟及控制信号作用下,沿数据通道的各级寄存器之间的传输过程。可以用于可综合电路程序和仿真测试程序。
begin-end语法格式:
begin:块名
块内声明语句;
语句1;
语句2;
….
语句n;
end
串行语句块特点:
(1)串行语句块中每条语句依据块中的排列次序,先后逐条顺序执行。块中每条语句给出的延时都是相对于前一条执行结束的相对时间。
(2)串行语句块的起始执行时间就是串行语句块第一句语句开始执行的时间,结束时间是串行语句块中最后一条语句的结束时间。
并行语句块
并行语句采取关键字fork-join,其中语句按照
并行方式并发执行
,它描述的是电路上电后,各模块同时开始工作的过程。
fork-join语法格式:
fork:块名
块内声明语句;
语句1;
语句2;
….
语句n;
join
并行语句的特点:
(1)块内语句
是同时执行的
,语句之间可以颠倒顺序,延迟时间是相对于仿真0时刻的绝对时间。
(2)并行语句的起始时间是转入并行语句的时间,结束时间是执行时间最长的那条语句的执行结束时间。
过程赋值语句
过程赋值语句只在begin-end中讨论,有阻塞性过程赋值语句和非阻塞性过程赋值语句两种形式。
阻塞性过程赋值语句
阻塞性过程赋值语句在串行语句块中按照顺序依次执行,在并行语句中并发执行。执行阻塞性赋值语句的顺序是先计算等号右边的表达式的值,然后
立刻
将结果赋值给左边的变量,
与仿真时间无关。
语法格式:
变量=表达式;
例如b=a;
非阻塞过程赋值语句
非阻塞过程赋值语句是
串行语句块中的并行化语句
,各条非阻塞赋值语句的执行没有先后顺序执行,并发执行。执行非阻塞赋值语句的顺序是先计算右端表达式的值,然后
等到延时时间结束
时,将计算结果的值赋给左边的变量。
语法格式:
变量<=表达式
例如b<=a;
阻塞和非阻塞过程赋值语句的例子
代码举例
以下程序基本描述相同,不同的是程序(1)采用了阻塞赋值语句,程序(2)采用了非阻塞性赋值语句。
程序(1)
module procedure1(din,clk,out1,out2) input din,clk; output out1,out2; reg out1,out2; always@(posedge clk) begin out1=din; out2=out1; end endmodule
程序(2)
module procedure1(din,clk,out1,out2) input din,clk; output out1,out2; reg out1,out2; always@(posedge clk) begin out1<=din; out2<=out1; end endmodule
程序(2)若使用阻塞性赋值语句实现:
module procedure1(din,clk,out1,out2) input din,clk; output out1,out2; reg out1,out2; always@(posedge clk) begin out2=out1; out1=din; end endmodule
非阻塞赋值语句的优势
电路的一般结构为如图所示,它是由组合逻辑电路加时序逻辑电路构成,一般过程为寄存器->组合逻辑->寄存器,而这其中的组合逻辑部分的延迟对处理器的速度影响巨大,使用非阻塞赋值语句实现流水,大大提高主频效率,处理速度。
小结
在硬件描述语言中,
只有在行为级建模中的串行语句块中的阻塞赋值语句才是串行结构
,其余所有结构都是并行结构。
过程连续赋值语句
过程连续赋值语句是用来
临时分配
,有两种类型:赋值、重新赋值语句(assign deassign)和强制、释放语句(force release)。强制、释放语句的优先级和语法强度更高。
赋值、重新赋值语句(assign deassign)
语法格式:
赋值语句: assign<寄存器变量>=<赋值表达式>;
重新赋值语句:deassign<寄存器变量>;
例.使用assign和deassign设计异步清零D触发器
module program1(d,clr,clk,q) input d,clk,clr; output q; reg q; always@(clr) begin if(!clr) assign q=0;//清零信号来临时 临时q=0 else dessign q;//恢复q值 end always@(negedge clk) q=d; endmodule
强制、释放语句(force release)
语法格式:
强制语句: force<寄存器变量或连线型变量>=<赋值表达式>;
释放语句:release<寄存器变量或连线型变量>;
条件分支语句
条件分支语句的
可综合性极强
,在Verilog中极其重要。
if条件语句
if条件分支语句,与
C语言中的if语句的语法格式
完全相同。
语法格式有如下几种形式:
形式1:if(条件表达式)语句块;
形式2:if-else结构
形式3:if-else if-else结构
在if语句中同C语言相同,允许嵌套语句
例.条件分支语句可代替三目运算符(out=sel?a:b)实现经典2选1数据选择器
if (sel) out=a; else out=b;
case条件分支语句
case条件分支语句的分支更多,可实现多路分支选择控制语句,且更加直观。一般,可用于
描述真值表,描述有限状态机
,用于多条件译码电路设计。
case语法格式:
case(控制表达式)
值1:语句块1;
值2:语句块2;
……
值n:语句块n;
default:其他可能结果;
endcase
注:
(1)每个值必须不同,一旦判断到相同,执行后,立马结束case语句;
(2)default选项相当对if-else的else部分,如果前面已经列出所有可能结果,那么default可以忽略;如果不能包含全所有状态,那么缺省项必须写,否则将产生锁存器,这在同步时序电路设计中是不允许的;
(3)所有的值,位宽必须相等。
(4)case casex casez的区别:
case是全等比较
casex只比较0 1
casez只比较0 1 x
循环语句
forever循环语句
无限循环或永久循环。在永久循环中不包含任何条件表达式,只执行无限循环,直到遇到$finish结束。如果需要从循环中退出,可使用disable语句。
语法格式:
forever 语句或语句块;
注:
通常,forever 循环是和时序控制结构配合使用的。
例如,使用 forever 语句产生一个时钟:
repeat循环语句
关键字reapeat是固定次数的循环
语法格式:
reapeat(循环次数)
语句块或语句;
注:
repeat 循环的次数必须是一个常量、变量或信号。如果循环次数是变量信号,则循环次数是开始执行 repeat 循环时变量信号的值。即便执行期间,循环次数代表的变量信号值发生了变化,repeat 执行次数也不会改变。
while循环
关键字while循环是一种条件循环,根据表达式的真假判断是否还继续执行循环。
语法格式:
while(循环条件) 语句或语句块;
for循环
关键字for循环也是一种条件循环。但是在循环条件内可以定义循环次数。
语法格式:
for(循环变量赋初值,循环结束条件,循环变量递增递减) 语句块;
注:
(1)一般来说,因为初始条件和自加操作等过程都已经包含在 for 循环中,所以 for 循环写法比 while 更为紧凑,但也不是所有的情况下都能使用 for 循环来代替 while 循环。
(2)需要注意的是,i = i + 1 不能像 C 语言那样写成 i++ 的形式,i = i -1 也不能写成 i — 的形式。