问答 店铺
热搜: ZYNQ FPGA discuz

QQ登录

只需一步,快速开始

微信登录

微信扫码,快速开始

微信扫一扫 分享朋友圈

已有 30 人浏览分享

开启左侧

第五课 Verilog 语法_过程结构与赋值

[复制链接]
30 0
AMD-FPGA课程
AMD课程: 04-FPGA语法和硬件基础 » X
1 概述
      本节主要讲解过程结构与赋值,需要掌握阻塞和非阻塞赋值的区别。


2 过程结构
      过程结构语句有两种,initial 与 always 语句。它们是 RTL 级建模的两种基本语句。一个模块中可以包含多个initial always 语句。这些语句在模块间并行执行,与其在模块的前后顺序没有关系。但是 initial 语句或 always语句内部可以理解为是顺序执行的(非阻塞赋值除外)。两种语句在仿真的开始同时立即执行,initial 语句只执行一次,而 always 语句重复执行,直到仿真结束。


2.1 initial 语句
      initial 语句的格式如下:
      initial
      begin
      语句 1;
      语句 2;
      ......
      语句 n;
      end
      initial 可以对 reg 型变量赋初始值,初始化的过程不需要任何时间。例:

reg [7:0] data;
initial
begin
data=8'h32;
//赋值
#10
//经过 10 个时钟周期
data=8'h12;
//赋值
#10
//经过 10 个时钟周期

data=8'h02;
//赋值
#10
//经过 10 个时钟周期
data=8'h22;
//赋值
end

      initial 语句可以生成激励波形,用于测试电路的仿真信号。

2.2 always 语句
      always 语句是重复执行的语句,不像 initial 语句只执行一次。声明格式如下:
      always <时序控制> <语句>例:
reg clk;
//reg 变量
initial clk = 0;
//reg 通过 initial 赋值
always #10 clk = ~clk; //重复翻转
      使用 always 语句生成一个仿真的时钟信号。

3 过程赋值
      过程性赋值是在 initial 或 always 语句块里的赋值,赋值对象是寄存器、整数、实数等类型。这些变量在被赋值后,其值将保持不变,直到重新被赋予新值。
      连续性赋值总是处于激活状态,任何操作数的改变都会影响表达式的结果;过程赋值只有在语句执行的时候,才会起作用。这是连续性赋值与过程性赋值的区别。
      Verilog 过程赋值包括两种类型:阻塞赋值与非阻塞赋值。


3.1 阻塞赋值
      阻塞赋值属于顺序执行,即下一条语句执行前,当前语句一定会执行完毕。阻塞赋值语句使用等号“=”作为赋值符。例:
always@(*)
begin
q1 = d[0];
q2 = d[1];
q3 = d[2];
if(s == 2'b00)
q = d[0];
//阻塞赋值,同时进行
else if(s == 2'b01)
q = d[1];
//阻塞赋值,同时进行
else if(s == 2'b10)
q = d[2];
//阻塞赋值,同时进行
else if(s == 2'b11)
q = d[3];
//阻塞赋值,同时进行

else
;
end


3.2 非阻塞赋值
      非阻塞赋值属于并行执行语句,即下一条语句的执行和当前语句的执行是同时进行的,它不会阻塞位于同一个
      语句块中后面语句的执行。
      非阻塞赋值语句使用“<=”作为赋值符。例:
always@(posedge clk )
begin
q1 <= d[0];
q2 <= d[1];
q3 <= d[2];
if(s == 2'b00)
q <= d[0];
//非阻塞赋值,不会相互影响
else if(s == 2'b01)
q <= d[1];
//非阻塞赋值,不会相互影响
else if(s == 2'b10)
q <= d[2];
//非阻塞赋值,不会相互影响
else if(s == 2'b11)
q <= d[3];
//非阻塞赋值,不会相互影响
else
;
end

3.3 阻塞与非阻塞赋值的使用注意
      一般在 Verilog 代码设计时,一般不在一个过程结构中混合使用阻塞赋值与非阻塞赋值。两种赋值方式混用时,时序不容易控制,会造成意外的错误。
      通常在设计电路时,always 时序逻辑块中多用非阻塞赋值,always 组合逻辑块中多用阻塞赋值。在仿真电路时,initial 块中一般多用阻塞赋值。
      为实现在时钟上升沿交换 2 个寄存器值的功能,在 2 个 always 块中使用阻塞赋值。
      因为 2 个 always 块中的语句是同时进行的,但是 a=b 与 b=a 是无法判定执行顺序的,这就造成了竞争的局面。
      不考虑哪个先执行,不考虑时序问题时,执行顺序总有先后,最后 a 与 b 的值总是相等的。没有达到交换 2个寄存器值的效果。例:
always @(posedge clk) begin
a = b ;
//阻塞赋值,同时进行
end

always @(posedge clk) begin
b = a;
//阻塞赋值,同时进行
end
      但是,如果在 always 块中使用非阻塞赋值,则可以避免上述竞争冒险的情况。
      2 always 块中语句并行执行,赋值操作右端操作数使用的是上一个时钟周期的值,此时 a<=b b<=a 可以相互不干扰的执行,达到交换寄存器值的目的。例:
always @(posedge clk) begin
a <= b ;
//非阻塞赋值,对上个周期的值进行操作
end
always @(posedge clk) begin
b <= a;
//非阻塞赋值,对上个周期的值进行操作
end

总结:为了不出现问题,平时建议规范书写代码,注意几点:
1、时序电路用非阻塞
2、组合电路用阻塞
3、同一个 always 块中阻塞和非阻塞不混用





您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

0

关注

10

粉丝

110

主题
精彩推荐
热门资讯
    网友晒图
      图文推荐
        
        • 微信公众平台

        • 扫描访问手机版