问答 店铺
热搜: ZYNQ FPGA discuz

QQ登录

只需一步,快速开始

微信登录

微信扫码,快速开始

微信扫一扫 分享朋友圈

已有 59 人浏览分享

开启左侧

第六课 Verilog 语法_时序控制与语句块

[复制链接]
59 0
AMD-FPGA课程
AMD课程: 04-FPGA编程基础 » Verilog编程语法入门
1 概述
        本节讲解时序控制语句相关的语法与几种语句块的使用介绍,需要掌握时序控制的规则和顺序块、并行块、命名块、嵌套块的使用。

2 时序控制简介
       Verilog 提供了两类时序控制方法:时延控制和事件控制。时延控制主要用于仿真,事件控制主要用于时序设计,分为边沿触发控制与电平敏感控制。
2.1 时延控制
       基于时延的时序控制出现在表达式中,它指定了语句从开始执行到执行完毕之间的时间间隔。时延可以是数字、标识符或者表达式。
       通常根据时延在表达式中的位置差异,时延控制又可以分为常规时延与内嵌时延。
2.1.1 常规时延
格式为#<数字> <表达式>例:
reg [7:0] data;
initial
begin
#10 data=8'h12; //常规时延
#10 data=8'h02; //常规时延
#10 data=8'h22; //常规时延
end

2.1.2 内嵌时延
       遇到内嵌延迟语句后,先计算出表达式右端的结果,然后再延迟一定的时间,赋值给目标信号例:
reg [7:0] data;
initial
begin

data=#10 8'h12; //内嵌式时延
data=#10 8'h02; //内嵌式时延
data=#10 8'h22; //内嵌式时延
end
需要说明的是,这两种时延控制方式的效果是有所不同的。
当延时语句的赋值符号右端是常量时,两种时延控制都能达到相同的延时赋值效果。
当延时语句的赋值符号右端是变量时,两种时延控制可能会产生不同的延时赋值效果。

2.2 事件控制
2.2.1 边沿触发控制
边沿触发在 Verilog 中指寄存器或者线网类型变量发生了值的变化。
关键字 posedge 指信号发生边沿正向跳变,negedge 指信号发生负向边沿跳变,未指明跳变方向时,则两种情况的边沿变化都会触发相关事件。例:
always@(posedge clk )
//关键词 posedgeclk 正向边沿跳变
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

always@(negedge clk ) //关键词 negedgeclk 负向边沿跳变
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


always@(clk )
//未指明跳变方向,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
       说明 always@(敏感列表),敏感列表中可以有多个不同的事件,中间用关键字“or”或“,”分开。例:
always@(negedge clk or negedge ) //关键词 negedgeclk 负向边沿跳变;关键词 negedge,rst 可负向边沿跳变
begin
if (!rst_n)
q <= 0;
else 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

always@(negedge clk , negedge rst)/关键词 negedgeclk 负向边沿跳变;关键词 negedge,rst 可负向边沿跳变
begin
if (!rst_n)
q <= 0;
else 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

       当组合逻辑输入变量很多时,那么编写敏感列表会很麻烦。此时,更为简洁的写法是“@*”或“@(*)”,表示对语句块中的所有输入变量的变化都是敏感的。例:
wire [15:0] data_out;
reg [15:0] data_reg;
integer i;
always@(*)
//对语句块中的所有输入变量的变化都是敏感的
begin
for(i=0;i<15;i=i+1)
begin
data_reg = data_out[15 - i];
end
end
       命名事件控制,用户可以声明 event 类型的变量,并触发该变量来识别该事件是否发生。命名事件用关键字event 来声明,触发信号用 -> 表示。例如:
event start_r ;
always@( posedge clk)
begin
-> start_r;
end
always@(start_r)
//事件触发,敏感词
begin
data_buf = {data[0], data[1]};
end

2.2.2 电平敏感控制
       Verilog 中支持使用电平作为敏感信号来控制时序,即后面语句的执行需要等待某个条件为真。Verilog 中使用关键字 wait 来表示这种电平敏感情况。例:
initial begin
wait (start_1) ;
//电平敏感时间,等待 start_1 事件触发
forever
begin
@(posedge clk)
data_1= {data[0], data[1]};
end

3 语句块介绍
       Verilog 中有四种语句块,分别是顺序块,并行块,嵌套块,命名块。
3.1 顺序块
       顺序块用关键字 begin 和 end 来表示。顺序块中的语句是一条条执行的。非阻塞赋值除外。仿真中,initial 块中的阻塞赋值,都是顺序块的实例。例:
reg [7:0] data;
initial
begin
#10 data=8'h12;
//按照时间,顺序执行
#10 data=8'h02;
#10 data=8'h22;
end

3.2 并行块
       并行块有关键字 fork 和 join 来表示。并行块中的语句是并行执行的,即便是阻塞形式的赋值。并行块中每条语句的时延都是与块语句开始执行的时间相关。例:
initial
fork
#10 data=8'h12;
//data 按照时间并行执行,与 data=8'h02 同时进行,一般实际情况下我们不这样使用,仅仅是作为示例
#10 data=8'h02;
join
initial
fork
#10 data1=8'h32; //data1 按照时间并行执行,与 data1=8'h22 同时进行,一般实际情况下我们不这样使用,仅仅是作为示例
#10 data1=8'h22;
join

3.3 嵌套块
       顺序块和并行块还可以嵌套使用。例:
reg [7:0] data;
initial
begin
#10 data=8'h12;
#10 data=8'h02;
#10 data=8'h22;
fork
#10 data=8'h12;
#10 data=8'h02;
join
end

3.4 命名块
       可以给块语句结构命名。例:
reg [7:0] data;
initial
begin:start_initial
#10 data=8'h12;
#10 data=8'h02;
#10 data=8'h22;
fork
#10 data=8'h12;
#10 data=8'h02;
join
end



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

本版积分规则

0

关注

10

粉丝

119

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

        • 扫描访问手机版