米联客-FPGA程序设计Verilog语法入门篇连载-06 Verilog语法_时序控制与语句块

软件版本:无

操作系统:WIN10 64bit

硬件平台:适用所有系列FPGA

板卡获取平台:https://milianke.tmall.com/

登录"米联客"FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!

1 概述

本节讲解时序控制语句相关的语法与几种语句块的使用介绍,需要掌握时序控制的规则和顺序块、并行块、命名块、嵌套块的使用。

2 时序控制 简介

Verilog 提供了两类时序控制方法:时延控制和事件控制。时延控制主要用于仿真,事件控制主要用于时序设计,分为边沿触发控制与电平敏感控制。

2.1 时延控制

基于时延的时序控制出现在表达式中,它指定了语句从开始执行到执行完毕之间的时间间隔。时延可以是数字、标识符或者表达式。

通常根据时延在表达式中的位置差异,时延控制又可以分为常规时延与内嵌时延。

2.1.1 常规时延

格式为#<数字> <表达式>例:

cpp 复制代码
reg [7:0] data;

initial

begin

#10 data=8'h12; //常规时延

#10 data=8'h02; //常规时延

#10 data=8'h22; //常规时延

end
2.1.2 内嵌时延

遇到内嵌延迟语句后,先计算出表达式右端的结果,然后再延迟一定的时间,赋值给目标信号例:

cpp 复制代码
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 指信号发生负向边沿跳变,未指明跳变方向时,则两种情况的边沿变化都会触发相关事件。例:

cpp 复制代码
always@(posedge clk )    //关键词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

        ;
cpp 复制代码
always@(negedge clk ) //关键词negedge,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
cpp 复制代码
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"或","分开。例:

cpp 复制代码
always@(negedge clk or negedge ) //关键词negedge,clk 负向边沿跳变;关键词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
cpp 复制代码
always@(negedge clk , negedge rst)/关键词negedge,clk 负向边沿跳变;关键词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

当组合逻辑输入变量很多时,那么编写敏感列表会很麻烦。此时,更为简洁的写法是"@*"或"@(*)",表示对语句块中的所有输入变量的变化都是敏感的。例:

cpp 复制代码
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[i] = data_out[15 - i];

    end

end

命名事件控制,用户可以声明 event类型的变量,并触发该变量来识别该事件是否发生。命名事件用关键字 event 来声明,触发信号用 -> 表示。例如:

cpp 复制代码
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来表示这种电平敏感情况。例:

cpp 复制代码
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 块中的阻塞赋值,都是顺序块的实例。例:

cpp 复制代码
reg [7:0] data;

initial

begin

#10 data=8'h12;       //按照时间,顺序执行

#10 data=8'h02;

#10 data=8'h22;

end

3.2 并行块

并行块有关键字 fork 和 join 来表示。并行块中的语句是并行执行的,即便是阻塞形式的赋值。并行块中每条语句的时延都是与块语句开始执行的时间相关。例:

cpp 复制代码
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 嵌套块

顺序块和并行块还可以嵌套使用。例:

cpp 复制代码
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 命名块

可以给块语句结构命名。例:

cpp 复制代码
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
相关推荐
邹莉斯2 小时前
FPGA基本结构和简单原理
fpga开发·硬件工程
悲喜自渡7212 小时前
易灵思FPGA开发(一)——软件安装
fpga开发
ZxsLoves2 小时前
【【通信协议ARP的verilog实现】】
fpga开发
爱奔跑的虎子4 小时前
FPGA与Matlab图像处理之伽马校正
图像处理·matlab·fpga开发·fpga·vivado·xilinx
机器未来21 小时前
基于FPGA的SD卡的数据读写实现(SD NAND FLASH)
arm开发·嵌入式硬件·fpga开发
贾saisai1 天前
Xilinx系FPGA学习笔记(八)FPGA与红外遥控
笔记·学习·fpga开发
吉孟雷2 天前
ZYNQ FPGA自学笔记
fpga开发·verilog·led·仿真·vivado·zynq
行者..................2 天前
1. ZYNQ 2. MPSOC 3. FPGA 4. IO分配 5. 硬件设计
fpga开发
tsumikistep2 天前
【无标题】Efinity 0基础进行流水灯项目撰写(FPGA)
fpga开发
行者..................2 天前
FPGA学习 VIVADO Verilog 编程
学习·fpga开发