米联客-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 小时前
基于 AD9361 (PZSDR‑P201Pro) 软件无线电实战综述:从板卡选型、硬件平台升级到 GNU Radio QPSK 完整收发链路
经验分享·嵌入式硬件·fpga开发·软件无线电·sdr·璞致电子
炎龙铠甲会合体4 小时前
从 SPEC 到上板:在 Zynq-7020 上用 RTL 手写一个 YOLO 卷积加速器(完整教程)
yolo·fpga开发·axi·芯片验证
FPGA小徐4 小时前
Vivado 按键消抖与复位模块代码修复详解:KEY_TOP、key、rst_gen 完整实战
fpga开发
炎龙铠甲会合体6 小时前
AXI2ICACHE— AXI4-Full 四路组相联指令 Cache 设计与 UVM 验证
fpga开发·面试·芯片验证
bingcheby6 小时前
FMQL15/20/45 (复旦微青龙系列 PSOC)新手使用说明
fpga开发
漫漫长远7 小时前
低功耗UPF介绍(一)
笔记·嵌入式硬件·学习·fpga开发
自小吃多18 小时前
【Verilog/FPGA】存储器(数组)
嵌入式硬件·fpga开发
szxinmai主板定制专家18 小时前
RK3588+FPGA异构架构|高速数据采集+边缘AI落地应用全解析
人工智能·嵌入式硬件·fpga开发·架构·zynq
明德扬1 天前
FPGA MIPI 多路视频聚合方案
fpga开发·mipi视频拼接·mipi多路拼接·mipi协议·mipi视频拼接方案·fpga mipi方案·mipi csi
XMAIPC_Robot1 天前
为什么大型储能需要边缘 AI 协调控制器?RK3588+FPGA 高速采集方案
人工智能·嵌入式硬件·fpga开发·arm+fpga·rk3588+fpga·协调控制器