03 Verilog HDL 语法

Verilog HDL(Hardware Description Language)是在 C 语言的基础上发展起来的一种硬件描述语言(用它可以表示逻辑电路图、逻辑表达式、数字逻辑系统所完成的逻辑功能等)具有灵活性高、易学易用等特点。Verilog HDL 可以在较短的时间内学习和掌握,目前已经在 FPGA 开发/IC 设计领域占据绝对的领导地位。

Verilog HDL的基本语法

Verilog 的逻辑值

逻辑电路中有四种值,即四种状态:

  1. 逻辑 0:表示低电平
  2. 逻辑 1:表示高电平
  3. 逻辑 X:表示未知,有可能是高电平,也有可能是低电平
  4. 逻辑 Z:表示高阻态,外部没有激励信号是一个悬空状态

Verilog 的标识符

标识符(identifier)用于定义模块名、端口名、信号名等。Verilog 的标识符可以是任意一组字母、数字、$和_(下划线)符号的组合,但标识符的第一个字符必须是字母或者下划线,另外标识符是区分大小写。

常量

在程序运行过程中,其值不能被改变的量称为常量,Verilog 常见的常量有数字、参数。

数字

  • 整数
    在Verilog HDL中,整型常量有以下四种进制表示形式:
  1. 二进制整数(b或B)
  2. 十进制整数(d或D)
  3. 十六进制整数(h或H)
  4. 八进制整数(o或O)
    表达方式有以下三种:
  5. <位宽><进制><数字>这是一种全面的描述方式
  6. <进制><数字>在这种描述方式中,数字的位宽采用默认位宽(这由具体的机器系统决定,但至少32位)
  7. <数字>在这种描述方式中,数字进制采用默认的十进制,数字的位宽采用默认位宽(这由具体的机器系统决定,但至少32位)
8'b10101100 //位宽为8的数的二进制表示, 'b表示二进制 
8'ha2 //位宽为8的数的十六进制,'h表示十六进制
  • x和z值
    在数字电路中,x代表不定值,z代表高阻值。在十六进制格式中x表示四位二进制,在八进制格式中x表示三位二进制,在二进制格式中x表示一位二进制。z的表示方式同x类似。
4'b10x0 //位宽为4的二进制数从低位数起第二位为不定值
4'b101z //位宽为4的二进制数从低位数起第一位为高阻值
12'dz //位宽为12的十进制数其值为高阻值
8'h4x //位宽为8的十六进制数其低四位值为不定值
  • 负数
    一个数字可以被定义为负数,只需在位宽前加一个减号。
-8'd5 //这个表达式代表-5的补码(用八位二进制数表示)
  • 下划线
    下划线可以用来对数进行分隔,以提高程序可读性
16'b1010_1011_1111_1010

parameter参数

在Verilog HDL中可以用parameter来定义常量,即用parameter来定义一个标识符代表一个常量,称为符号常量,即标识符形式的常量,采用标识符代表一个常量可提高程序的可读性和可维护性。其说明格式如下:

parameter 参数名1=表达式,参数名2=表达式, …, 参数名n=表达式;	//语法格式
parameter msb=7; //定义参数msb为常量7

parameter 参数可以定义在模块参数列表中,通过在例化模块时传入不同的值,以达到配置模块功能的目的。

localparam参数

与parameter类似,localparam也可以用来定义符号常量,但是localparam不能用在模块参数列表中。

变量

Verilog中常用的变量类型有reg型、wire型

wire型

wire型即线型,可以把他理解为数字电路中的导线,只能在assign语句中对其赋值,其定义方法如下:

wire [n-1:0] 数据名1,数据名2,…数据名i; //共有i条总线,每条总线内有n位
wire [7:0] b; //定义了一个八位的wire型数据 
wire [4:1] c, d; //定义了二个四位的wire型数据

reg型

wire型即寄存器类型,可以把他理解为数字电路中的寄存器(在综合时组合逻辑中的reg可能不会综合成寄存器),只能在always语句中对其赋值,其定义方法如下:

reg [n-1:0] 数据名1,数据名2,… 数据名i;
reg [3:0] regb; //定义了一个四位的名为regb的reg型数据 
reg [4:1] regc, regd; //定义了两个四位的名为regc和regd的reg型数据

