夏宇闻教材3

发布时间 : 星期日 文章夏宇闻教材3更新完毕开始阅读

3.4.1 赋值语句

在Verilog HDL语言中,信号有两种赋值方式:

(1).非阻塞(Non_Blocking)赋值方式( 如 b <= a; ) 1) 块结束后才完成赋值操作。 2) b的值并不是立刻就改变的。 3) 这是一种比较常用的赋值方法。(特别在编写可综合模块时)

(2).阻塞(Blocking)赋值方式( 如 b = a; ) 1) 赋值语句执行完后,块才结束。

2) b的值在赋值语句执行完后立刻就改变的。 3) 可能会产生意想不到的结果。

非阻塞赋值方式和阻塞赋值方式的区别常给设计人员带来问题。问题主要是给\块内的reg型信号的赋值方式不易把握。到目前为止,前面所举的例子中的\模块内的reg型信号都是采用下面的这种赋值方式:

b <= a;

这种方式的赋值并不是马上执行的,也就是说\块内的下一条语句执行后,b并不等于a,而是保持原来的值。\块结束后,才进行赋值。而另一种赋值方式阻塞赋值方式,如下所示:

b = a;

这种赋值方式是马上执行的。也就是说执行下一条语句时,b已等于a。尽管这种方式看起来很直观,但是可能引起麻烦。下面举例说明:

[例1]:always @( posedge clk ) begin b<=a; c<=b; end

[例1] 中的\块中用了非阻塞赋值方式,定义了两个reg型信号b和c,clk信号的上升沿到来时,b就等于a,c就等于b,这里应该用到了两个触发器。请注意:赋值是在\块结束后执行的,c应为原来b的值。这个\块实际描述的电路功能如下图所示:

[例2]: always @(posedge clk) begin b=a;

c=b; end

[例2]中的 \块用了阻塞赋值方式。clk信号的上升沿到来时,将发生如下的变化:b马上取a的值,c马上取b的值(即等于a),生成的电路图如下所示只用了一个触发器来寄存器a的值,又输出给b和c。这大概不是设计者的初衷,如果采用[例1]所示的非阻塞赋值方式就可以避免这种错误。

关于赋值语句更详细的说明请参阅第七章中深入理解阻塞和非阻塞赋值小节。

3.4.2 块语句

块语句通常用来将两条或多条语句组合在一起,使其在格式上看更象一条语句。块语句有两种,一种是begin_end语句,通常用来标识顺序执行的语句,用它来标识的块称为顺序块。一种是fork_join语句,通常用来标识并行执行的语句,用它来标识的块称为并行块。下面进行详细的介绍。

一.顺序块

顺序块有以下特点:

1) 块内的语句是按顺序执行的,即只有上面一条语句执行完后下面的语句才能执行。 2) 每条语句的延迟时间是相对于前一条语句的仿真时间而言的。 3) 直到最后一条语句执行完,程序流程控制才跳出该语句块。 顺序块的格式如下: begin 语句1; 语句2; ...... 语句n; end 或

begin:块名

块内声明语句 语句1; 语句2; ...... 语句n; end

其中:

? 块名即该块的名字,一个标识名。其作用后面再详细介绍。 ? 块内声明语句可以是参数声明语句、reg型变量声明语句、integer型变量声明语句、real型变量声明语句。

下面举例说明: [例1]:begin areg = breg;

creg = areg; //creg的值为breg的值。 end

从该例可以看出,第一条赋值语句先执行,areg的值更新为breg的值,然后程序流程控制转到第二条赋值语句,creg的值更新为areg的值。因为这两条赋值语句之间没有任何延迟时间,creg的值实为breg的值。当然可以在顺序块里延迟控制时间来分开两个赋值语句的执行时间,见[例2]:

[例2]: begin areg = breg; #10 creg = areg;

//在两条赋值语句间延迟10个时间单位。 end

[例3]:parameter d=50; //声明d是一个参数

reg [7:0] r; //声明r是一个8位的寄存器变量 begin //由一系列延迟产生的波形 #d r = 'h35; #d r = 'hE2; #d r = 'h00; #d r = 'hF7;

#d -> end_wave; //触发事件end_wave end

这个例子中用顺序块和延迟控制组合来产生一个时序波形。

二. 并行块

并行块有以下四个特点:

1) 块内语句是同时执行的,即程序流程控制一进入到该并行块,块内语句则开始同时并行地执行。

2) 块内每条语句的延迟时间是相对于程序流程控制进入到块内时的仿真时间的。 3) 延迟时间是用来给赋值语句提供执行时序的。

4) 当按时间时序排序在最后的语句执行完后或一个disable语句执行时,程序流程控制跳出该程序块。

并行块的格式如下: fork 语句1; 语句2; ....... 语句n;

join 或

fork:块名

块内声明语句 语句1; 语句2; ...... 语句n; join

其中:

? 块名即标识该块的一个名字,相当于一个标识符。 ? 块内说明语句可以是参数说明语句、reg型变量声明语句、integer型变量声明语句、real型变量声明语句、time型变量声明语句、事件(event)说明语句。

下面举例说明:

[例4]:fork #50 r = 'h35; #100 r = 'hE2; #150 r = 'h00; #200 r = 'hF7;

#250 -> end_wave; //触发事件end_wave. join

在这个例子中用并行块来替代了前面例子中的顺序块来产生波形,用这两种方法生成的波形是一样的。

三. 块名

在VerilgHDL语言中,可以给每个块取一个名字,只需将名字加在关键词begin或fork后面即可。这样做的原因有以下几点。

1) 这样可以在块内定义局部变量,即只在块内使用的变量。 2) 这样可以允许块被其它语句调用,如被disable语句。 3) 在Verilog语言里,所有的变量都是静态的,即所有的变量都只有一个唯一的存储地址,因此进入或跳出块并不影响存储在变量内的值。

基于以上原因,块名就提供了一个在任何仿真时刻确认变量值的方法。

四. 起始时间和结束时间

在并行块和顺序块中都有一个起始时间和结束时间的概念。对于顺序块,起始时间就是第一条语句开始被执行的时间,结束时间就是最后一条语句执行完的时间。而对于并行块来说,起始时间对于块内所有的语句是相同的,即程序流程控制进入该块的时间,其结束时间是按时间排序在最后的语句执行完的时间。

联系合同范文客服:xxxxx#qq.com(#替换为@)