memory型

Verilog HDL通过对reg型变量建立数组来对存储器建模(可以将memory型理解为reg数组,在Verilog中只支持一维数组),数组中的每一个单元通过一个数组索引进行寻址,其定义方法如下:

reg [n-1:0] 存储器名[m-1:0];	//reg[n-1:0]定义了存储器中每一个存储单元的大小,[m-1:0]定义了该存储器中有多少个这样的寄存器([n-1:0]决定位宽,[m-1:0]决定个数)
reg [7:0] mema[2550];	//定义了一个名为mema的存储器,该存储器有256个8位的寄存器,存储单元索引范围是0到255
mema[3]=0; //给memory中的第3个存储单元赋值为0。

signed关键字

在Verilog中wire和reg默认是无符号(unsigned)类型的,可以通过关键字signed定义有符号的wire和reg型变量(有符号变量负数采用补码表示),其定义方法如下:

reg signed [3:0] regb; //定义了一个四位的有符号reg型数据 
wire signed [7:0] wireb; //定义了一个八位的有符号wire型数据 

在使用有符号变量时需要注意以下几点:

  1. 一条运算究竟是按unsigned运算还是按signed运算,取决于其右值的操作数是否含有unsigned变量,只要右值存在unsigned变量,整个操作就会按unsigned处理(这里可能会出现将一个表示负数的补码当作一个很大的正数来处理)
  2. 如果对signed进行截位运算,截位后会变成unsigned变量,如wireb是有符号wire型数据,而wireb[5:0]就不是有符号wire型数据
  3. signed变量需要有符号位,所以单bit变量无法表示一个有符号数负数,若用其做有符号运算时会出错(必须为其扩展符号位才能进行有符号运算)
  4. 无符号变量可以通过$signed()转换为有符号变量,比如一个无符号变量和一个有符号变量进行运算时,希望按有符号处理则可以使用$signed()将无符号变量转换为有符号变量($signed()不会改变变量的值,只是告诉编译器,这个无符号变量要当作有符号变量处理)
  5. 无符号数和有符号数进行比较时按无符号数处理(即有符号的负数会被当做一个很大的正数)

运算符

算术运算符

在Verilog HDL语言中,算术运算共有下面几种:

  1. + (加法运算符,或正值运算符,如 rega+regb,+3)
  2. - (减法运算符,或负值运算符,如 rega-3,-3)
  3. × (乘法运算符,如rega*3)
  4. / (除法运算符,相除取整,如5/3的值为1)
  5. % (模运算符,相除取余。如7%3的值为1)
    不建议在Verilog使用除法运算符,应使用除法IP核来进行除法处理,如果是除以2^n可以用移位操作替代

位运算符

Verilog HDL作为一种硬件描述语言,提供了以下五种位运算符:

  1. ~ //取反
  2. & //按位与
  3. | //按位或
  4. ^ //按位异或
  5. ^~ //按位同或

逻辑运算符

在Verilog HDL语言中提供了三种逻辑运算符:

  1. && 逻辑与
  2. || 逻辑或
  3. ! 逻辑非

关系运算符

Verilog HDL语言中关系运算符共有以下四种:

  1. a < b a小于b
  2. a > b a大于b
  3. a <= b a小于或等于b
  4. a >= b a大于或等于b

等式运算符

Verilog HDL语言中有四种等式运算符:

  1. == 等于,当于操作数中某些位为不定值x或高阻值z,结果可能为不定值x
  2. != 不等于,当于操作数中某些位为不定值x或高阻值z,结果可能为不定值x
  3. === 等于 ,不对定值x和高阻值z也进行比较
  4. !== 不等于 ,不对定值x和高阻值z也进行比较

移位运算符

在Verilog HDL中有两种移位运算符:

  1. << 左移位运算符
  2. >> 右移位运算符

拼接运算符

在Verilog HDL语言有一个特殊的运算符:拼接运算符{}。用这个运算符可以把两个或多个信号的某些位拼接起来进行运算操作,其使用方法如下:
{信号1的某几位,信号2的某几位,…,…,信号n的某几位}

运算符优先级别

对各种运算符的优先级别如下:
在这里插入图片描述

Verilog关键字

Verilog 和 C 语言类似,都因编写需要定义了一系列保留字,叫做关键字(或关键词),如下是Verilog的所有关键字
在这里插入图片描述
其中常用的关键字如下

关键字含义
module模块开始定义
input输入端口定义
output输出端口定义
inout双向端口定义
parameter参数常量定义
localparam参数常量定义
wire线型变量定义
reg寄存器变量定义
always产生reg型变量语句的关键字
assign产生wire型变量语句的关键字
begin顺序块起始标志,当出现多条语句时需要写在begin end之间
end顺序块结束标志
posedge表示上升沿敏感
negedge表示下降沿敏感
case多条件分支语句起始标记
default多条件分支语句的默认分支
endcase多条件分支语句结束标记
iff/else语句标记
elseif/else语句标记
forfor语句标记
endmodule模块结束定义

模块开始和结束

Verilog模块以以module开始,endmodule结束,其格式如下:

//模块开始
module 模块名 #(//模块参数,模块参数非必选项parameter 参数1,parameter 参数2,......,parameter 参数n
)
(//输入参数input 输入端口1,input 输入端口2,......,input 输入端口n,//双向参数inout 双向端口1,inout 双向端口2,......,inout 双向端口n,//输出参数output 输出端口1,output 输出端口2,......,output 输出端口n
)//内部参数变量定义//内部功能定义//模块结束
endmodule

条件语句

  • if_else语句,if语句是用来判定所给定的条件是否满足,根据判定的结果(真或假)决定执行给出的两种操作之一,Verilog HDL语言提供了三种形式的if语句。
1if(表达式)语句
2if(表达式)语句1
else语句2
3if(表达式1)语句1;
else if(表达式2)语句2; 
else if(表达式3)语句3; 
........ 
else if(表达式m)语句m; 
else语句n;

在if和else后面可以包含一条语句,也可以包含多条语句,当包含多条语句时需要用用begin和end将多条语句组合成一个复合语句。

if(a>b) begin out1<=int1; out2<=int2; 
end 
else begin out1<=int2; out2<=int1; 
end
  • case语句,case语句是一种多分支选择语句,它的一般形式如下:
case(控制表达式)条件1 : 语句1;条件2 : 语句2;条件3 : 语句3;......条件n : 语句n;default : 语句n+1;
endcase

当控制表达式的值与分支条件的值相等时(分支条件必须是常量,且不能与其他分支相同,位宽也必须与控制表达式的位宽一致),就执行分支条件后面的语句,如果所有分支都不匹配,就执行default后面的语句(如果没有default则此时case不执行任何分支的语句)

循环语句

在Verilog HDL中存在着四种类型的循环语句,用来控制执行语句的执行次数,不过Verilog在综合时只能综合有限次数的循环语句。

  • repeat语句,repeat语句用于控制语句执行指定的次数,语法格式如下
1//表达式用于指定循环次数,一般为常量
repeat(表达式) 语句;
2repeat(表达式) begin 多条语句
end
  • while语句,while循环语句通过循环条件来控制循环次数,语法格式如下
1while(表达式)语句
2while(表达式) begin多条语句
end
  • for语句,for语句与while语句一样,都是通过循环条件控制循环次数,语法格式如下:
1for(表达式1; 表达式2; 表达式3)语句
2for(表达式1; 表达式2; 表达式3) begin语句
end

其执行流程相当于下面的while语句:

表达式1;
while(表达式2) begin语句;表达式3;
end

assign语句和always语句

assign语句和always语句是Verilog中的两个基本语句,使用频率很高。
assign语句使用时不能带时钟,只能生成组合逻辑电路,在assign语句中只能对wire型变量赋值。
always语句可以带时钟,也可以不带时钟,不带时钟时生成组合逻辑,带时钟时生成时序逻辑,在always语句中只能对reg型变量赋值

task和function语句

task和function说明语句分别用来定义任务和函数,利用任务和函数可以把一个很大的程序模块分解成许多较小的任务和函数便于理解和调试

  • function语句
    function语句的格式如下:
function [automatic] [返回值宽度] 函数名;输入端口列表;[变量声明语句];begin语句;......end
endfunction

function:表示函数开始。
automatic:声明函数未可重入,表示函数内定义的变量默认为动态的,在调用函数时单独分配,可以避免在多个地方同时调用时出现结果未知的情况,但是会消耗更多资源。
[返回值宽度]:它是是可选的,若未指定则默认未1bit。
函数名:函数名是函数的名字,调用时通过此名字来调用,同时还会在函数内部定义一个同名的变量用于返回函数的返回值。
输入端口列表:一个函数至少包含一个输入端口,不能有输出端口和双向端口。
[变量声明语句]:用于声明函数内部使用的变量。
endfunction:表示函数结束。
function的调用格式如下:
函数可以在always中被调用,也可以在assign被调用,函数调用时只能做右值,不能单独作为一条语句

变量 = 函数名(表达式1[, 表达式2, ......])

注意
在函数中使能实现组合逻辑,不能出现延时语句(如#200),不能出现敏感事件控制语句(如wait),不能出现过程块语句(如always)。

  • task语句
    task语句的格式如下:
task [automatic] 任务名;[输入端口列表];[输出端口列表];[双向端口列表];[变量声明语句];begin语句;......end
endtask

task:表示任务开始
[automatic]:表示任务内定义的变量默认为动态的,在调用任务时单独分配
任务名:任务的名称,在always中可以通过任务名调用任务
[输入端口列表]:任务可以包含0个或多个输入端口
[输出端口列表]:任务可以包含0个或多个输出端口
[双向端口列表]:任务可以包含0个或多个双向端口
[变量声明语句]:声明任务内部所需要使用的变量
endtask:表示任务结束
任务调用格式如下:
任务只能在过程语句中被调用(如always),其调用格式如下:

任务名([表达式1], [表达式2], ......]);

注意:
虽然在任务中可以使用延时语句(如#200),敏感事件控制语句(如wait),但是使用了这些语句的任务无法综合,因为Verilog只能综合组合逻辑电路的任务。

Verilog中的赋值操作

在Verilog中有两种赋值方式:

  • 阻塞式赋值(如b = a;)
    在执行赋值语句时计算右值,计算完成后立即赋给变量,整个过程完成再执行后面的语句
  • 非阻塞式赋值(如 b <= a;)
    在执行赋值语句时计算右值,计算完成后不会立即赋给变量,然后继续执行后面的指令,待语句块结束后才将右值结果赋给变量
    一般再组合逻辑中用阻塞式赋值,在时序逻辑中用非阻塞式赋值(若在时序电路中用阻塞赋值会出现时钟到来时一边在进行赋值操作,一边在进行读取操作,从而导致读取的结果不确定的问题,而组合逻辑电路没有时钟,输入直接取决于输出,故而用阻塞式赋值)

Verilog程序框架

下面以一个LED流水灯为例展示Verilog 的程序框架

`timescale 1ns / 1ns//module表示模块开始
module flow_led #(//参数列表parameter LED_CHANNEL = 4,				     //LED数量parameter COUNT_WIDTH = 25,				//内部计数器宽度parameter COUNT_PERIOD = 25_000_000		//计数器最大周期,决定LED多久变化依次
)
(//输入参数列表,输入参数列表只能式wireinput            sys_clk,			//时钟input            sys_rst_n,			//复位,低电平有效//双向(inout)参数列表,双向参数只能是wire,这里暂未使用//输出参数列表,输出参数可以是wire可以是reg,默认是wireoutput reg [LED_CHANNEL-1:0] led	//LED
);//周期计数器
reg [COUNT_WIDTH-1:0] count;//一个周期计数器,计数范围为0~COUNT_PERIOD-1,即周期为COUNT_PERIOD
//always用于产生一个对reg型变量进行赋值的语句块
//posedge表示关注信号上升沿
//@表示敏感变量表条件成立执行一次
//begin/end产生一个顺序块
//<=用于赋值时是非阻塞式赋值,执行时先计数右值,并不会立即赋给变量,需要等语句块结束后才赋给变量,因此需要在下一个时钟沿才能读取到这时钟沿赋的值
always @(posedge sys_clk) beginif(!sys_rst_n)count <= 0;else if(count < (COUNT_PERIOD - 1))count <= count + 1;elsecount <= 0;
end//控制LED输出
always @(posedge sys_clk) beginif(!sys_rst_n)led <= 1;else if(count == (COUNT_PERIOD - 1))led <= {led[LED_CHANNEL-2:0],led[LED_CHANNEL-1]};
end//endmodule是模块结束标记
endmodule

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/654637.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【DeepLearning-10】yolo.py文件关键代码parse_model(d, ch)函数

这段代码功能是根据提供的配置字典&#xff08;d&#xff09;和输入通道列表&#xff08;ch&#xff09;来解析并构建一个YOLOv5模型。函数的核心工作是遍历模型的每一层&#xff0c;并根据配置创建相应的神经网络层。 我们可以在函数中为新增模块配置构造参数设置。 函数中 f…

响应式Web开发项目教程(HTML5+CSS3+Bootstrap)第2版 例5-3 getBoundingClientRect()

代码 <!doctype html> <html> <head> <meta charset"utf-8"> <title>getBoundingClientRect()</title> </head> <script>function getRect(){var obj document.getElementById(example); //获取元素对象var objR…

【数据结构1-3】集合

有时候&#xff0c;我们并不关心数据之间的前后关系&#xff0c;也不关心数据的层次关系。一些确定元素只是单纯的聚集在一起&#xff0c;这样的元素聚集体被称为集合。 当希望知道某个数据是否存在一个集合中&#xff0c;或者两个元素是否在同一个集合中时&#xff0c;就需要使…

IP关联是什么?有什么后果?如何防止电商账号因IP关联被封?

在跨境电商的世界里&#xff0c;IP关联给多账号运营的商家带来了挑战。比如&#xff0c;亚马逊IP关联规则的执行对于那些经营多个店铺的卖家来说可能是一个不小的障碍。IP关联的影响不只是限于亚马逊&#xff0c;其他平台如Instagram、Facebook也有类似的机制&#xff0c;在之前…

PHP语法

#本来是在学命令执行&#xff0c;所以学了学&#xff0c;后来发现&#xff0c;PHP语法和命令执行的关系好像没有那么大&#xff0c;不如直接学php的一些命令执行函数了。# #但是还是更一下&#xff0c;毕竟还是很多地方都要求掌握php作为脚本语言&#xff0c;所以就学了前面的…

HTML新手教程

HTML入门 教程&#xff1a;【狂神说Java】HTML5完整教学通俗易懂_哔哩哔哩_bilibili 一.初识HTML HyperTextMarkupLanguage&#xff08;超文本标记语言&#xff09; 超文本包括&#xff1a;文字、图片、音频、视频、动画。 HTML5的优势 世界知名浏览器厂商对HTML5的支持市场的…

无人值守变电所运维在海南市某住宅区的应用

1 前言 随着国家电网改革政策的逐步推进和落实&#xff0c;AcrelCloud-1000变电所运维云平台运用互联网和大数据技术&#xff0c;为电力运维公司提供变电所运维云平台。该平台作为连接运维单位和用电企业的纽带&#xff0c;监视用户配电系统的运行状态和电量数据&#xff0c;为…

Vue3使用setup-extend简化组件名写法

如果我们在Vue3中要使用setup的语法糖&#xff0c;就需要使用两个script标签&#xff0c;一个用于设置组件的name属性&#xff0c;一个用于编写setup中的代码。如下&#xff1a; 但是我们有觉得光是因为一个name属性就多写一个script标签有点麻烦了。 因此我们可以使用插件来进…

【Python笔记-设计模式】抽象工厂模式

一、说明 (一) 解决问题 抽象工厂是一种创建型设计模式&#xff0c;主要解决接口选择的问题。能够创建一系列相关的对象&#xff0c;而无需指定其具体类。 (二) 使用场景 系统中有多于一个的产品族&#xff0c;且这些产品族类的产品需实现同样的接口。 例如&#xff1a;有…

AI对话软件哪个好?首选这3款堪称神器的AI工具!

在过去的一年里&#xff0c;AI对话软件无疑深度嵌入到了我们工作或生活的方方面面&#xff0c;成为了我们的得力助手。它们可以帮我们解决问题&#xff0c;提供信息&#xff0c;甚至陪伴我们度过孤独的时刻。 但是&#xff0c;面对市场上数量众多的AI对话软件&#xff0c;你是…

arcgis 批量删除字段

一、打开ArcToolbox-数据管理工具-字段-删除字段。 二、在输入表中选择要删除字段的要素&#xff0c;在删除字段栏中选择要删除的字段&#xff0c;点击确认即可。

【C语言】深入理解指针(4)回调函数

目录 回调函数 回调函数的应用 i&#xff0c;简化代码逻辑 ii&#xff0c;实现上下机之间的通讯 回调函数 回调函数就是⼀个通过函数指针调用的函数。 如果你把函数的指针&#xff08;地址&#xff09;作为参数传递给另⼀个函数&#xff0c;当这个指针被用来调用其所指向…

老龄化对投资意味着什么?

1月15日&#xff0c;国务院办公厅印发《关于发展银发经济增进老年人福祉的意见》从4个方面提出26项举措&#xff0c;为我国首个以“银发经济”命名的政策文件。 近期&#xff0c;国信证券分析师王开发布题为《银发经济再思考&#xff1a;老龄化对投资的影响》的报告&#xff0…

Hive(15)中使用sum() over()实现累积求和和滑动求和

目的&#xff1a; 三个常用的排序函数row_number(),rank()和dense_rank()。这三个函数需要配合开窗函数over()来实现排序功能。但over()的用法远不止于此&#xff0c;本文咱们来介绍如何实现累计求和和滑动求和。 1、数据介绍 三列数据&#xff0c;分别是员工的姓名、月份和…

源聚达科技:开一家抖音店铺怎么做最好

在数字化浪潮的推动下&#xff0c;抖音不仅是年轻人展示才华的舞台&#xff0c;也成为商家争夺流量的新阵地。开一家抖音店铺&#xff0c;看似简单&#xff0c;实则需要精心策划和周到运营。 首要任务是确立店铺定位。正如古人云“磨刀不误砍柴工”&#xff0c;明确目标受众和主…

神经网络建立(结果可变)最小神经元

目录 介绍&#xff1a; 初始化&#xff1a; 建模: 预测&#xff1a; 改变结果&#xff1a; 介绍&#xff1a; 在深度学习中&#xff0c;神经元通常指的是人工神经元&#xff08;或感知器&#xff09;&#xff0c;它是深度神经网络中的基本单元。深度学习的神经元模拟了生…

JavaWeb基础01-基本技术体系介绍和相关工具的安装

一、JavaWeb 1.概述 Web&#xff1a;全球广域网&#xff0c;也称为万维网(www)&#xff0c;能够通过浏览器访问的网站JavaWeb&#xff1a;是用Java技术来解决相关web互联网领域的技术栈 2.组成 &#xff08;1&#xff09;网页&#xff1a;展示数据&#xff08;前端技术&…

计算机网络·网络层

网络层 网络层提供的两种服务 争论&#xff1a; 网络层应该向运输层提供怎样的服务&#xff1f;面向连接还是无连接&#xff1f; 在计算机通信中&#xff0c;可靠交付应当由谁来负责&#xff1f;是网络还是端系统&#xff1f; 2 种观点&#xff1a; 面向连接的可靠交付。 无连…

【C\C++ 04】归并排序

归并排序&#xff08;MERGE-SORT&#xff09;是建立在归并操作上的一种有效的排序算法&#xff0c;该算法是采用分治法&#xff08;Divide and Conquer&#xff09;的一个非常典型的应用&#xff0c;也是用空间换时间思维的体现。 将已有序的子序列合并&#xff0c;得到完全有…

w24文件上传之PHP伪协议

PHP支持的伪协议 file:// - 访问本地文件系统 http:// - 访问网址 ftp:// - 访问文件 php:// -访问各个输入/输出流 zlib:// -压缩流 data:// - 数据 glob:// -查找匹配的文件路径模式 phar:// - php归档 ssh2:// - Secure shell 2 rar:// - RAR ogg:// - 音频流 expect:// - …